diff --git a/includes/SearchlightDatasource.inc b/includes/SearchlightDatasource.inc
index 3d229be..44deac6 100644
--- a/includes/SearchlightDatasource.inc
+++ b/includes/SearchlightDatasource.inc
@@ -6,6 +6,7 @@ class SearchlightDatasource {
var $base_table;
var $base_field;
var $fields;
+ var $relations;
var $filters;
var $options;
@@ -22,6 +23,7 @@ class SearchlightDatasource {
$this->fields = !empty($this->fields) ? $this->fields : array();
$this->filters = !empty($this->filters) ? $this->filters : array();
+ $this->relations = !empty($this->relations) ? $this->relations : array();
$this->options = !empty($this->options) ? $this->options : array();
$this->options = $this->options + array(
'node_access' => TRUE,
@@ -31,10 +33,8 @@ class SearchlightDatasource {
}
function setId() {
- global $db_url;
- $url = is_array($db_url) ? $db_url['default'] : $db_url;
- $url = parse_url($url);
- $this->id = trim(urldecode($url['path']), '/') .'_'. $this->name;
+ global $databases;
+ $this->id = $databases['default']['default']['database'] . '_' . $this->name;
return $this;
}
@@ -46,6 +46,7 @@ class SearchlightDatasource {
views_include('view');
$this->view = new view;
$this->view->base_table = $this->base_table;
+ $this->view->base_field = $this->base_field;
$this->view->api_version = '3.0-alpha1';
$this->view->new_display('default', 'Default', 'default');
$this->view->set_display('default');
@@ -67,18 +68,25 @@ class SearchlightDatasource {
'id' => $this->base_field,
'table' => $this->base_table,
'field' => $this->base_field,
- 'relationship' => 'none'
+ 'relationship' => 'none',
);
}
foreach ($this->getFields() as $name => $field) {
- $fields[$name] = array(
- 'id' => $field['name'],
- 'table' => $field['table'],
- 'field' => $field['field'],
- 'relationship' => 'none'
- );
+ $data = views_fetch_data($field['table']);
+ if (isset($data[$field['field']]['field'])) {
+ $relationship = empty($field['relationship']) ? 'none' : $field['relationship'];
+ $fields[$name] = array(
+ 'id' => $field['name'],
+ 'table' => $field['table'],
+ 'field' => $field['field'],
+ 'relationship' => $relationship,
+ );
+ }
}
$handler->override_option('fields', $fields);
+
+ $handler->override_option('relationships', $this->getRelations());
+
return $this;
}
@@ -110,20 +118,30 @@ class SearchlightDatasource {
$schema = drupal_get_schema($table);
if ($schema && isset($field, $schema['fields'][$field])) {
$class = $handler ? get_class($handler) : NULL;
-
+ // Use handler defined in $data in case $data has been altered by another
+ // and requires for example another handler
+ if (isset($data[$table][$field]['field']['handler'])) {
+ $class = $data[$table][$field]['field']['handler'];
+ }
// Get the datasource attribute type.
// We use the handler class for special cases like timestamp where DB
// column type is not enough information to determine the usage of the
// field.
$map = array(
- 'serial' => 'int',
- 'int' => 'int',
+ 'serial' => 'int',
+ 'int' => 'int',
'varchar' => 'text',
- 'text' => 'text',
- 'float' => 'float',
+ 'text' => 'text',
+ 'float' => 'float',
+ 'numeric' => 'float',
+ 'decimal' => 'float',
);
if (isset($map[$schema['fields'][$field]['type']])) {
$column_type = $map[$schema['fields'][$field]['type']];
+ // Allow custom handlers to specity the column type in definition
+ if (isset($handler->definition['data_type'])) {
+ $column_type = $handler->definition['data_type'];
+ }
if ($column_type === 'int' && strpos($class, 'date') !== FALSE) {
return 'timestamp';
}
@@ -163,6 +181,19 @@ class SearchlightDatasource {
return $fields;
}
+ /**
+ * Retrieve relationships currently enabled for this datasource.
+ */
+ function getRelations() {
+ $relationships = array();
+ foreach ($this->relations as $name => $relation) {
+ $relation['relationship'] = 'none';
+ $relation['group_type'] = 'group';
+ $relationships[$name] = $relation;
+ }
+ return $relationships;
+ }
+
/**
* Retrieve all possible multivalue fields for this base table.
*/
@@ -182,7 +213,6 @@ class SearchlightDatasource {
}
}
}
-
foreach ($usable as $view) {
if ($view->name !== 'searchlight_node_access') {
foreach ($view->display as $display) {
@@ -219,6 +249,57 @@ class SearchlightDatasource {
return $nodeaccess;
}
+
+ /**
+ * Finds all possible relations ships for a field.
+ *
+ * Orignal code resides in admin.inc of views.
+ */
+ function getFieldRelationshipOptions($field_id) {
+ $relationship_options = array();
+ $view = &$this->view;
+ $item = $view->get_item('default', 'field', $field_id);
+
+// // If relation is already set, return it
+// if (!empty($item['relationship']) && $item['relationship'] != 'none') {
+// $relationship_options[$item['relationship']] = $item['relationship'];
+// return $relationship_options;
+// }
+ // A whole bunch of code to figure out what relationships are valid for
+ // this item.
+ $relationships = $view->display_handler->get_option('relationships');
+ $relationship_options = array();
+
+ foreach ($relationships as $relationship) {
+ $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
+ // ignore invalid/broken relationships.
+ if (empty($relationship_handler)) {
+ continue;
+ }
+
+ // If this relationship is valid for this type, add it to the list.
+ $data = views_fetch_data($relationship['table']);
+ $base = $data[$relationship['field']]['relationship']['base'];
+ $base_fields = views_fetch_fields($base, 'field', $view->display_handler->use_group_by());
+ if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
+ $relationship_handler->init($view, $relationship);
+ $relationship_options[$relationship['id']] = $relationship_handler->options['field'];
+ //$relationship_options[$relationship['id']] = $relationship_handler->label();
+ }
+ }
+
+ if (!empty($relationship_options)) {
+ // Make sure the existing relationship is even valid. If not, force
+ // it to none.
+ $base_fields = views_fetch_fields($view->base_table, 'field', $view->display_handler->use_group_by());
+ if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
+ $relationship_options = array_merge(array('none' => t('Do not use a relationship')), $relationship_options);
+ }
+ }
+
+ return $relationship_options;
+ }
+
/**
* Provide the default form for setting options.
*/
@@ -226,26 +307,27 @@ class SearchlightDatasource {
views_include('admin');
views_include('form');
+ $this->viewInit()->viewSetHandlers();
+ $base_tables = $this->view->get_base_tables();
+
// Theme function will handle formatting of datasource information.
$form['#theme'] = 'searchlight_admin_datasource';
$form['#datasource'] = $this;
// Calculations of indexing percentage.
- $result = db_query("SELECT count(id) AS count, status FROM {searchlight_search} WHERE type = '%s' GROUP BY status", $this->base_table);
+ $result = db_query("SELECT count(id) AS count, status FROM {searchlight_search} WHERE type = :type GROUP BY status", array(':type' => $this->base_table));
$items_indexed = 0;
$items_total = 0;
- while ($row = db_fetch_object($result)) {
+ foreach ($result as $row) {
$items_indexed = $row->status == 1 ? $row->count : $items_indexed;
$items_total = $items_total + $row->count;
}
$form['index']['#tree'] = TRUE;
$form['index']['percent'] = array(
- '#type' => 'markup',
- '#value' => !empty($items_total) ? number_format(($items_indexed / $items_total * 100), 1) . '%' : '0%',
+ '#markup' => !empty($items_total) ? number_format(($items_indexed / $items_total * 100), 1) . '%' : '0%',
);
$form['index']['counts'] = array(
- '#type' => 'markup',
- '#value' => t('@indexed of @total total', array(
+ '#markup' => t('@indexed of @total total', array(
'@indexed' => $items_indexed,
'@total' => $items_total,
)),
@@ -257,7 +339,7 @@ class SearchlightDatasource {
$form['help'] = array(
'#type' => 'item',
- '#value' => t('Choose a usage type for each field in the search datasource. Content fields will be used to perform text searches. Attributes can be used to filter, sort or group the search results.')
+ '#markup' => t('Choose a usage type for each field in the search datasource. Content fields will be used to perform text searches. Attributes can be used to filter, sort or group the search results.'),
);
$form['fields'] = array(
@@ -270,7 +352,8 @@ class SearchlightDatasource {
// Add fields
$field_options = array();
- $fields = views_fetch_fields($this->base_table, 'field', TRUE);
+ $fields = views_fetch_fields(array_keys($base_tables), 'field', TRUE);
+
foreach ($fields as $field_id => $info) {
$field_options[$info['group']][$field_id] = $info['title'];
}
@@ -279,15 +362,19 @@ class SearchlightDatasource {
'#type' => 'select',
'#options' => $field_options,
);
+
$form['fields']['new']['add'] = array(
'#value' => t('Add field'),
'#type' => 'submit',
'#submit' => array('searchlight_admin_datasource_edit_submit'),
- '#ahah' => array(
- 'path' => 'admin/settings/search/datasource/ahah/edit-fields-new-add/fields',
- 'wrapper' => 'datasource-fields',
- 'method' => 'replace',
- ),
+ '#limit_validation_errors' => array(array('fields', 'new')),
+ // @TODO: Determine why AJAX is failing. Possibly because the element to
+ // which the ajax behavior is attached is replaced by the ajax callback.
+ // '#ajax' => array(
+ // 'callback' => 'searchlight_admin_datasource_ajax_fields_add',
+ // 'wrapper' => 'datasource-fields',
+ // 'method' => 'replace',
+ // ),
);
// Remove fields
@@ -296,14 +383,14 @@ class SearchlightDatasource {
'#value' => t('Remove selected fields'),
'#type' => 'submit',
'#submit' => array('searchlight_admin_datasource_edit_submit'),
- '#ahah' => array(
- 'path' => 'admin/settings/search/datasource/ahah/edit-fields-remove/fields',
- 'wrapper' => 'datasource-fields',
- 'method' => 'replace',
- ),
+ '#limit_validation_errors' => array(array('fields', 'fields')),
+ // '#ajax' => array(
+ // 'callback' => 'searchlight_admin_datasource_ajax_fields_remove',
+ // 'wrapper' => 'datasource-fields',
+ // 'method' => 'replace',
+ // ),
);
}
-
// Adjust existing fields
$form['fields']['fields'] = array('#tree' => TRUE);
foreach ($this->getFields() as $name => $info) {
@@ -315,16 +402,34 @@ class SearchlightDatasource {
'#default_value' => FALSE,
);
+ // Relation
+ if (count($relation_options = $this->getFieldRelationshipOptions($name)) > 1) {
+
+ $form['fields']['fields'][$name]['relationship'] = array(
+ '#type' => 'select',
+ '#options' => $relation_options,
+ '#default_value' => ((!empty($info['relationship'])) ? $info['relationship'] : NULL),
+ );
+ }
+ else {
+ $relation = $info['relationship'];
+ $form['fields']['fields'][$name]['relation_name'] = array(
+ '#markup' => ((empty($relation)) ? t('none') : $relation),
+ );
+ $form['fields']['fields'][$name]['relationship'] = array(
+ '#type' => 'hidden',
+ '#value' => ((empty($relation)) ? t('none') : $relation),
+ );
+ }
+
// Field label.
$form['fields']['fields'][$name]['label'] = array(
- '#type' => 'markup',
- '#value' => $info['label'],
+ '#markup' => $info['label'],
);
// Datatype
$form['fields']['fields'][$name]['datatype'] = array(
- '#type' => 'markup',
- '#value' => "{$info['datatype']}
",
+ '#markup' => "{$info['datatype']}
",
);
// Usage
@@ -332,20 +437,15 @@ class SearchlightDatasource {
$default_usage = isset($this->fields[$name]['usage']) ? $this->fields[$name]['usage'] : $default_usage;
$form['fields']['fields'][$name]['usage'] = array(
'#type' => 'select',
- '#options' => array( 'content' => t('Content'), 'attribute' => t('Attribute')),
+ '#options' => array(
+ 'content' => t('Content'),
+ 'attribute' => t('Attribute'),
+ ),
'#default_value' => $default_usage,
);
}
- // @TODO: Handle multivalues.
- $form['multivalues'] = array(
- '#tree' => TRUE,
- '#theme' => 'searchlight_admin_datasource_fields',
- '#title' => t('Multivalues'),
- '#prefix' => "
",
- '#suffix' => "
",
- );
-
+ // Handle multivalues.
// Add fields
$multivalue_options = array();
foreach ($this->buildMultivalues() as $name => $info) {
@@ -353,6 +453,13 @@ class SearchlightDatasource {
$multivalue_options[$name] = $info['label'];
}
}
+ $form['multivalues'] = array(
+ '#tree' => TRUE,
+ '#theme' => 'searchlight_admin_datasource_fields',
+ '#title' => t('Multivalues'),
+ '#prefix' => "",
+ '#suffix' => "
",
+ );
$form['multivalues']['new']['#tree'] = TRUE;
$form['multivalues']['new']['field'] = array(
'#type' => 'select',
@@ -362,11 +469,12 @@ class SearchlightDatasource {
'#value' => t('Add multivalue'),
'#type' => 'submit',
'#submit' => array('searchlight_admin_datasource_edit_submit'),
- '#ahah' => array(
- 'path' => 'admin/settings/search/datasource/ahah/edit-multivalues-new-add/multivalues',
- 'wrapper' => 'datasource-multivalues',
- 'method' => 'replace',
- ),
+ '#limit_validation_errors' => array(array('multivalues', 'new')),
+ // '#ajax' => array(
+ // 'callback' => 'searchlight_admin_datasource_ajax_multivalues_add',
+ // 'wrapper' => 'datasource-multivalues',
+ // 'method' => 'replace',
+ // ),
);
// Remove fields
@@ -375,14 +483,15 @@ class SearchlightDatasource {
'#value' => t('Remove selected multivalues'),
'#type' => 'submit',
'#submit' => array('searchlight_admin_datasource_edit_submit'),
- '#ahah' => array(
- 'path' => 'admin/settings/search/datasource/ahah/edit-multivalues-remove/multivalues',
- 'wrapper' => 'datasource-multivalues',
- 'method' => 'replace',
- ),
+ '#limit_validation_errors' => array(array('multivalues', 'fields')),
+ // '#ajax' => array(
+ // 'callback' => 'searchlight_admin_datasource_ajax_multivalues_remove',
+ // 'wrapper' => 'datasource-multivalues',
+ // 'method' => 'replace',
+ // ),
);
}
-
+ $form['multivalues']['fields'] = array();
foreach ($this->getMultivalues() as $name => $info) {
$form['multivalues']['fields'][$name] = array();
@@ -394,33 +503,144 @@ class SearchlightDatasource {
// Field label.
$form['multivalues']['fields'][$name]['label'] = array(
- '#type' => 'markup',
- '#value' => $info['label'],
+ '#markup' => $info['label'],
);
// Datatype
$form['multivalues']['fields'][$name]['datatype'] = array(
- '#type' => 'markup',
- '#value' => "{$info['datatype']}
",
+ '#markup' => "{$info['datatype']}
",
);
$form['multivalues']['fields'][$name]['usage'] = array(
- '#type' => 'markup',
- '#value' => t('Multivalue'),
+ '#markup' => t('Multivalue'),
+ );
+ }
+
+ $form['relations'] = array(
+ '#prefix' => "",
+ '#suffix' => "
",
+ '#tree' => TRUE,
+ '#theme' => 'searchlight_admin_datasource_relations',
+ '#title' => t('Relations'),
+ );
+
+ // Add relations
+ $relation_options = array();
+ $fields = views_fetch_fields(array_keys($base_tables), 'relationship');
+ foreach ($fields as $relation_id => $info) {
+ $relation_options[$info['group']][$relation_id] = $info['title'];
+ }
+ $form['relations']['new']['#tree'] = TRUE;
+ $form['relations']['new']['relation'] = array(
+ '#type' => 'select',
+ '#options' => $relation_options,
+ );
+ $form['relations']['new']['add'] = array(
+ '#value' => t('Add relation'),
+ '#type' => 'submit',
+ '#submit' => array('searchlight_admin_datasource_edit_submit'),
+ '#limit_validation_errors' => array(array('relations', 'new')),
+ );
+
+ $relations = $this->getRelations();
+ // Remove relations
+ if (count($relations)) {
+ $form['relations']['remove'] = array(
+ '#value' => t('Remove selected relations'),
+ '#type' => 'submit',
+ '#submit' => array('searchlight_admin_datasource_edit_submit'),
+ '#limit_validation_errors' => array(array('relations', 'relations')),
);
}
+ // Adjust existing relations
+ $form['relations']['relations'] = array('#tree' => TRUE);
+ foreach ($relations as $name => $info) {
+ $form['relations']['relations'][$name] = array();
+
+ // Remove field checkbox.
+ $form['relations']['relations'][$name]['remove'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => FALSE,
+ );
+
+ // Relation label.
+ $form['relations']['relations'][$name]['label'] = array(
+ '#type' => 'textfield',
+ '#default_value' => $info['label'],
+ '#field_suffix' => '(' . $info['table'] . '.' . $info['field'] . ')',
+ );
- $form['options']['#tree'] = TRUE;
- // In reality, these are multivalue fields that are generated
- // programmatically.
- if ($this->base_table === 'node') {
- $form['options']['node_access'] = array(
- '#title' => t('Node access'),
- '#description' => t('Include node access information in datasource'),
+ // Required relation.
+ $form['relations']['relations'][$name]['required'] = array(
'#type' => 'checkbox',
- '#default_value' => $this->options['node_access'],
+ '#default_value' => (int) $info['required'],
);
}
+
+ $backend = variable_get('searchlight_backend');
+ $settings = variable_get('searchlight_backend_' . $backend);
+ if ($settings['grouping']) {
+ // Group
+ $form['groupfield'] = array(
+ '#tree' => TRUE,
+ '#theme' => 'searchlight_admin_datasource_fields',
+ '#title' => t('Group'),
+ '#prefix' => "",
+ '#suffix' => "
",
+ );
+
+ // Add fields
+ $groupfield_options = array();
+ foreach ($this->getFields() as $name => $info) {
+ $groupfield_options[$name] = $info['label'];
+ }
+ $form['groupfield']['new']['#tree'] = TRUE;
+ $form['groupfield']['new']['field'] = array(
+ '#type' => 'select',
+ '#options' => $groupfield_options,
+ );
+ $form['groupfield']['new']['add'] = array(
+ '#value' => t('Add group field'),
+ '#type' => 'submit',
+ '#submit' => array('searchlight_admin_datasource_edit_submit'),
+ '#limit_validation_errors' => array(array('groupfield', 'new')),
+ );
+
+ // Remove field
+ if (isset($this->options['groupfield'])) {
+ $form['groupfield']['remove'] = array(
+ '#value' => t('Remove groupfield'),
+ '#type' => 'submit',
+ '#submit' => array('searchlight_admin_datasource_edit_submit'),
+ '#limit_validation_errors' => array(array('groupfield', 'fields')),
+ );
+ }
+ $form['groupfield']['fields'] = array();
+ if (isset($this->options['groupfield'])) {
+ $form['groupfield']['fields'][$this->options['groupfield']] = array();
+
+ // Remove field checkbox.
+ $form['groupfield']['fields'][$this->options['groupfield']]['remove'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => FALSE,
+ );
+
+ // Field label.
+ $form['groupfield']['fields'][$this->options['groupfield']]['label'] = array(
+ '#markup' => $this->fields[$this->options['groupfield']]['label'],
+ );
+
+ // Datatype
+ $form['groupfield']['fields'][$this->options['groupfield']]['datatype'] = array(
+ '#markup' => "{$this->fields[$this->options['groupfield']]['datatype']}
",
+ );
+
+ $form['groupfield']['fields'][$this->options['groupfield']]['usage'] = array(
+ '#markup' => t('Grouping'),
+ );
+ }
+ }
+
return $form;
}
@@ -459,6 +679,31 @@ class SearchlightDatasource {
}
searchlight_datasource_save($this, TRUE);
break;
+ case 'edit-groupfield-new-add':
+ $this->options['groupfield'] = $form_state['values']['groupfield']['new']['field'];
+ searchlight_datasource_save($this, TRUE);
+ break;
+ case 'edit-groupfield-remove':
+ foreach ($form_state['values']['groupfield']['fields'] as $name => $values) {
+ if (!empty($values['remove'])) {
+ unset ($this->options['groupfield']);
+ }
+ }
+ searchlight_datasource_save($this, TRUE);
+ break;
+ case 'edit-relations-new-add':
+ list($table, $field) = explode('.', $form_state['values']['relations']['new']['relation']);
+ $this->addRelation($table, $field);
+ searchlight_datasource_save($this, TRUE);
+ break;
+ case 'edit-relations-remove':
+ foreach ($form_state['values']['relations']['relations'] as $name => $values) {
+ if (!empty($values['remove'])) {
+ $this->removeRelation($name);
+ }
+ }
+ searchlight_datasource_save($this, TRUE);
+ break;
case 'edit-save':
// Save additional metadata from fields, multivalues.
foreach (array('fields', 'multivalues') as $key) {
@@ -472,34 +717,103 @@ class SearchlightDatasource {
}
}
// Save options.
- $this->options = $form_state['values']['options'];
+ $this->options = isset($form_state['values']['options']) ? $form_state['values']['options'] : $this->options;
+
+ // Save relations
+ if (!empty($form_state['values']['relations']['relations'])) {
+ foreach ($form_state['values']['relations']['relations'] as $name => $values) {
+ $values = array_diff_key($values, array('remove' => NULL));
+ if (isset($this->relations[$name])) {
+ $this->relations[$name] = array_merge($this->relations[$name], $values);
+ }
+ }
+ }
// Save the datasource.
searchlight_datasource_save($this);
drupal_set_message(t('Datasource @datasource saved. The index for this datasource needs to be rebuilt.', array('@datasource' => $this->name)));
break;
+
+ case 'edit-relations-new-add':
+ $this->addRelation($form_state['values']['relations']['new']['table'], $form_state['values']['relations']['new']['field']);
+ searchlight_datasource_save($this, TRUE);
+ break;
+ case 'edit-relations-remove':
+ foreach ($form_state['values']['relations']['relations'] as $name => $values) {
+ if (!empty($values['remove'])) {
+ $this->removeRelation(NULL, NULL, $name);
+ }
+ }
+ searchlight_datasource_save($this, TRUE);
+ break;
+ }
+ }
+
+
+ /**
+ * Remove relation.
+ * @param string $relation
+ */
+ function removeRelation($name) {
+ if (array_key_exists($name, $this->relations)) {
+ unset($this->relations[$name]);
+ }
+ return $this->viewInit()->viewSetHandlers();
+ }
+
+ /**
+ * Adds a new relation for the datasource.
+ * @param string $table
+ * @param string $field
+ * @param boolean $required
+ */
+ function addRelation($table, $field, $label = NULL, $required = FALSE) {
+ $this->viewInit()->viewSetHandlers();
+
+ if (empty($label)) {
+ $label = $table . '.' . $field;
}
+
+ $options = array(
+ 'label' => $label,
+ 'required' => (bool) $required,
+ );
+ $id = $this->view->add_item('default', 'relationship', $table, $field, $options);
+
+ $this->relations = $this->view->display_handler->get_option('relationships');
}
function addField($table, $field) {
// Add the field to the view and build. This will give us an inited handler
// with full aliases.
$this->viewInit()->viewSetHandlers();
- $fields = $this->view->display_handler->get_option('fields');
+ $fields = &$this->view->display_handler->get_option('fields');
$fields[$field] = array(
'id' => $field,
'table' => $table,
'field' => $field,
'relationship' => 'none',
);
+
$this->view->display_handler->set_option('fields', $fields);
$this->view->build();
+
+ $relationship = 'none';
+ foreach($this->getFieldRelationshipOptions($field) as $key => $val) {
+ $relationship = $val;
+ }
+ $fields[$field]['relationship'] = $relationship;
// Retrieve field information for storage with datasource.
$handler = isset($this->view->field[$field]) ? $this->view->field[$field] : NULL;
+ // Track fields added so we can provide a default usage based on datatype.
+ $fields_added = array();
+
// Don't use alias for base field.
if ($field === $this->view->base_field) {
+ $fields_added[] = $field;
+
$this->fields[$field] = array(
'label' => $field,
'datatype' => $this->getDatatype(NULL, $table, $field),
@@ -509,13 +823,24 @@ class SearchlightDatasource {
);
}
// Use alias for all other fields.
- if ($handler) {
+ if ($handler && $field != $this->view->base_field) {
+ // Generate unique id's
+ $alias_base = $handler->field_alias;
+ $count = 1;
+ while (!empty($this->fields[$handler->field_alias])) {
+ $handler->field_alias = $alias_base . '_' . $count++;
+ }
+
+ $fields_added[] = $handler->field_alias;
+
$this->fields[$handler->field_alias] = array(
+ 'id' => $handler->field_alias,
'label' => $handler->ui_name() . " ({$handler->real_field})",
'datatype' => $this->getDatatype($handler, $handler->table, $handler->real_field),
'table' => $handler->table,
'field' => $handler->real_field,
'name' => $handler->field_alias,
+ 'relationship' => $relationship,
);
}
if (!empty($handler->additional_fields)) {
@@ -528,17 +853,40 @@ class SearchlightDatasource {
$table = isset($info['table']) ? $info['table'] : $table;
$field = $info['field'];
}
- if ($field !== $handler->view->base_field || $table !== $handler->view->base_table) {
+
+ // Check if we are dealing with a field API field handler.
+ // - Skip the actual field specified by the handler (entity_id).
+ // - Exclude field metadata in additional_fields (language, entity_type, delta, etc.)
+ $add_field = FALSE;
+ if (isset($handler->definition['field_info'], $handler->definition['entity_tables'])) {
+ $add_field = !in_array($field, array('delta', 'entity_type', 'language')) && strpos($field, '_format') === FALSE;
+ }
+ else {
+ $add_field = $field !== $handler->view->base_field || $table !== $handler->view->base_table;
+ }
+ if ($add_field) {
+ $fields_added[] = $handler->aliases[$field];
+
$this->fields[$handler->aliases[$field]] = array(
+ 'id' => $handler->aliases[$field],
'label' => $handler->ui_name() . " ({$field})",
'datatype' => $this->getDatatype($handler, $table, $field),
'table' => $table,
'field' => $field,
'name' => $handler->aliases[$field],
+ 'relationship' => $relationship,
);
}
}
}
+
+ if (sizeof($fields_added)) {
+ foreach ($fields_added as $name) {
+ if (!isset($this->fields[$name]['usage'])) {
+ $this->fields[$name]['usage'] = ($this->fields[$name]['datatype'] === 'text') ? 'content' : 'attribute';
+ }
+ }
+ }
return $this->viewInit()->viewSetHandlers();
}
@@ -548,7 +896,7 @@ class SearchlightDatasource {
unset($this->fields[$name]);
}
}
- else if (isset($table, $field)) {
+ elseif (isset($table, $field)) {
foreach ($this->fields as $name => $field) {
if ($field['table'] === $table && $field['field'] === $field) {
unset($this->fields[$name]);
diff --git a/includes/SearchlightEnvironment.inc b/includes/SearchlightEnvironment.inc
index 67b977a..3774af1 100644
--- a/includes/SearchlightEnvironment.inc
+++ b/includes/SearchlightEnvironment.inc
@@ -97,14 +97,19 @@ class SearchlightEnvironment {
$rendered = array();
foreach ($this->plugins as $name => $plugin) {
foreach ($deltas as $delta) {
- if ($render = $plugin->render(drupal_clone($this->query), $delta)) {
+ if ($render = $plugin->render(clone $this->query, $delta)) {
// Theme each item
$items = array();
foreach ($render as $item) {
$items[] = $plugin->theme($item, $delta);
}
// Generate a label/items array suitable for theme('searchlight_facet')
- $rendered[$name] = array('label' => $plugin->label($delta), 'items' => $items, 'delta' => $delta);
+ $rendered[$name] = array(
+ 'name' => $name,
+ 'label' => $plugin->label($delta),
+ 'items' => $items,
+ 'delta' => $delta,
+ );
}
}
}
@@ -127,17 +132,26 @@ class SearchlightEnvironment {
*/
function getBlock($delta) {
if ($delta === 'facets' && $this->initView()) {
+ // Provide an array with 'unthemed' data for modules implementing
+ // hook_block_view_alter() in order to have more theming flexibility
+ $data = array();
$output = '';
+ $data['container']['name'] = $this->name;
+ $data['container']['view_name'] = $this->view->name;
+ $data['container']['facets'] = array();
foreach ($this->render() as $rendered) {
- $output .= theme('searchlight_facet', $rendered);
+ $data['container']['facets'][] = $rendered;
+ // If we don't get back arrays for items, we directly them them
+ if (!is_array($rendered['items'][0])) {
+ $output .= theme('searchlight_facet', array('facet' => $rendered));
+ }
}
if (!empty($output)) {
$output = "{$output}
";
- return array(
- 'subject' => filter_xss_admin($this->options['facets_label']),
- 'content' => $output,
- );
+ $data['label'] = filter_xss_admin($this->options['facets_label']);
+ $data['content'] = $output;
}
+ return $data;
}
return array();
}
@@ -149,6 +163,7 @@ class SearchlightEnvironment {
// Adapted from searchlight_build_view. It should be possible to
// retrieve a data source from a view without running it, untill then...
$split = explode(':', $this->view_display);
+
if (count($split) === 2 && $view = views_get_view($split[0])) {
return searchlight_get_datasource($view->base_table);
}
@@ -209,7 +224,10 @@ class SearchlightEnvironment {
if ($datasource) {
$form['facets'] = array('#tree' => TRUE);
$fields = $datasource->fields;
- $fields['search_query'] = array('label' => t('Search query'));
+ $fields['search_query'] = array(
+ 'label' => t('Search query'),
+ 'name' => 'search_query'
+ );
foreach ($fields as $name => $field) {
if ($this->isValidFacet($name)) {
$form['facets'][$name] = array(
@@ -219,12 +237,11 @@ class SearchlightEnvironment {
$form['facets'][$name]['enabled'] = array(
'#title' => t('Enabled'),
'#type' => 'checkbox',
- '#default_value' => isset($this->facets[$name]['enabled']) ? $this->facets[$name]['enabled'] : TRUE,
+ '#default_value' => isset($this->facets[$name]['enabled']) ? $this->facets[$name]['enabled'] : FALSE,
);
$form['facets'][$name]['ui_name'] = array(
'#title' => t('Facet'),
- '#type' => 'markup',
- '#value' => $field['label'],
+ '#markup' => $field['label'],
);
$form['facets'][$name]['weight'] = array(
'#title' => t('Weight'),
@@ -235,7 +252,8 @@ class SearchlightEnvironment {
// We instantiate plugins here rather than using initView() as the
// facets on this form may not already be enabled for this environment.
$plugin = searchlight_get_facet($datasource, $name);
- $plugin->construct($this, $datasource->fields[$name], $this->getValue($name), isset($this->facets[$name]) ? $this->facets[$name] : array());
+ $plugin->construct($this, $field, $this->getValue($name), isset($this->facets[$name]) ? $this->facets[$name] : array());
+
$plugin->optionsForm($form['facets'][$name], $form_state);
$form['facets'][$name]['settings'] = array(
@@ -265,6 +283,9 @@ class SearchlightEnvironment {
unset($this->facets[$name]['settings']);
$this->facets[$name] = array_merge($this->facets[$name], $options['settings']);
}
+ if (empty($options['enabled'])) {
+ unset($this->facets[$name]);
+ }
}
$this->options = $form_state['values']['options'];
@@ -301,8 +322,8 @@ class SearchlightEnvironment {
* Get the URL options for the current set of active facets, adjusted using
* one of the $op operations.
*
- * 'add': Add a facet value for the given key/value pair.
- * 'remove': Add a facet value for the given key/value pair.
+ * 'add': Add a facet value or multiple facet values for the given key/value pair.
+ * 'remove': Add a facet value or multiple facet values for the given key/value pair.
* 'active': Retain only active facets and drop any other query strings.
*/
function getURLOptions($op = 'add', $key = NULL, $value = NULL) {
@@ -315,8 +336,17 @@ class SearchlightEnvironment {
break;
case 'remove':
$modifier = $modifier + $this->active_values;
- if (isset($modifier[$key])) {
- unset($modifier[$key]);
+ if (is_array($modifier[$key]) && !empty($value)) {
+ foreach ($modifier[$key] as $k => $v) {
+ if ($v === $value) {
+ unset($modifier[$key][$k]);
+ }
+ }
+ }
+ else {
+ if (isset($modifier[$key])) {
+ unset($modifier[$key]);
+ }
}
break;
case 'active':
@@ -348,7 +378,7 @@ class SearchlightEnvironment {
else if (empty($modifier)) {
$exclude[] = $key;
}
- $options['query'] = drupal_query_string_encode($query, $exclude);
+ $options['query'] = drupal_get_query_parameters($query, $exclude);
return $options;
}
diff --git a/libraries/SolrPhpClient/Apache/Solr/Service.php b/libraries/SolrPhpClient/Apache/Solr/Service.php
index c9786b9..61791a0 100644
--- a/libraries/SolrPhpClient/Apache/Solr/Service.php
+++ b/libraries/SolrPhpClient/Apache/Solr/Service.php
@@ -327,6 +327,7 @@ protected function _sendRawGet($url, $timeout = FALSE)
}
//$http_response_header is set by file_get_contents
+ $http_response_header = '';
$response = new Apache_Solr_Response(@file_get_contents($url, false, $this->_getContext), $http_response_header, $this->_createDocuments, $this->_collapseSingleValueArrays);
if ($response->getHttpStatus() != 200)
diff --git a/plugins/SearchlightBackend.inc b/plugins/SearchlightBackend.inc
index a287858..65dcbbf 100644
--- a/plugins/SearchlightBackend.inc
+++ b/plugins/SearchlightBackend.inc
@@ -88,8 +88,7 @@ abstract class SearchlightBackend {
*
* @param $datasource
*/
- function initClient($datasource) {
- }
+ function initClient($datasource) { }
/**
* Execute a query using the search backend. Should return an array with the
@@ -99,38 +98,32 @@ abstract class SearchlightBackend {
* 'total': Total number of non-paged results.
* 'raw': The raw result object/array/data from the search client.
*/
- function executeQuery(&$client, $datasource, $query = '') {
- }
+ function executeQuery(&$client, $datasource, $query = '') { }
/**
* Set any custom options for the search backend.
*/
- function setOptions(&$client, $datasource, $options) {
- }
+ function setOptions(&$client, $datasource, $options) { }
/**
* Set a filter parameter for the search backend.
*/
- function setFilter(&$client, $datasource, $filters) {
- }
+ function setFilter(&$client, $datasource, $filters) { }
/**
* Set a sort parameter for the search backend.
*/
- function setSort(&$client, $datasource, $sorts) {
- }
-
+ function setSort(&$client, $datasource, $sorts) { }
+
/**
* Set a pager/limit parameter for the search backend.
*/
- function setPager(&$client, $offset, $limit) {
- }
+ function setPager(&$client, $offset, $limit) { }
/**
* Set node_access attribute filters.
*/
- function setNodeAccess(&$client) {
- }
+ function setNodeAccess(&$client) { }
/**
* Utility date methods =====================================================
@@ -193,8 +186,7 @@ abstract class SearchlightBackend {
/**
* Invalidate the search index associated with this datasource.
*/
- function invalidateIndex($datasource) {
- }
+ function invalidateIndex($datasource) { }
/**
* Drush methods ============================================================
@@ -203,36 +195,30 @@ abstract class SearchlightBackend {
/**
* Start a search backend daemon process through drush.
*/
- function drushSearchd($command = 'start') {
- }
+ function drushSearchd($command = 'start') { }
/**
* Start a search backend indexing process through drush.
*/
- function drushIndex() {
- }
+ function drushIndex() { }
/**
* Write search backend configuration files through drush.
*/
- function drushConf() {
- }
+ function drushConf() { }
/**
* Execute functionality on a drush cron run.
*/
- function drushCron() {
- }
+ function drushCron() { }
/**
* When a new site is installed via Aegir.
*/
- function drushAegirInstall() {
- }
+ function drushAegirInstall() { }
/**
* When a site is migrated via Aegir.
*/
- function drushAegirDeploy() {
- }
+ function drushAegirDeploy() { }
}
diff --git a/plugins/SearchlightBackendSolr.inc b/plugins/SearchlightBackendSolr.inc
index 43f45e4..fa6e501 100644
--- a/plugins/SearchlightBackendSolr.inc
+++ b/plugins/SearchlightBackendSolr.inc
@@ -40,6 +40,12 @@ class SearchlightBackendSolr extends SearchlightBackend {
'#default_value' => $this->settings['path'],
'#size' => 60,
);
+ $form['jar_path'] = array(
+ '#title' => t('Solr jar path'),
+ '#type' => 'textfield',
+ '#default_value' => $this->settings['jar_path'],
+ '#size' => 60,
+ );
$form['item_limit'] = array(
'#title' => t('Items to index per job'),
'#type' => 'select',
@@ -53,6 +59,11 @@ class SearchlightBackendSolr extends SearchlightBackend {
1000 => 1000,
),
);
+ $form['grouping'] = array(
+ '#title' => t('Supports Result Grouping / Field Collapsing (Solr4.0 and higher)'),
+ '#type' => 'checkbox',
+ '#default_value' => $this->settings['grouping'],
+ );
return $form;
}
@@ -61,7 +72,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
*/
function initClient($datasource) {
$this->solrInclude();
- $path = $this->settings['path'] .'/'. $datasource->id;
+ $path = $this->settings['path'] . '/' . $datasource->id;
$client = new Apache_Solr_Service($this->settings['host'], (int) $this->settings['port'], $path);
return $client;
}
@@ -76,29 +87,53 @@ class SearchlightBackendSolr extends SearchlightBackend {
$options = array();
if (isset($client->searchlightSort)) {
+ $sort = '';
foreach ($client->searchlightSort as $field => $order) {
$field = ($field == 'searchlight_weight' ? 'score' : $field);
- $sort .= $field .' '. strtolower($order) .',';
+ $sort .= $field . ' ' . strtolower($order) . ',';
}
$options['sort'] = rtrim($sort, ',');
}
+
+ // Handle grouping
+ if (isset($datasource->options['groupfield'])) {
+ $groupfilter = array();
+ $options['group'] = 'true';
+ $options['group.field'] = $datasource->options['groupfield'];
+ }
- try {
+ try {
$response = $client->search($query, $offset, $limit, $options);
}
catch (Exception $e) {
- drupal_set_message('Caught exception: '. $e->getMessage(), 'error');
+ drupal_set_message('Caught exception: ' . $e->getMessage(), 'error');
return FALSE;
}
-
- foreach ($response->response->docs as $doc) {
- $ids[] = $doc->{$datasource->base_field};
+
+ if (!empty($datasource->options['groupfield']) && is_array($response->grouped->{$datasource->options['groupfield']}->groups)) {
+ foreach ($response->grouped->{$datasource->options['groupfield']}->groups as $group) {
+ if (is_array($group->doclist->docs)) {
+ foreach ($group->doclist->docs as $doc) {
+ $ids[] = $doc->{$datasource->base_field};
+ }
+ }
+ }
+ }
+ else {
+ foreach ($response->response->docs as $doc) {
+ $ids[] = $doc->{$datasource->base_field};
+ }
}
-
if (!empty($ids)) {
+ if (!empty($datasource->options['groupfield'])) {
+ $count = $response->grouped->{$datasource->options['groupfield']}->matches;
+ }
+ else {
+ $count = $response->response->numFound;
+ }
return array(
- 'result' => $ids,
- 'total' => $response->response->numFound,
+ 'result' => $ids,
+ 'total' => $count,
'raw' => $response,
);
}
@@ -115,29 +150,29 @@ class SearchlightBackendSolr extends SearchlightBackend {
foreach ($filters as $params) {
$field = $params['field'];
$operator = $params['operator'];
- $args = $params['args'];
+ $value = $params['args'];
- switch($operator) {
+ switch ($operator) {
case '<':
case '<=':
- $range_filters[$field]['max'] = $args[0];
+ $range_filters[$field]['max'] = implode($value);
break;
case '>':
case '>=':
- $range_filters[$field]['min'] = $args[0];
+ $range_filters[$field]['min'] = implode($value);
break;
case '=':
- $client->searchlightFilters[] = $field .':"'. $args[0] .'"';
+ $client->searchlightFilters[] = $field . ':"' . implode($value) . '"';
break;
case '!=':
case '<>':
- $client->searchlightFilters[] = '-'. $field .':"'. $args[0] .'"';
+ $client->searchlightFilters[] = '-' . $field . ':"' . implode($value) . '"';
break;
case 'IN':
- $client->searchlightFilters[] = "{$field}:(" . implode(' OR ', $args) .")";
+ $client->searchlightFilters[] = "{$field}:(" . implode(' OR ', $value) . ")";
break;
case 'NOT IN':
- $client->searchlightFilters[] = "-{$field}:(" . implode(' OR ', $args) .")";
+ $client->searchlightFilters[] = "-{$field}:(" . implode(' OR ', $value) . ")";
break;
default:
//dsm($params);
@@ -159,7 +194,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
if (!empty($sorts)) {
$client->searchlightSort = array();
foreach ($sorts as $sort) {
- $client->searchlightSort[$sort['field']] = $sort['order'];
+ $client->searchlightSort[$sort['field']] = $sort['direction'];
}
}
}
@@ -200,7 +235,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
function facetBuild(&$client, $datasource, $query = '', $facets) {
$query = $this->solrPrepareQuery($client, $datasource, $query);
- $limit_options = $options;
+ $limit_options = array();
$options = array(
'facet' => 'true',
'facet.mincount' => '1',
@@ -219,12 +254,13 @@ class SearchlightBackendSolr extends SearchlightBackend {
$field = $datasource->fields[$facet['field']];
switch ($field['datatype']) {
case 'timestamp':
+ case 'date':
$date_facets[$facet['field']] = $facet;
// TODO cache this value so it's not requested on every page load.
$limits = array(
- 'max' => $facet['field'] ." desc",
- 'min' => $facet['field'] ." asc",
+ 'max' => $facet['field'] . " desc",
+ 'min' => $facet['field'] . " asc",
);
foreach ($limits as $lim => $sort) {
@@ -237,7 +273,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
$limits[$lim] = $response->response->docs[0]->{$facet['field']};
}
catch (Exception $e) {
- drupal_set_message('Caught exception: '. $e->getMessage(), 'error');
+ drupal_set_message('Caught exception: ' . $e->getMessage(), 'error');
return;
}
}
@@ -245,7 +281,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
$options['facet.date'][] = $facet['field'];
// @TODO several issues here
// - start/end will need to be adjusted to match an even started
- // point for the gap so that dates all fit within the declared
+ // point for the gap so that dates all fit within the declared
// gap, and we avoid "midnight" problems.
// - the month/day/time is set to Jan 1 00:00:00 as granularity/gaps
// are calculated as increments from the starting point. HOWEVER,
@@ -257,7 +293,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
$options["f.{$facet['field']}.facet.date.start"] = $limits['min'];
$options["f.{$facet['field']}.facet.date.end"] = $limits['max'];
- switch ($facet['granularity']) {
+ switch (!empty($facet['granularity']) ? $facet['granularity'] : 'month') {
case 'day':
$gap = '+1DAY';
break;
@@ -284,7 +320,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
$response = $client->search($query, 0, 1, $options);
}
catch (Exception $e) {
- drupal_set_message('Caught exception: '. $e->getMessage(), 'error');
+ drupal_set_message('Caught exception: ' . $e->getMessage(), 'error');
return;
}
@@ -295,8 +331,13 @@ class SearchlightBackendSolr extends SearchlightBackend {
foreach ($v as $i => $j) {
// '_empty_' is Solr speak for NULL or empty values. Convert that
// string back into something more palatable in Drupal.
- $i = $i === '_empty_' ? NULL : $i;
- $built[$k][$i] = array('id' => $i, 'count' => $j);
+ $i = ($i === '_empty_' || empty($i)) ? NULL : $i;
+ if (!empty($i)) {
+ $built[$k][$i] = array(
+ 'id' => $i,
+ 'count' => $j,
+ );
+ }
}
}
}
@@ -305,16 +346,19 @@ class SearchlightBackendSolr extends SearchlightBackend {
foreach ($response->facet_counts->facet_dates as $k => $v) {
foreach ($v as $i => $j) {
// Filter out empty ranges.
- if (!empty($j) && !in_array($i, array('gap', 'end'))) {
+ if (!empty($j) && !in_array($i, array('gap', 'end', 'start'))) {
// $time = gmmktime($i);
// $build[$k][$i]format_date($time);
- $built[$k][$i] = array('id' => $i, 'count' => $j);
+ $built[$k][$i] = array(
+ 'id' => $i,
+ 'count' => $j,
+ );
}
}
- // Reverse-chronological sort the dates.
+ // Chronological sort the dates.
// @TODO: unhardwire this and do handling of facets sorting in general.
if (!empty($built[$k])) {
- krsort($built[$k]);
+ ksort($built[$k]);
// Hard limit the date facet as Solr returns all elements between start
// and end times.
if (!empty($date_facets[$k]['limit']) && count($built[$k]) > $date_facets[$k]['limit']) {
@@ -338,7 +382,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
$solr->commit();
}
catch (Exception $e) {
- drupal_set_message('Caught exception: '. $e->getMessage(), 'error');
+ drupal_set_message('Caught exception: ' . $e->getMessage(), 'error');
return;
}
}
@@ -348,19 +392,38 @@ class SearchlightBackendSolr extends SearchlightBackend {
* Start the Solr service.
*/
function drushSearchd() {
- $file_path = conf_path() .'/solr';
- $solr_home = drush_locate_root() .'/'. conf_path() . '/solr';
- $log_dir = $solr_home .'/log';
- if (file_check_directory($log_dir, TRUE)) {
- $opts .= '-Dsolr.solr.home='. $solr_home .' ';
- $opts .= '-Djetty.logs='. $log_dir.' ';
- $opts .= '-Djetty.home='. $this->settings['jar_path'] .' ';
- $opts .= '-jar '. $this->settings['jar_path'] .'/start.jar';
- drush_op('drush_shell_exec', 'java '. $opts);
+ $file_path = conf_path() . '/solr';
+ $solr_home = drush_locate_root() . '/' . conf_path() . '/solr';
+ $log_dir = $solr_home . '/log';
+ if (file_prepare_directory($log_dir, TRUE)) {
+ $opts .= '-Dsolr.solr.home=' . $solr_home . ' ';
+ $opts .= '-Djetty.logs=' . $log_dir . ' ';
+ $opts .= '-Djetty.home=' . $this->settings['jar_path'] . ' ';
+ $opts .= '-jar ' . $this->settings['jar_path'] . '/start.jar';
+ drush_op('drush_shell_exec', 'java ' . $opts);
}
return drush_log("An error ocurred while starting the search daemon.", 'error');
}
+ /**
+ * Create Solr date format
+ */
+ function createSolrDate($value, $type = 'date') {
+ if (!empty($value)) {
+ switch($type) {
+ case 'timestamp' && preg_match('~^[1-9][0-9]*$~', $value):
+ $date = gmdate('Y-m-d\\TH:i:s\\Z', $value);
+ break;
+ default:
+ $date_time = new DateTime($value, new DateTimeZone('UTC'));
+ $date = $date_time->format('Y-m-d\\TH:i:s\\Z');
+ break;
+ }
+ return $date;
+ }
+ return $value;
+ }
+
/**
* Override of drushIndex().
* Run an indexing job. Requires that the Solr service is available.
@@ -442,7 +505,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
}
$ids = implode(',', array_keys($items['datasource']));
- $view->query->add_where(0, "{$view->base_table}.{$view->base_field} IN ({$ids})");
+ $view->query->add_where(0, "{$view->base_table}.{$view->base_field} IN ({$ids})", array(), 'formula');
}
else {
continue;
@@ -477,26 +540,36 @@ class SearchlightBackendSolr extends SearchlightBackend {
break;
case 'multivalue':
$mva_item = $raw_items[$field['name']][$id];
- // Ideally we would use the handler to discover the MVA field
- // alias. For now just do it by convention.
- $alias = "{$field['table']}_{$field['field']}";
- if (isset($mva_item->{$alias})) {
- if ($field['datatype'] == 'timestamp') {
- $document->{$field['name']} = gmdate('Y-m-d\\TH:i:s\\Z', $mva_item->{$alias});
- }
- else {
- $document->{$field['name']} = $mva_item->{$alias};
- }
- }
+ $document->{$field['name']} = $mva_item->{$field['name']};
break;
default:
$raw_item = $raw_items['datasource'][$id];
- if (isset($raw_item->{$field['name']})) {
- if ($field['datatype'] == 'timestamp') {
- $document->{$field['name']} = gmdate('Y-m-d\\TH:i:s\\Z', $raw_item->{$field['name']});
+ if (!empty($raw_item->{$field['name']})) {
+ switch($field['datatype']) {
+ case 'date':
+ case 'timestamp':
+ $document->{$field['name']} = $this->createSolrDate($raw_item->{$field['name']}, $field['datatype']);
+ break;
+ case 'int':
+ $document->{$field['name']} = intval($raw_item->{$field['name']});
+ break;
+ default:
+ $document->{$field['name']} = $raw_item->{$field['name']};
+ break;
}
- else {
- $document->{$field['name']} = $raw_item->{$field['name']};
+ }
+ elseif (!empty($item->{$field['name']})) {
+ switch($field['datatype']) {
+ case 'date':
+ case 'timestamp':
+ $document->{$field['name']} = $this->createSolrDate($item->{$field['name']}, $field['datatype']);
+ break;
+ case 'int':
+ $document->{$field['name']} = intval($item->{$field['name']});
+ break;
+ default:
+ $document->{$field['name']} = $item->{$field['name']};
+ break;
}
}
break;
@@ -511,10 +584,11 @@ class SearchlightBackendSolr extends SearchlightBackend {
$solr->commit();
// $solr->optimize(); //merges multiple segments into one
- $args = $ids;
- array_unshift($args, $datasource->base_table);
- db_query("UPDATE {searchlight_search} SET status = 1 WHERE type ='%s'
- AND id IN (". rtrim(str_repeat('%d,', count($ids)), ',') .")", $args);
+ $query = db_update('searchlight_search')
+ ->fields(array('status' => 1))
+ ->condition('type', $datasource->base_table)
+ ->condition('id', $ids, 'IN')
+ ->execute();
drush_log(dt('@datasource: Indexing completed for @count items.', array('@datasource' => $datasource->name, '@count' => count($ids))), 'success');
}
@@ -523,9 +597,13 @@ class SearchlightBackendSolr extends SearchlightBackend {
}
// Deletion.
- $result = db_query("SELECT * FROM {searchlight_search} WHERE status = -1 AND type = '%s'", $datasource->base_table);
+ $result = db_select('searchlight_search', 's')
+ ->fields('s')
+ ->condition('status', -1)
+ ->condition('type', $datasource->base_table)
+ ->execute();
$delete = array();
- while ($row = db_fetch_object($result)) {
+ foreach ($result as $row) {
$delete[] = $row->id;
}
if (!empty($delete)) {
@@ -536,11 +614,14 @@ class SearchlightBackendSolr extends SearchlightBackend {
$solr->commit();
// Once updates are complete, remove the Drupal-side records.
- db_query("DELETE FROM {searchlight_search} WHERE status = -1 AND type = '%s'", $datasource->base_table);
+ db_delete('searchlight_search')
+ ->condition('status', -1)
+ ->condition('type', $datasource->base_table)
+ ->execute();
drush_log(dt('@datasource: Deletion completed for @count items.', array('@datasource' => $datasource->name, '@count' => count($delete))), 'success');
}
- variable_set('searchlight_solr_last', time());
+ variable_set('searchlight_solr_last', REQUEST_TIME);
}
}
@@ -549,23 +630,23 @@ class SearchlightBackendSolr extends SearchlightBackend {
* Write the Solr configuration files.
*/
function drushConf() {
- $file_path = conf_path() .'/solr';
- if (file_check_directory($file_path, TRUE)) {
+ $file_path = conf_path() . '/solr';
+ if (file_prepare_directory($file_path, TRUE)) {
// Collect configuration arrays for each datasource.
$cores = array();
foreach (searchlight_get_datasource() as $datasource) {
$datasource->init();
$cores[] = $datasource->id;
- $core_path = $file_path .'/'. $datasource->id;
- if (!file_check_directory($core_path, TRUE)) {
+ $core_path = $file_path . '/' . $datasource->id;
+ if (!file_prepare_directory($core_path, TRUE)) {
return drush_log("/{$core_path} could not be written to.", 'error');
}
$core_path .= '/conf';
- if (file_check_directory($core_path, TRUE)) {
+ if (file_prepare_directory($core_path, TRUE)) {
// Generate configuration file from datasources.
$schema = $this->solrDatasourceConf($datasource);
$files = array(
- 'schema.xml' => theme('searchlight_solr_schema', $schema),
+ 'schema.xml' => theme('searchlight_solr_schema', array('datasource' => $schema)),
'solrconfig.xml' => theme('searchlight_solr_config'),
);
$this->solrWriteFiles($core_path, $files);
@@ -575,7 +656,7 @@ class SearchlightBackendSolr extends SearchlightBackend {
}
}
// Generate top level config.
- $files = array('solr.xml' => theme('searchlight_solr_cores', $cores));
+ $files = array('solr.xml' => theme('searchlight_solr_cores', array('cores' => $cores)));
$this->solrWriteFiles($file_path, $files);
}
else {
@@ -604,9 +685,9 @@ class SearchlightBackendSolr extends SearchlightBackend {
* Assemble the query string.
*/
function solrPrepareQuery(&$client, $datasource, $query) {
- $query = empty($query) ? '[* TO *]' : '"'. $query .'"'; // Is this really right?
+ $query = empty($query) ? '[* TO *]' : '"' . $query . '"'; // Is this really right?
if (isset($client->searchlightFilters)) {
- $query .= ' '. implode(' ', $client->searchlightFilters);
+ $query .= ' ' . implode(' ', $client->searchlightFilters);
}
return $query;
}
@@ -643,10 +724,14 @@ class SearchlightBackendSolr extends SearchlightBackend {
case 'int':
$conf['schema'][$f]['type'] = 'integer';
break;
+ case 'float':
+ $conf['schema'][$f]['type'] = 'sfloat';
+ break;
case 'text':
$conf['schema'][$f]['type'] = 'string';
break;
case 'timestamp':
+ case 'date':
$conf['schema'][$f]['type'] = 'date';
}
@@ -662,15 +747,15 @@ class SearchlightBackendSolr extends SearchlightBackend {
* Write config to the filesystem
*/
function solrWriteFiles($path, $files) {
- foreach($files as $name => $contents) {
+ foreach ($files as $name => $contents) {
if ($contents) {
$existing = '';
if (file_exists("{$path}/{$name}")) {
$existing = file_get_contents("{$path}/{$name}");
}
if ($contents !== $existing) {
- file_put_contents("{$path}/{$name}", $contents);
- drush_log("{$path}/{$name} was written successfully.", 'success');
+ file_put_contents("{$path}/{$name}", $contents);
+ drush_log("{$path}/{$name} was written successfully.", 'success');
}
else {
drush_log("{$path}/{$name} is unchanged.", 'success');
diff --git a/plugins/SearchlightBackendSphinx.inc b/plugins/SearchlightBackendSphinx.inc
index e043635..ac4e234 100644
--- a/plugins/SearchlightBackendSphinx.inc
+++ b/plugins/SearchlightBackendSphinx.inc
@@ -52,12 +52,12 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$form['index'] = array(
'#type' => 'fieldset',
'#title' => t('Index settings'),
- '#description' => t('Advanced configuration options for Sphinx. Use these options to enable CJK or other character set handling for Sphinx. Otherwise, you can leave these blank.')
+ '#description' => t('Advanced configuration options for Sphinx. Use these options to enable CJK or other character set handling for Sphinx. Otherwise, you can leave these blank.'),
);
$form['index']['morphology'] = array(
'#title' => t('Morphology'),
'#description' => t('Morphology processors to apply. See !link', array(
- '!link' => l(t('Sphinx: morphology'), 'http://www.sphinxsearch.com/docs/current.html#conf-morphology')
+ '!link' => l(t('Sphinx: morphology'), 'http://www.sphinxsearch.com/docs/current.html#conf-morphology'),
)),
'#type' => 'textfield',
'#default_value' => $this->settings['index']['morphology'],
@@ -83,7 +83,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
'#title' => t('N-gram characters list'),
'#description' => t('N-gram characters list for basic CJK support. See !link and !charset for CJK support', array(
'!link' => l(t('Sphinx: ngram_chars'), 'http://www.sphinxsearch.com/docs/current.html#ngram_chars'),
- '!charset' => l(t('CJK n-gram characters'), 'http://sphinxsearch.com/wiki/doku.php?id=charset_tables#cjk_ngram_characters')
+ '!charset' => l(t('CJK n-gram characters'), 'http://sphinxsearch.com/wiki/doku.php?id=charset_tables#cjk_ngram_characters'),
)),
'#type' => 'textfield',
'#default_value' => $this->settings['index']['ngram_chars'],
@@ -145,13 +145,13 @@ class SearchlightBackendSphinx extends SearchlightBackend {
* Override of facetBuild().
*/
function facetBuild(&$client, $datasource, $query = '', $facets) {
- $client = drupal_clone($client);
+ $client = clone $client;
foreach ($facets as $facet) {
$field = $datasource->fields[$facet['field']];
$limit = $facet['limit'];
-
switch ($field['datatype']) {
case 'timestamp':
+ case 'date':
$groupby = array('day' => SPH_GROUPBY_DAY, 'month' => SPH_GROUPBY_MONTH, 'year' => SPH_GROUPBY_YEAR);
$granularity = !empty($facet['granularity']) ? $facet['granularity'] : 'month';
$client->SetGroupBy($field['name'], $groupby[$granularity], '@group desc');
@@ -186,6 +186,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$id = $this->sphinxGetOrdinal($datasource, $field['name'], $attr['@groupby']);
break;
case 'timestamp':
+ case 'date':
$id = $this->sphinxGetTimestamp($attr['@groupby'], !empty($facet['granularity']) ? $facet['granularity'] : 'month');
break;
default:
@@ -209,8 +210,10 @@ class SearchlightBackendSphinx extends SearchlightBackend {
variable_del('searchlight_sphinx_last');
$delete = array();
- $result = db_query("SELECT " . $datasource->base_field . " FROM {" . $datasource->base_table . "}");
- while ($row = db_fetch_object($result)) {
+ $result = db_select($datasource->base_table, 'b')
+ ->fields('b', array($datasource->base_field))
+ ->execute();
+ foreach ($result as $row) {
$delete[$row->{$datasource->base_field}] = array(1);
}
@@ -283,6 +286,9 @@ class SearchlightBackendSphinx extends SearchlightBackend {
case 'NOT IN':
$this->sphinxSetFilter($client, $datasource, $field, $args, TRUE);
break;
+ case 'IS NOT NULL':
+ $this->sphinxSetFilter($client, $datasource, $field, array(0), TRUE);
+ break;
}
}
}
@@ -305,10 +311,10 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$sphinx_sorts = array();
foreach ($sorts as $sort) {
if ($sort['field'] === 'searchlight_weight') {
- $sphinx_sorts[] = "@weight {$sort['order']}";
+ $sphinx_sorts[] = "@weight {$sort['direction']}";
}
else {
- $sphinx_sorts[] = "{$sort['field']} {$sort['order']}";
+ $sphinx_sorts[] = "{$sort['field']} {$sort['direction']}";
}
}
$client->setSortMode(SPH_SORT_EXTENDED, implode(', ', $sphinx_sorts));
@@ -347,7 +353,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
}
}
-
+
/**
* Return a directory where the configuration files and indexes are stored.
*
@@ -371,13 +377,13 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$conf_path = $this->drushGetConfigPath();
$conf_file = $this->drushGetConfigFile();
- if (file_check_directory($conf_path, TRUE)) {
+ if (file_prepare_directory($conf_path, TRUE)) {
$files = array();
// rerieve list of possible configuration file matches.
$files[] = $conf_path . '/sphinx.conf';
- $matches = drush_scan_directory($conf_path . '/index.d/', '/^.*\.conf$/', array('.', '..') , 0, false, 'name');
+ $matches = drush_scan_directory($conf_path . '/index.d/', '/^.*\.conf$/', array('.', '..'), 0, false, 'name');
foreach ($matches as $name => $file) {
$files[] = $file->filename;
@@ -393,7 +399,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
}
}
- // load the previous file
+ // load the previous file
$old_config = (file_exists($conf_file)) ? file_get_contents($conf_file) : '';
if ($old_config != $string) {
@@ -414,7 +420,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$file_path = $this->drushGetConfigPath() . '/log';
$lock_file = "{$file_path}/searchd.lock";
- if (file_check_directory($file_path, TRUE)) {
+ if (file_prepare_directory($file_path, TRUE)) {
$lock = file_exists($lock_file) ? file_get_contents($lock_file) : 0;
if ((int) $lock == 1) {
@@ -422,7 +428,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
}
file_put_contents($lock_file, '1');
- if (file_check_directory($file_path, TRUE)) {
+ if (file_prepare_directory($file_path, TRUE)) {
$pid_file = "{$file_path}/searchd.pid";
$pid = file_exists($pid_file) ? file_get_contents($pid_file) : '';
@@ -450,9 +456,9 @@ class SearchlightBackendSphinx extends SearchlightBackend {
// Create the sphinx directory if it doesn't exist.
$changed = $this->drushGenerateMergedConfig();
$file_path = $this->drushGetConfigPath() . '/indexes';
- if (file_check_directory($file_path, TRUE)) {
+ if (file_prepare_directory($file_path, TRUE)) {
// Determine if we should update deltas only.
- $delta = $this->settings['delta_ttl'] && (variable_get('searchlight_sphinx_last', 0) + $this->settings['delta_ttl']) > time();
+ $delta = $this->settings['delta_ttl'] && (variable_get('searchlight_sphinx_last', 0) + $this->settings['delta_ttl']) > REQUEST_TIME;
// Build list of this site's indexes.
$indexes = array();
@@ -473,8 +479,12 @@ class SearchlightBackendSphinx extends SearchlightBackend {
// Note that we must update both the main and delta indices.
foreach (searchlight_get_datasource() as $datasource) {
$delete = array();
- $result = db_query("SELECT * FROM {searchlight_search} WHERE status = -1 AND type = '%s'", $datasource->base_table);
- while ($row = db_fetch_object($result)) {
+ $result = db_select('searchlight_search', 's')
+ ->fields('s')
+ ->condition('status', -1)
+ ->condition('type', $datasource->base_table)
+ ->execute();
+ foreach ($result as $row) {
$delete[$row->id] = array(1);
}
if (!empty($update)) {
@@ -483,14 +493,20 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$client->UpdateAttributes($indexes_delta[$datasource->id], array('searchlight_deleted'), $delete);
// Once updates are complete, remove the Drupal-side records.
- db_query("DELETE FROM {searchlight_search} WHERE status = -1 AND type = '%s'", $datasource->base_table);
+ db_delete('searchlight_search')
+ ->condition('status', -1)
+ ->condition('type', $datasource->base_table)
+ ->execute();
}
}
// Clear caches so that sphinx id -> facet name mapping is updated.
cache_clear_all('searchlight', 'cache', TRUE);
- db_query('UPDATE {searchlight_search} SET status = 1 WHERE status = 0');
- variable_set('searchlight_sphinx_last', time());
+ db_update('searchlight_search')
+ ->fields(array('status' => 1))
+ ->condition('status', 0)
+ ->execute();
+ variable_set('searchlight_sphinx_last', REQUEST_TIME);
drush_log('Indexing complete.', 'success');
if ($changed === TRUE) {
return $this->drushSearchd();
@@ -527,28 +543,28 @@ class SearchlightBackendSphinx extends SearchlightBackend {
// variable_set('searchlight_config_changed', FALSE);
// }
- if (file_check_directory($file_path, TRUE) && drush_get_option('sl-sphinx-base-conf', TRUE)) {
+ if (file_prepare_directory($file_path, TRUE) && drush_get_option('sl-sphinx-base-conf', TRUE)) {
$this->drushBaseConf();
}
- if (file_check_directory($conf_path, TRUE)) {
+ if (file_prepare_directory($conf_path, TRUE)) {
// Collect configuration arrays for each datasource.
- foreach (searchlight_get_datasource() as $datasource) {
- $source = $this->sphinxDatasourceConf($datasource);
-
- // Add delta index.
+ foreach (searchlight_datasource_load(NULL, TRUE) as $datasource) {
+ $conf = array(FALSE);
if (!empty($this->settings['delta_ttl'])) {
- $source = $this->sphinxDatasourceConf($source, TRUE);
+ $conf[] = TRUE;
}
-
- $conf_file = "{$conf_path}/{$source['conf']['id']}.conf";
-
- // Generate configuration file from datasource.
- $sphinx_conf = theme('searchlight_sphinx_index_conf', $source);
- $existing = file_exists($conf_file) ? file_get_contents($conf_file) : '';
- if ($sphinx_conf !== $existing) {
- file_put_contents($conf_file, $sphinx_conf);
- drush_log("{$conf_file} was written successfully.", 'success');
+ foreach ($conf as $delta_ttl) {
+ $source = $this->sphinxDatasourceConf($datasource, $delta_ttl);
+ $conf_file = "{$conf_path}/{$source['conf']['id']}.conf";
+
+ // Generate configuration file from datasource.
+ $sphinx_conf = theme('searchlight_sphinx_index_conf', array('datasource' => $source));
+ $existing = file_exists($conf_file) ? file_get_contents($conf_file) : '';
+ if ($sphinx_conf !== $existing) {
+ file_put_contents($conf_file, $sphinx_conf);
+ drush_log("{$conf_file} was written successfully.", 'success');
+ }
}
}
return drush_log("Sphinx configuration files were written", 'success');
@@ -562,8 +578,8 @@ class SearchlightBackendSphinx extends SearchlightBackend {
function drushBaseConf() {
$file_path = $this->drushGetConfigPath();
$conf_file = "{$file_path}/sphinx.conf";
- if (file_check_directory($file_path, TRUE)) {
- $sphinx_conf = theme('searchlight_sphinx_conf', $this->sphinxSearchdConf());
+ if (file_prepare_directory($file_path, TRUE)) {
+ $sphinx_conf = theme('searchlight_sphinx_conf', array('searchd' => $this->sphinxSearchdConf()));
if ($sphinx_conf) {
$existing = file_exists($conf_file) ? file_get_contents($conf_file) : '';
if ($sphinx_conf === $existing) {
@@ -618,7 +634,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
*/
function sphinxSetFilter(&$client, $datasource, $attribute, $values, $exclude = FALSE) {
$ordinals = array();
- foreach ($values as $arg) {
+ foreach ((array) $values as $arg) {
$arg = trim($arg);
if (is_numeric($arg)) {
$ordinals[] = $arg;
@@ -640,22 +656,24 @@ class SearchlightBackendSphinx extends SearchlightBackend {
$datasource->init();
$datasource_id = $delta ? $datasource->id . '_delta' : $datasource->id;
- $conf = array('conf' => array(), 'index' => array());
-
- // Retrieve db info.
- global $db_url, $db_type;
- $url = is_array($db_url) ? $db_url['default'] : $db_url;
- $url = parse_url($url);
+ $conf = array(
+ 'conf' => array(),
+ 'index' => array(),
+ );
// Configuration options.
$conf['conf']['id'] = $datasource_id;
- $conf['conf']['type'] = $db_type === 'mysqli' ? 'mysql' : $db_type;
- $conf['conf']['sql_user'] = urldecode($url['user']);
- $conf['conf']['sql_pass'] = isset($url['pass']) ? urldecode($url['pass']) : '';
- $conf['conf']['sql_host'] = urldecode($url['host']);
- $conf['conf']['sql_db'] = trim(urldecode($url['path']), '/');
- $conf['conf']['sql_port'] = isset($url['port']) ? urldecode($url['port']) : '3306';
+ // Use mysql stored database credentials.
+ if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) {
+ $conf['conf']['type'] = $creds['driver'] === 'mysqli' ? 'mysql' : $creds['driver'];
+ $conf['conf']['sql_user'] = $creds['user'];
+ $conf['conf']['sql_pass'] = $creds['pass'];
+ $conf['conf']['sql_host'] = $creds['host'];
+ $conf['conf']['sql_db'] = $creds['name'];
+ $conf['conf']['sql_port'] = isset($creds['port']) ? $creds['port'] : '3306';
+
+ }
// Check for optional sql_sock option.
$sock = trim($this->settings['sql_sock']);
if (!empty($sock)) {
@@ -693,23 +711,24 @@ class SearchlightBackendSphinx extends SearchlightBackend {
// Force utf8 when indexing.
$conf['conf']['sql_query_pre'] = "SET NAMES utf8";
- $sql_query = drupal_clone($view->query);
- $sql_query->add_where(0, "{$view->base_table}.{$view->base_field}" .' BETWEEN $start AND $end');
+ $sql_query = clone $view->query;
+
+ $sql_query->add_where(0, "{$view->base_table}.{$view->base_field}" . ' BETWEEN $start AND $end ', array(), 'formula');
$sql_query->add_field(NULL, '0', 'searchlight_deleted');
if ($delta) {
$this->queryFresh($sql_query);
}
- $conf['conf']['sql_query'] = $this->sphinxWriteSQL($sql_query->query(), $sql_query->get_where_args());
+ $conf['conf']['sql_query'] = $this->sphinxWriteSQL($sql_query);
$conf['conf']['sql_query'] = str_replace("\n", " \\\n", trim($conf['conf']['sql_query']));
// Build the info query.
- $sql_query_info = drupal_clone($view->query);
- $sql_query_info->add_where(0, "{$view->base_table}.{$view->base_field}" .' = $id');
+ $sql_query_info = clone $view->query;
+ $sql_query_info->add_where(0, "{$view->base_table}.{$view->base_field}" . ' = $id', array(), 'formula');
$sql_query_info->add_field(NULL, '0', 'searchlight_deleted');
if ($delta) {
$this->queryFresh($sql_query_info);
}
- $conf['conf']['sql_query_info'] = $this->sphinxWriteSQL($sql_query_info->query(), $sql_query_info->get_where_args());
+ $conf['conf']['sql_query_info'] = $this->sphinxWriteSQL($sql_query);
$conf['conf']['sql_query_info'] = str_replace("\n", " \\\n", trim($conf['conf']['sql_query_info']));
// Assume serial ids on the base table and step by 1000.
@@ -721,9 +740,9 @@ class SearchlightBackendSphinx extends SearchlightBackend {
// Merge in attributes.
$sql_attr = array();
$sphinx_type = array(
- 'text' => 'sql_attr_str2ordinal',
- 'int' => 'sql_attr_uint',
- 'float' => 'sql_attr_float',
+ 'text' => 'sql_attr_str2ordinal',
+ 'int' => 'sql_attr_uint',
+ 'float' => 'sql_attr_float',
'timestamp' => 'sql_attr_timestamp',
);
@@ -739,7 +758,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
}
// Generate multivalue queries.
else if ($field['usage'] === 'multivalue' && $mva_view = searchlight_build_view($field['view'])) {
- $query = drupal_clone($mva_view->query);
+ $query = clone $mva_view->query;
// Remove any fields that are not the id field or attribute field.
foreach ($query->fields as $alias => $query_field) {
if ($query_field['field'] === $mva_view->base_field && $query_field['table'] === $mva_view->base_table) {
@@ -753,7 +772,7 @@ class SearchlightBackendSphinx extends SearchlightBackend {
if ($delta) {
$this->queryFresh($query);
}
- $mva_query = $this->sphinxWriteSQL($query->query(), $query->get_where_args());
+ $mva_query = $this->sphinxWriteSQL($query);
$mva_query = str_replace("\n", " \\\n", trim($mva_query));
$sql_attr[] = "sql_attr_multi = uint {$field['name']} from query; {$mva_query}";
}
@@ -767,8 +786,8 @@ class SearchlightBackendSphinx extends SearchlightBackend {
}
/**
- * Get the Sphinx searchd settings.
- */
+ * Get the Sphinx searchd settings.
+ */
function sphinxSearchdConf() {
$searchd = array();
$searchd['log'] = $this->drushGetConfigPath() . '/log/searchd.log';
@@ -787,11 +806,75 @@ class SearchlightBackendSphinx extends SearchlightBackend {
/**
* Write a SQL query with fully prefixed tables and replaced arguments.
*/
- function sphinxWriteSQL($query, $args) {
- _db_query_callback($args, TRUE);
- $query = db_prefix_tables($query);
- $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
- return $query;
+ function sphinxWriteSQL($query) {
+ $connection = Database::getConnection('default');
+ $sql = $connection->prepareQuery( (string) $query->query())->queryString;
+
+ // Monstrous hack. Because PDO only allows access to prepared queries and
+ // not the full query with placeholders replaced with actual values we
+ // need to "parse" and replace the placeholders on our own.
+ //
+ // Assumptions:
+ // - Argument placeholder tokens are named as :db_condition_placeholder_[x]
+ // and Views where condition are in the same order and as the
+ // placeholders.
+ $replace = array();
+ // Process SQL args in Views JOINs.
+ $i = 0;
+ foreach ($query->table_queue as $t) {
+ if (!empty($t['join']->extra) && is_array($t['join']->extra)) {
+ foreach ($t['join']->extra as $extra) {
+ if (!is_null($extra['value'])) {
+ $replace[":views_join_condition_{$i}"] = $this->sphinxPrepareSQLArg($extra['value']);
+ $i++;
+ }
+ }
+ }
+ }
+ // Process SQL args in Views WHEREs
+ $i = 0;
+ foreach ($query->where as $w) {
+ if (isset($w['conditions'])) {
+ foreach ($w['conditions'] as $condition) {
+ if (!empty($condition['value'])) {
+ $args = array();
+ foreach ($condition['value'] as $arg) {
+ $args[] = $this->sphinxPrepareSQLArg($arg);
+ }
+ $replace[":db_condition_placeholder_{$i}"] = implode(',', $args);
+ $i++;
+ }
+ }
+ }
+ }
+ $sql = strtr($sql, $replace);
+ return $sql;
+ }
+
+ /**
+ * Prepare an SQL argument for use in an SQL query.
+ * Do *NOT* use this unless you absolutely know how and why you might need
+ * it. It is only used in the Searchlight sphinx backend to generate select
+ * queries for use in the sphinx.conf file.
+ */
+ function sphinxPrepareSQLArg($arg) {
+ $connection = Database::getConnection('default');
+ switch ($connection->databaseType()) {
+ case 'mysql':
+ case 'pgsql':
+ // @TODO better handling of types. Currently numeric strings and actual
+ // number fields can be confused.
+ if (is_numeric($arg)) {
+ }
+ else {
+ // addslashes() is used here because mysql_real_escape_string()
+ // requires a mysql_connect() connection which is not used by PDO.
+ // @TODO: fix this stopgap with a real solution..
+ $arg = addslashes($arg);
+ $arg = "'{$arg}'";
+ }
+ return $arg;
+ }
}
/**
@@ -856,14 +939,13 @@ class SearchlightBackendSphinx extends SearchlightBackend {
if (!empty($result['matches']) && count($result['matches']) < 1000) {
// Dispatch a Views query to retrieve the corresponding string.
- $ids = implode(',', array_keys($result['matches']));
+ $ids = array_keys($result['matches']);
$view = $datasource->view->copy();
$view->build();
$view->set_items_per_page(0);
$view->query->where = array();
- $view->query->add_where(0, "{$view->base_table}.{$view->base_field} IN ({$ids})");
+ $view->query->add_where(0, "{$view->base_table}.{$view->base_field}", $ids, 'IN');
$view->build_info['query'] = $view->query->query();
- $view->build_info['query_args'] = $view->query->get_where_args();
$view->execute();
foreach ($view->result as $row) {
$id = $row->{$view->base_field};
diff --git a/plugins/SearchlightFacet.inc b/plugins/SearchlightFacet.inc
index af32d98..f1f6011 100644
--- a/plugins/SearchlightFacet.inc
+++ b/plugins/SearchlightFacet.inc
@@ -36,7 +36,16 @@ class SearchlightFacet {
*/
function query(&$query) {
// Filter the query if there is an active facet value.
+ // Remove any existing filters for this same value in order to cleanly
+ // "replace" the filter condition. Note that this requires the Searchlight
+ // facets filter handler to be placed *after* any other Views filters that
+ // should be replaced when a facet is active.
if (isset($this->value)) {
+ foreach ($query->search_filter as $key => $filter) {
+ if ($filter['field'] === $this->name) {
+ unset($query->search_filter[$key]);
+ }
+ }
$query->search_filter[] = array(
'field' => $this->name,
'operator' => '=',
@@ -93,7 +102,9 @@ class SearchlightFacet {
break;
}
if (!empty($items) && $this->viewInit($query)) {
- return $this->viewRenderItems($items);
+ $items = $this->viewRenderItems($items);
+ $this->sort($items);
+ return $items;
}
return array();
}
@@ -114,12 +125,12 @@ class SearchlightFacet {
$path = $this->environment->getURLPath();
$options = $this->environment->getURLOptions('remove', $this->name, $item['id']);
$item['link'] = l(t('remove'), $path, $options);
- return theme('searchlight_facet_active', $this->field, $item);
+ return theme('searchlight_facet_active', array('field' => $this->field, 'item' => $item));
case 'facets':
$path = $this->environment->getURLPath();
$options = $this->environment->getURLOptions('add', $this->name, $item['id']);
$item['link'] = l($item['title'], $path, $options);
- return theme('searchlight_facet_link', $this->field, $item);
+ return theme('searchlight_facet_link', array('field' => $this->field, 'item' => $item));
}
}
@@ -140,8 +151,8 @@ class SearchlightFacet {
else {
$this->view = $query->datasource->view->copy();
$this->view->build();
- foreach ($this->view->field as $field_handler) {
- if ($field_handler->field_alias === $this->name) {
+ foreach ($this->view->field as $name => $field_handler) {
+ if (isset($field_handler->aliases[$this->name]) || $name == $this->name) {
$this->handler = $field_handler;
}
}
@@ -155,25 +166,18 @@ class SearchlightFacet {
*/
function viewRenderItems($items) {
$rows = array();
+ $options = array();
// Multivalue fields must build a new Views query in order to
// retrieve any secondary label field values.
if ($this->field['usage'] === 'multivalue') {
$ids = array_keys($items);
- // Views 2.x
- if (views_api_version() == '2.0') {
- views_include('query');
- $query = new views_query($this->field['table'], $this->field['field']);
- }
- // Views 3.x
- else {
- $query = views_get_plugin('query', 'views_query');
- $query->init($this->field['table'], $this->field['field']);
- }
+ $query = views_get_plugin('query', 'views_query');
+ $query->init($this->field['table'], $this->field['field'], $options);
// Add WHERE condition on item ids.
- $query->add_where(0, "{$this->field['table']}.{$this->field['field']} IN (". db_placeholders($ids, 'int') .")", $ids);
+ $query->add_where(0, "{$this->field['table']}.{$this->field['field']}", $ids, 'IN');
// Add base field.
$field_alias = $query->add_field($this->field['table'], $this->field['field']);
@@ -189,15 +193,11 @@ class SearchlightFacet {
$rows[$row->{$this->name}] = $row;
}
}
- // For regular fields attempt to spoof rows with the appropriate field
- // values for rendering by the field handler.
- else {
- $rows = array();
- foreach ($items as $item) {
- $row = new stdClass();
- $row->{$this->name} = $item['id'];
- $rows[$item['id']] = $row;
- }
+
+ foreach ($items as $item) {
+ $row = new stdClass();
+ $row->{$this->handler->field_alias} = $item['id'];
+ $rows[$item['id']] = $row;
}
// Render item titles.
@@ -215,6 +215,7 @@ class SearchlightFacet {
return array(
'label' => '',
'items' => 5,
+ 'sort' => 'count'
);
}
@@ -234,6 +235,12 @@ class SearchlightFacet {
'#default_value' => $this->options['items'],
'#options' => drupal_map_assoc(range(1, 20)) + array(0 => t('Show all')),
);
+ $form['sort'] = array(
+ '#title' => t('Sort by'),
+ '#type' => 'select',
+ '#default_value' => $this->options['sort'],
+ '#options' => array('count' => t('Number of items'), 'name' => t('Alphabetical')),
+ );
}
/**
@@ -241,4 +248,34 @@ class SearchlightFacet {
*/
function extendedForm(&$form, $form_state) {
}
+
+ /**
+ * Sort built facet items.
+ */
+ function sort(&$items) {
+ switch ($this->options['sort']) {
+ case 'count':
+ uasort($items, 'SearchlightFacet::sortCount');
+ break;
+ case 'name':
+ uasort($items, 'SearchlightFacet::sortName');
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * uasort callback, sort by count.
+ */
+ function sortCount($a, $b) {
+ return $a['count'] < $b['count'];
+ }
+
+ /**
+ * uasort callback, sort by name.
+ */
+ function sortName($a, $b) {
+ return $a['title'] > $b['title'];
+ }
}
diff --git a/plugins/SearchlightFacetDatatypeTimestamp.inc b/plugins/SearchlightFacetDatatypeTimestamp.inc
index e6ef57a..7b49261 100644
--- a/plugins/SearchlightFacetDatatypeTimestamp.inc
+++ b/plugins/SearchlightFacetDatatypeTimestamp.inc
@@ -9,6 +9,12 @@ class SearchlightFacetDatatypeTimestamp extends SearchlightFacet {
*/
function query(&$query) {
if (isset($this->value)) {
+ foreach ($query->search_filter as $key => $filter) {
+ if ($filter['field'] === $this->name) {
+ unset($query->search_filter[$key]);
+ }
+ }
+
$range = $query->backend->dateRange($this->value, $this->options['granularity']);
$query->search_filter[] = array(
@@ -51,7 +57,7 @@ class SearchlightFacetDatatypeTimestamp extends SearchlightFacet {
foreach ($items as $k => $item) {
$format = $this->options['date_format'];
$timestamp = is_numeric($item['id']) ? $item['id'] : strtotime($item['id']);
- $items[$k]['title'] = format_date($timestamp, 'custom', $format, 0);
+ $items[$k]['title'] = format_date($timestamp, 'custom', $format, 'UTC');
}
return $items;
}
@@ -65,9 +71,19 @@ class SearchlightFacetDatatypeTimestamp extends SearchlightFacet {
$options = parent::optionsDefault();
$options['granularity'] = 'month';
$options['date_format'] = 'F, Y';
+ $options['sort'] = 'date';
return $options;
}
+ /**
+ * Provide an options form to be exposed in the Environment editor.
+ */
+ function optionsForm(&$form, $form_state) {
+ parent::optionsForm($form, $form_state);
+ $form['sort']['#type'] = 'hidden';
+ $form['sort']['#value'] = 'date';
+ }
+
/**
* Provide an options form to be exposed in the Environment editor.
*/
diff --git a/plugins/SearchlightFacetSearchQuery.inc b/plugins/SearchlightFacetSearchQuery.inc
index e3807d8..5a0d8d8 100644
--- a/plugins/SearchlightFacetSearchQuery.inc
+++ b/plugins/SearchlightFacetSearchQuery.inc
@@ -44,7 +44,7 @@ class SearchlightFacetSearchQuery extends SearchlightFacet {
$path = $this->environment->getURLPath();
$options = $this->environment->getURLOptions('active', $this->name, $item['id']);
$item['link'] = l(t('remove'), $path, $options);
- return theme('searchlight_facet_active', $this->field, $item);
+ return theme('searchlight_facet_active', array('field' => $this->field, 'item' => $item));
}
}
@@ -77,9 +77,9 @@ class SearchlightFacetSearchQuery extends SearchlightFacet {
*/
function optionsForm(&$form, $form_state) {
parent::optionsForm($form, $form_state);
- $form['items'] = array(
- '#type' => 'value',
- '#value' => 1,
- );
+ $form['items']['#type'] = 'hidden';
+ $form['items']['#value'] = true;
+ $form['sort']['#type'] = 'hidden';
+ $form['sort']['#value'] = 'count';
}
}
diff --git a/plugins/SearchlightFacetTerm.inc b/plugins/SearchlightFacetTerm.inc
index fdb6344..7245d74 100644
--- a/plugins/SearchlightFacetTerm.inc
+++ b/plugins/SearchlightFacetTerm.inc
@@ -5,220 +5,18 @@
*/
class SearchlightFacetTerm extends SearchlightFacet {
/**
- * Override of construct().
- * Do additional setup and provide information about the current active facet
- * term, vocab and hierarchy.
- */
- function construct($environment, $field, $value, $options) {
- parent::construct($environment, $field, $value, $options);
-
- $this->term = taxonomy_get_term($this->value);
-
- // Attempt to parse the vocab from the field name.
- $identifier = trim(array_pop(explode('term_data_tid_', $this->name)));
- if (is_numeric($identifier)) {
- $vid = $identifier;
- }
- else {
- $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = '%s' LIMIT 1", $identifier));
- }
- $this->vocab = taxonomy_vocabulary_load($vid);
- if (!empty($this->vocab->hierarchy)) {
- $this->tree = array();
- foreach (taxonomy_get_tree($this->vocab->vid) as $term) {
- $this->tree[$term->tid] = $term;
- }
- }
-
- $this->children = array();
- $this->parents = array();
- if (!empty($this->value) && $this->term) {
- foreach (taxonomy_get_children($this->term->tid) as $term) {
- $this->children[] = $term->tid;
- }
- foreach (taxonomy_get_parents($this->term->tid) as $term) {
- $this->parents[] = $term->tid;
- }
- }
- }
-
- /**
- * Override of query().
- * Handle hierarchical taxonomies.
- */
- function query(&$query) {
- // Filter the query if there is an active facet value.
- if (isset($this->value)) {
- $query->search_filter[] = array(
- 'field' => $this->name,
- 'operator' => 'IN',
- 'args' => array_merge(array($this->value), $this->children),
- );
- }
-
- // Add this facet to be built by the backend.
- // An extremely high limit is used so that we can process returned terms
- // properly Drupalside.
- // @TODO: This is probably a terrible idea.
- if (!empty($this->vocab->hierarchy)) {
- $limit = 1000;
- }
- else {
- $limit = isset($this->options['items']) ? $this->options['items'] : 5;
- }
- $query->add_search_facet($this->name, $limit);
- }
-
- /**
- * Override of theme().
- */
- function theme($item, $delta) {
- if ($this->vocab->hierarchy && $delta === 'active') {
- if (isset($this->tree[$this->value], $this->tree[$item['id']])) {
- $term_item = $this->tree[$item['id']];
- $term_current = $this->tree[$this->value];
-
- // Add a class specifying the item's depth.
- $item['class'] = "depth-{$term_item->depth}";
-
- // Compare this item's depth vs. current value depth.
- // If the item is deeper than the current depth it should be an option
- // for further faceting drill-down.
- if ($term_item->depth > $term_current->depth) {
- return parent::theme($item, 'facets');
- }
- // Otherwise, broaden the search by either linking to a parent term
- // facet or (root terms) removing the term facets alltogether.
- else {
- if ($parent = reset($term_item->parents)) {
- $path = $this->environment->getURLPath();
- $options = $this->environment->getURLOptions('add', $this->name, $parent);
- $item['link'] = l(t('remove'), $path, $options);
- }
- else {
- $path = $this->environment->getURLPath();
- $options = $this->environment->getURLOptions('remove', $this->name, $term_item->tid);
- $item['link'] = l(t('remove'), $path, $options);
- }
- return theme('searchlight_facet_active', $this->field, $item);
- }
+ * Override viewRenderItems to use a simple db_select().
+ */
+ function viewRenderItems($items) {
+ $result = db_select('taxonomy_term_data')
+ ->fields('taxonomy_term_data', array('name', 'tid'))
+ ->condition('tid', array_keys($items))
+ ->execute();
+ foreach ($result as $term) {
+ if (isset($items[$term->tid])) {
+ $items[$term->tid]['title'] = $term->name;
}
- return '';
}
- return parent::theme($item, $delta);
- }
-
-
- /**
- * Override of render().
- * Most of the complexity here is for smart handling of
- * hierarchical taxonomies.
- */
- function render($query, $delta) {
- if ($this->viewInit($query)) {
- switch ($delta) {
- case 'active':
- if (isset($this->value)) {
- $items = array();
- // Add terms from current value all the way to root term.
- $trail = $this->parents;
- $trail[] = $this->value;
- foreach ($trail as $num => $id) {
- $items[] = array(
- 'id' => $id,
- 'title' => $this->getName($id),
- );
- }
- // Add direct children terms and get their counts.
- if ($this->vocab->hierarchy && $this->term) {
- $raw = $query->get_search_facet($this->name);
- $terms = taxonomy_get_children($this->term->tid, $this->vocab->vid);
- foreach ($terms as $term) {
- $count = $this->getDeepCount($term->tid, $raw);
- if ($count) {
- $items[] = array('id' => $term->tid, 'title' => $term->name, 'count' => $count);
- }
- }
- }
- return $items;
- }
- break;
- case 'facets':
- $items = array();
- // If hierarchical, only show root terms and calculate their "deep"
- // count values.
- if ($this->vocab->hierarchy && empty($this->term)) {
- $raw = $query->get_search_facet($this->name);
- $terms = taxonomy_get_children(0, $this->vocab->vid);
- foreach ($terms as $term) {
- $count = $this->getDeepCount($term->tid, $raw);
- if ($count) {
- $items[] = array('id' => $term->tid, 'title' => $term->name, 'count' => $count, /*'link' => l($term->name, $_GET['q'], $options)*/);
- }
- }
- }
- // If non-hierarchical, simple flat list of terms.
- else if (!isset($this->value)) {
- foreach ($query->get_search_facet($this->name) as $item) {
- $item['title'] = $this->getName($item['id']);
- $items[] = $item;
- }
- }
- return $items;
- break;
- }
- }
- return array();
- }
-
- /**
- * Simple renderer for term names.
- */
- function getName($tid) {
- if ($term = taxonomy_get_term($tid)) {
- return $term->name;
- }
- return NULL;
- }
-
- /**
- * Retrieve the full sum count (including all children) for a term.
- * @TODO: This is wrong! If a node is tagged with both the parent term and
- * a child term (or more) it will be counted multiple times. Fix this.
- */
- function getDeepCount($tid, $raw) {
- $count = isset($raw[$tid]['count']) ? $raw[$tid]['count'] : 0;
- if ($this->options['count_method'] === 'deep') {
- $children = taxonomy_get_children($tid);
- $children = array_intersect_key($raw, $children);
- if (!empty($children)) {
- foreach (array_keys($children) as $tid) {
- $count = $count + $this->getDeepCount($tid, $raw);
- }
- }
- }
- return $count;
- }
-
- /**
- * Provide default values for options.
- */
- function optionsDefault() {
- $options = parent::optionsDefault();
- $options['deep_count'] = 'yes';
- return $options;
- }
-
- /**
- * Provide an options form to be exposed in the Environment editor.
- */
- function extendedForm(&$form, $form_state) {
- parent::extendedForm($form, $form_state);
- $form['count_method'] = array(
- '#title' => t('Count mode'),
- '#type' => 'select',
- '#options' => array('shallow' => t('Shallow'), 'deep' => t('Deep')),
- '#default_value' => $this->options['count_method'],
- );
+ return $items;
}
}
diff --git a/searchlight.admin.inc b/searchlight.admin.inc
index f916fec..dc1ca13 100644
--- a/searchlight.admin.inc
+++ b/searchlight.admin.inc
@@ -3,7 +3,7 @@
/**
* Datasource management form.
*/
-function searchlight_admin_environment($form_state) {
+function searchlight_admin_environment($form, $form_state) {
$form = array(
'#theme' => 'searchlight_admin_list',
'#objects' => array(searchlight_environment_load(NULL, TRUE)),
@@ -40,7 +40,7 @@ function searchlight_admin_environment_view_displays() {
$usable = array();
foreach ($views as $view) {
foreach ($view->display as $display) {
- if ($display->display_plugin === 'page') {
+ if ($display->display_plugin === 'page' || $display->display_plugin === 'panel_pane') {
$view->set_display($display->id);
$filters = $view->display_handler->get_option('filters');
if (!empty($filters)) {
@@ -65,7 +65,7 @@ function searchlight_admin_environment_validate_name($element, &$form_state) {
form_set_error('name', t('The environment name can only consist of lowercase letters, dashes, underscores, and numbers.'));
}
// Check for name collision
- else if ($exists = searchlight_environment_load($element['#value'], TRUE)) {
+ elseif ($exists = searchlight_environment_load($element['#value'], TRUE)) {
form_set_error('name', t('A environment with this name already exists. Please choose another name or delete the existing environment before creating a new one.'));
}
}
@@ -76,7 +76,7 @@ function searchlight_admin_environment_validate_name($element, &$form_state) {
function searchlight_admin_environment_new(&$form, &$form_state) {
$environment = searchlight_environment_new($form_state['values']['name'], $form_state['values']['view_display']);
if (searchlight_environment_save($environment)) {
- drupal_set_message(t('Saved environment %name.', array('%name' => $environment->name)));
+ drupal_set_message(t('Saved environment %name.', array('%name' => $environment->name)));
}
else {
drupal_set_message(t('Could not save environment %name.', array('%name' => $environment->name)), 'error');
@@ -86,19 +86,21 @@ function searchlight_admin_environment_new(&$form, &$form_state) {
/**
* Edit form for environment.
*/
-function searchlight_admin_environment_edit($form_state, $environment) {
- $form = array();
+function searchlight_admin_environment_edit($form, $form_state, $environment) {
$form['#environment'] = $environment;
$form['#environment_name'] = $environment->name;
+ $form['#attached']['js'][drupal_get_path('module', 'searchlight') . '/searchlight.admin.js'] = array('type' => 'file');
+ $form['#attached']['css'][drupal_get_path('module', 'searchlight') . '/searchlight.admin.css'] = array('type' => 'file');
$environment->optionsForm($form, $form_state);
- $form['buttons']['save'] = array(
+ $form['actions']['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
- $form['buttons']['cancel'] = array(
- '#type' => 'markup',
- '#value' => l(t('Cancel'), 'admin/settings/search/environment'),
+ $form['actions']['cancel'] = array(
+ '#type' => 'link',
+ '#title' => t('Cancel'),
+ '#href' => 'admin/config/search/settings/environment',
);
return $form;
}
@@ -115,7 +117,7 @@ function searchlight_admin_environment_edit_submit(&$form, $form_state) {
/**
* Datasource management form.
*/
-function searchlight_admin_datasource($form_state) {
+function searchlight_admin_datasource($form, $form_state) {
views_include('admin');
$base_tables = views_fetch_base_tables();
@@ -171,7 +173,7 @@ function searchlight_admin_datasource($form_state) {
);
$form['buttons']['cancel'] = array(
'#type' => 'markup',
- '#value' => l(t('Cancel'), 'admin/settings/search/datastore'),
+ '#value' => l(t('Cancel'), 'admin/config/search/settings/datastore'),
);
return $form;
}
@@ -186,11 +188,11 @@ function searchlight_admin_datasource_new_validate(&$form, &$form_state) {
form_set_error('name', t('!name field is required.', array('!name' => $form['new']['name']['#title'])));
}
// Check for string identifier sanity
- else if (!preg_match('!^[a-z0-9_-]+$!', $name)) {
+ elseif (!preg_match('!^[a-z0-9_-]+$!', $name)) {
form_set_error('name', t('The datasource name can only consist of lowercase letters, dashes, underscores, and numbers.'));
}
// Check for name collision
- else if ($exists = searchlight_datasource_load($name, TRUE)) {
+ elseif ($exists = searchlight_datasource_load($name, TRUE)) {
form_set_error('name', t('A datasource with this name already exists. Please choose another name or delete the existing datasource before creating a new one.'));
}
}
@@ -201,7 +203,7 @@ function searchlight_admin_datasource_new_validate(&$form, &$form_state) {
function searchlight_admin_datasource_new(&$form, &$form_state) {
$datasource = searchlight_datasource_new($form_state['values']['name'], $form_state['values']['base_table']);
if (searchlight_datasource_save($datasource)) {
- drupal_set_message(t('Created datasource %name.', array('%name' => $datasource->name)));
+ drupal_set_message(t('Created datasource %name.', array('%name' => $datasource->name)));
}
else {
drupal_set_message(t('Could not save datasource %name.', array('%name' => $datasource->name)), 'error');
@@ -214,8 +216,8 @@ function searchlight_admin_datasource_new(&$form, &$form_state) {
function searchlight_admin_datasource_save(&$form, &$form_state) {
foreach ($form_state['values']['active'] as $base_table => $datasource) {
if (!empty($datasource)) {
- $current = variable_get("searchlight_datasource_{$base_table}", "searchlight_{$base_table}");
- variable_set('searchlight_datasource_'. $base_table, $datasource);
+ $current = variable_get("searchlight_datasource_{$base_table}", "search_{$base_table}");
+ variable_set('searchlight_datasource_' . $base_table, $datasource);
drupal_set_message(t('New active datasource settings have been saved.'), 'status', FALSE);
// If active datasource settings have changed a rebuild is necessary.
@@ -234,20 +236,28 @@ function searchlight_admin_datasource_save(&$form, &$form_state) {
/**
* Edit form for datasource.
*/
-function searchlight_admin_datasource_edit($form_state, $datasource) {
- $form = array();
+function searchlight_admin_datasource_edit($form, $form_state, $datasource) {
$form['#datasource'] = $datasource;
$form['#datasource_name'] = $datasource->name;
+ $form['#attached']['js']['misc/tableselect.js'] = array('type' => 'file');
+
$datasource->init();
$datasource->optionsForm($form, $form_state);
- $form['buttons']['save'] = array(
+ $form['actions']['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
+ '#limit_validation_errors' => array(
+ array('options'),
+ array('fields', 'fields'),
+ array('multivalues', 'fields'),
+ array('relations', 'relations'),
+ ),
);
- $form['buttons']['cancel'] = array(
- '#type' => 'markup',
- '#value' => l(t('Cancel'), 'admin/settings/search/datastore'),
+ $form['actions']['cancel'] = array(
+ '#type' => 'link',
+ '#title' => t('Cancel'),
+ '#href' => 'admin/config/search/settings/datastore',
);
return $form;
}
@@ -255,45 +265,60 @@ function searchlight_admin_datasource_edit($form_state, $datasource) {
/**
* Submit handler for searchlight_admin_datasource_edit().
*/
-function searchlight_admin_datasource_edit_submit(&$form, $form_state) {
+function searchlight_admin_datasource_edit_submit($form, &$form_state) {
if (!empty($form['#datasource'])) {
$form['#datasource']->optionsSubmit($form, $form_state);
}
}
/**
- * AHAH callback & processor for datasource editor.
+ * AJAX callback & processor for datasource editor.
*/
-function searchlight_admin_datasource_ahah($clicked_id, $element = 'fields') {
- $form_state = array();
+function searchlight_admin_datasource_ajax($form, $form_state, $clicked_id, $element = 'fields') {
$form_state['clicked_button']['#id'] = $clicked_id;
- $form_state['values'] = $_POST;
- $form = form_get_cache($_POST['form_build_id'], $form_state);
- if ($form) {
- $datasource = searchlight_datasource_load($form['#datasource_name']);
- $datasource->optionsSubmit($form, $form_state);
-
- $form['#datasource'] = $datasource;
- $datasource->optionsForm($form, $form_state);
- form_set_cache($_POST['form_build_id'], $form, $form_state);
-
- // Build and render the new element, then return it in JSON format.
- $form_state = array();
- $form['#post'] = array();
- $form = form_builder($form['form_id']['#value'], $form, $form_state);
- $output = drupal_render($form[$element]);
- drupal_json(array('status' => TRUE, 'data' => $output));
- }
- else {
- drupal_json(array('status' => FALSE, 'data' => ''));
- }
- exit();
+
+ $datasource = searchlight_datasource_load($form['#datasource_name']);
+ $datasource->optionsSubmit($form, $form_state);
+
+ $form['#datasource'] = $datasource;
+ $datasource->optionsForm($form, $form_state);
+ form_set_cache($_POST['form_build_id'], $form, $form_state);
+
+ return $form[$element];
+}
+
+/**
+ * Form AJAX callback for adding fields.
+ */
+function searchlight_admin_datasource_ajax_fields_add($form, $form_state) {
+ return searchlight_admin_datasource_ajax($form, $form_state, 'edit-fields-new-add', 'fields');
+}
+
+/**
+ * Form AJAX callback for removing fields.
+ */
+function searchlight_admin_datasource_ajax_fields_remove($form, $form_state) {
+ return searchlight_admin_datasource_ajax($form, $form_state, 'edit-fields-remove', 'fields');
+}
+
+/**
+ * Form AJAX callback for adding MVA fields.
+ */
+function searchlight_admin_datasource_ajax_multivalues_add($form, $form_state) {
+ return searchlight_admin_datasource_ajax($form, $form_state, 'edit-multivalues-new-add', 'multivalues');
+}
+
+/**
+ * Form AJAX callback for removing MVA fields.
+ */
+function searchlight_admin_datasource_ajax_multivalues_remove($form, $form_state) {
+ return searchlight_admin_datasource_ajax($form, $form_state, 'edit-multivalues-remove', 'multivalues');
}
/**
* Confirmation form for datasource actions.
*/
-function searchlight_admin_confirm(&$form_state, $type, $object, $op) {
+function searchlight_admin_confirm($form, &$form_state, $type, $object, $op) {
switch ($type) {
case 'searchlight_datasource':
$type_name = t('datasource');
@@ -303,9 +328,18 @@ function searchlight_admin_confirm(&$form_state, $type, $object, $op) {
break;
}
$form = array();
- $form['type'] = array('#type' => 'value', '#value' => $type);
- $form['object'] = array('#type' => 'value', '#value' => $object);
- $form['action'] = array('#type' => 'value', '#value' => $op);
+ $form['type'] = array(
+ '#type' => 'value',
+ '#value' => $type,
+ );
+ $form['object'] = array(
+ '#type' => 'value',
+ '#value' => $object,
+ );
+ $form['action'] = array(
+ '#type' => 'value',
+ '#value' => $op,
+ );
switch ($op) {
case 'revert':
$action = t('revert');
@@ -324,9 +358,10 @@ function searchlight_admin_confirm(&$form_state, $type, $object, $op) {
$message = '';
break;
}
- $form = confirm_form($form,
+ $form = confirm_form(
+ $form,
t('Are you sure you want to !action the @type %title?', array('%title' => $object->name, '@type' => $type_name, '!action' => $action)),
- 'admin/settings/search',
+ 'admin/config/search/settings',
$message,
drupal_ucfirst($action), t('Cancel')
);
@@ -346,15 +381,16 @@ function searchlight_admin_confirm_submit($form, &$form_state) {
case 'searchlight_datasource':
searchlight_datasource_delete($object);
- // If reverting, display a message indicating that the index must be rebuilt.
+ // If reverting, display a message indicating that the index must be
+ // rebuilt.
if ($form_state['values']['action'] === 'revert') {
drupal_set_message(t('Datasource @datasource reverted. The index for this datasource needs to be rebuilt.', array('@datasource' => $object->name)));
}
- $form_state['redirect'] = 'admin/settings/search/datasource';
+ $form_state['redirect'] = 'admin/config/search/settings/datasource';
break;
case 'searchlight_environment':
searchlight_environment_delete($object);
- $form_state['redirect'] = 'admin/settings/search/environment';
+ $form_state['redirect'] = 'admin/config/search/settings/environment';
break;
}
break;
@@ -364,8 +400,8 @@ function searchlight_admin_confirm_submit($form, &$form_state) {
/**
* System settings form for Searchlight.
*/
-function searchlight_admin_backend($form_state) {
- drupal_add_js(drupal_get_path('module', 'searchlight') .'/searchlight.admin.js');
+function searchlight_admin_backend($form, $form_state) {
+ drupal_add_js(drupal_get_path('module', 'searchlight') . '/searchlight.admin.js');
$form = array();
@@ -387,7 +423,7 @@ function searchlight_admin_backend($form_state) {
'#type' => 'select',
'#title' => t('Global search'),
'#description' => t('Choose a View to power the global search block.'),
- '#options' => array(FALSE => '<'. t("Don't replace global search") .'>') + searchlight_admin_global_search_views(),
+ '#options' => array(FALSE => '<' . t("Don't replace global search") . '>') + searchlight_admin_global_search_views(),
'#default_value' => variable_get('searchlight_global_search', FALSE),
);
@@ -400,10 +436,10 @@ function searchlight_admin_backend($form_state) {
);
$form['backend']['searchlight_backend'] = array(
'#type' => 'select',
- '#options' => array(0 => '< '. t('Choose a backend') .' >'),
+ '#options' => array(0 => '< ' . t('Choose a backend') . ' >'),
'#default_value' => variable_get('searchlight_backend', 'sphinx'),
'#attributes' => array(
- 'class' => 'searchlight-backend-select',
+ 'class' => array('searchlight-backend-select'),
),
);
foreach (searchlight_registry('backend', TRUE) as $key => $info) {
@@ -414,7 +450,7 @@ function searchlight_admin_backend($form_state) {
$form["searchlight_backend_{$key}"]['#title'] = $info['title'];
$form["searchlight_backend_{$key}"]['#type'] = 'fieldset';
$form["searchlight_backend_{$key}"]['#attributes'] = array(
- 'class' => "searchlight-backend-settings searchlight-backend-{$key}",
+ 'class' => array("searchlight-backend-settings", "searchlight-backend-{$key}"),
);
}
$form = system_settings_form($form);
diff --git a/searchlight.admin.js b/searchlight.admin.js
index f740a8b..497156f 100644
--- a/searchlight.admin.js
+++ b/searchlight.admin.js
@@ -1,30 +1,34 @@
// $Id$
-Drupal.behaviors.searchlight = function(context) {
- $('.searchlight-backend-select:not(.searchlight-processed)', context).each(function() {
- $(this).change(function() {
- var value = $(this).val();
- $('.searchlight-backend-settings').hide();
- $('.searchlight-backend-' + value).show();
- });
- $(this).change();
- }).addClass('searchlight-processed');
- $('.searchlight-admin-environment .environment-settings:not(.searchlight-processed)', context).each(function() {
- $('a.environment-settings-link', this).click(function() {
- if ($(this).is('.settings-active')) {
- $('.searchlight-admin-environment .environment-settings-form').hide();
- $('a.environment-settings-link').removeClass('settings-active');
- }
- else {
- // Hide & show per-facet settings forms.
- $('.searchlight-admin-environment .environment-settings-form').hide();
- var target = $(this).attr('href').split('#')[1];
- $('#' + target).show();
+(function ($) {
+ Drupal.behaviors.searchlight = {
+ attach: function(context, settiongs) {
+ $('.searchlight-backend-select:not(.searchlight-processed)', context).each(function() {
+ $(this).change(function() {
+ var value = $(this).val();
+ $('.searchlight-backend-settings').hide();
+ $('.searchlight-backend-' + value).show();
+ });
+ $(this).change();
+ }).addClass('searchlight-processed');
+ $('.searchlight-admin-environment .environment-settings:not(.searchlight-processed)', context).each(function() {
+ $('a.environment-settings-link', this).click(function() {
+ if ($(this).is('.settings-active')) {
+ $('.searchlight-admin-environment .environment-settings-form').hide();
+ $('a.environment-settings-link').removeClass('settings-active');
+ }
+ else {
+ // Hide & show per-facet settings forms.
+ $('.searchlight-admin-environment .environment-settings-form').hide();
+ var target = $(this).attr('href').split('#')[1];
+ $('#' + target).show();
- // Set link classes.
- $('a.environment-settings-link').removeClass('settings-active');
- $(this).addClass('settings-active');
- }
- });
- $(this).change();
- }).addClass('searchlight-processed');
-};
+ // Set link classes.
+ $('a.environment-settings-link').removeClass('settings-active');
+ $(this).addClass('settings-active');
+ }
+ });
+ $(this).change();
+ }).addClass('searchlight-processed');
+ }
+ }
+})(jQuery);
diff --git a/searchlight.drush.inc b/searchlight.drush.inc
index 17c97a5..5af11e4 100644
--- a/searchlight.drush.inc
+++ b/searchlight.drush.inc
@@ -2,7 +2,7 @@
// $Id$
/**
- * Implementation of hook_drush_command().
+ * Implements hook_drush_command().
*/
function searchlight_drush_command() {
$items = array();
diff --git a/searchlight.info b/searchlight.info
index 5a324c9..3ca6880 100644
--- a/searchlight.info
+++ b/searchlight.info
@@ -1,6 +1,46 @@
-core = "6.x"
+core = 7.x
dependencies[] = "ctools"
dependencies[] = "views"
description = "Views-driven search API with pluggable search backends."
name = "Searchlight"
package = "Search"
+
+
+files[] = searchlight.admin.inc
+files[] = searchlight.drush.inc
+files[] = searchlight.install
+files[] = searchlight.module
+files[] = searchlight_provision.drush.inc
+files[] = includes/SearchlightDatasource.inc
+files[] = includes/SearchlightEnvironment.inc
+files[] = libraries/sphinxapi.php
+files[] = Solr/Document.php
+files[] = Solr/Response.php
+files[] = Solr/Service.php
+files[] = Service/Balancer.php
+files[] = plugins/SearchlightBackend.inc
+files[] = plugins/SearchlightBackendSolr.inc
+files[] = plugins/SearchlightBackendSphinx.inc
+files[] = plugins/SearchlightFacet.inc
+files[] = plugins/SearchlightFacetDatatypeTimestamp.inc
+files[] = plugins/SearchlightFacetLanguage.inc
+files[] = plugins/SearchlightFacetSearchQuery.inc
+files[] = plugins/SearchlightFacetTerm.inc
+files[] = theme/searchlight-admin-datasource.tpl.php
+files[] = theme/searchlight-admin-environment.tpl.php
+files[] = theme/searchlight-solr-config.tpl.php
+files[] = theme/searchlight-solr-cores.tpl.php
+files[] = theme/searchlight-solr-schema.tpl.php
+files[] = theme/searchlight-sphinx-conf.tpl.php
+files[] = theme/searchlight-sphinx-index-conf.tpl.php
+files[] = theme/searchlight.theme.inc
+files[] = views/searchlight.views.inc
+files[] = views/searchlight_handler_argument_search.inc
+files[] = views/searchlight_handler_field_facet_link.inc
+files[] = views/searchlight_handler_field_node_access.inc
+files[] = views/searchlight_handler_filter_facets.inc
+files[] = views/searchlight_handler_filter_search.inc
+files[] = views/searchlight_handler_sort_search.inc
+files[] = views/searchlight_plugin_display_multivalue.inc
+files[] = views/searchlight_plugin_display_solr.inc
+files[] = views/searchlight_plugin_query_v3.inc
diff --git a/searchlight.install b/searchlight.install
index 7ece968..bd9f9e3 100644
--- a/searchlight.install
+++ b/searchlight.install
@@ -1,12 +1,18 @@
t('Storage for Searchlight datasource configuration.'),
+ 'description' => 'Storage for Searchlight datasource configuration.',
'export' => array(
'key' => 'name',
'object' => 'SearchlightDatasource',
@@ -39,6 +45,11 @@ function searchlight_schema() {
'type' => 'text',
'serialize' => TRUE,
),
+ 'relations' => array(
+ 'description' => 'Serialized storage of datasource relations settings.',
+ 'type' => 'text',
+ 'serialize' => TRUE,
+ ),
'filters' => array(
'description' => 'Serialized storage of datasource filter settings.',
'type' => 'text',
@@ -53,7 +64,7 @@ function searchlight_schema() {
'primary key' => array('name'),
);
$schema['searchlight_environment'] = array(
- 'description' => t('Storage for Searchlight environment configuration.'),
+ 'description' => 'Storage for Searchlight environment configuration.',
'export' => array(
'key' => 'name',
'object' => 'SearchlightEnvironment',
@@ -95,55 +106,61 @@ function searchlight_schema() {
'primary key' => array('name'),
);
$schema['searchlight_search'] = array(
- 'description' => t('Stores a record of an items status in the index.'),
+ 'description' => 'Stores a record of an items status in the index.',
'fields' => array(
'type' => array(
- 'description' => t('The type of item.'),
+ 'description' => 'The type of item.',
'type' => 'varchar',
'length' => '128',
- 'not null' => TRUE
+ 'not null' => TRUE,
),
'id' => array(
- 'description' => t('The primary identifier for an item.'),
+ 'description' => 'The primary identifier for an item.',
'type' => 'int',
'unsigned' => TRUE,
- 'not null' => TRUE
+ 'not null' => TRUE,
),
'status' => array(
- 'description' => t('Boolean indicating whether the item should be available in the index.'),
+ 'description' => 'Boolean indicating whether the item should be available in the index.',
'type' => 'int',
'not null' => TRUE,
- 'default' => 0
+ 'default' => 0,
),
),
'indexes' => array(
'status' => array('status'),
),
- 'primary key' => array('type, id'),
+ 'primary key' => array('type', 'id'),
);
return $schema;
}
/**
- * Implementation of hook_enable().
+ * Implements hook_enable().
*/
function searchlight_enable() {
searchlight_invalidate_index();
}
/**
- * Implementation of hook_install().
+ * Implements hook_install().
*/
function searchlight_install() {
- drupal_install_schema('searchlight');
+ // TODO The drupal_(un)install_schema functions are called automatically in D7.
+ // drupal_install_schema('searchlight')
}
/**
- * Implementation of hook_uninstall().
+ * Implements hook_uninstall().
*/
function searchlight_uninstall() {
variable_del('searchlight_views');
variable_del('searchlight_backend');
- db_query("DELETE FROM {variable} WHERE name LIKE 'searchlight_backend_%'");
- drupal_uninstall_schema('searchlight');
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("DELETE FROM {variable} WHERE name LIKE 'searchlight_backend_%'") */
+ db_delete('variable')
+ ->condition('name', 'searchlight_backend_%', 'LIKE')
+ ->execute();
+ // TODO The drupal_(un)install_schema functions are called automatically in D7.
+ // drupal_uninstall_schema('searchlight')
}
diff --git a/searchlight.js b/searchlight.js
index 4952975..38c3f82 100644
--- a/searchlight.js
+++ b/searchlight.js
@@ -1,72 +1,8 @@
(function($) {
- $.fn.drupalSearchlight = function(method, params) {
- switch (method) {
- case 'ajaxViewLink':
- var settings = params.settings;
- var view = params.view;
- // If there are multiple views this might've ended up showing up multiple times.
- var ajax_path = Drupal.settings.views.ajax_path;
- if (ajax_path.constructor.toString().indexOf("Array") != -1) {
- ajax_path = ajax_path[0];
- }
-
- $(this).click(function() {
- var link = $(this);
- var viewData = { 'js': 1 };
-
- // Construct an object using the settings defaults and then overriding
- // with data specific to the link.
- $.extend(
- viewData,
- Drupal.Views.parseQueryString(link.attr('href')),
- // Extract argument data from the URL.
- Drupal.Views.parseViewArgs(link.attr('href'), settings.view_base_path),
- // Settings must be used last to avoid sending url aliases to the server.
- settings
- );
-
- // Show throbber.
- link.addClass('views-throbbing');
-
- // AJAX request.
- $.ajax({
- url: ajax_path,
- type: 'GET',
- data: viewData,
- success: function(response) {
- link.removeClass('views-throbbing');
-
- // Call all callbacks.
- if (response.__callbacks) {
- $.each(response.__callbacks, function(i, callback) { eval(callback)(view, response); });
- }
- },
- error: function(xhr) { link.removeClass('views-throbbing'); Drupal.Views.Ajax.handleErrors(xhr, ajax_path); },
- dataType: 'json'
- });
-
- // Don't follow through link.
- return false;
- });
- break;
- }
- return this;
- };
- $.fn.drupalSearchlight.replace = function(selector, data) {
- if (data.searchlightData) {
- for (var target in data.searchlightData) {
- if ($(target).size()) {
- $(target).replaceWith(data.searchlightData[target]);
- Drupal.attachBehaviors($(target));
- }
- }
- }
- };
-})(jQuery);
-
-Drupal.behaviors.searchlight = function(context) {
- if (Drupal.settings.views && Drupal.settings.views.ajaxViews) {
+Drupal.behaviors.searchlight = {};
+Drupal.behaviors.searchlight.attach = function(context, settings) {
+ if (Drupal.settings && Drupal.settings.views && Drupal.settings.views.ajaxViews) {
$('.searchlight-environment:not(.searchlightProcessed)').each(function() {
// Retrieve current page view's settings and DOM element.
var settings = {};
@@ -74,8 +10,11 @@ Drupal.behaviors.searchlight = function(context) {
var identifier = $(this).attr('class').split('searchlight-view-')[1].split('-');
for (var i in Drupal.settings.views.ajaxViews) {
if (
- Drupal.settings.views.ajaxViews[i].view_name == identifier[0] &&
- Drupal.settings.views.ajaxViews[i].view_display_id == identifier[1]
+ Drupal.settings.views.ajaxViews[i].view_name == identifier[0]
+ // @TODO: Do a loose (view-name only) check for attaching AJAX
+ // view handlers to allow environments to be used with multiple
+ // displays in the same view.
+ // && Drupal.settings.views.ajaxViews[i].view_display_id == identifier[1]
) {
settings = Drupal.settings.views.ajaxViews[i];
view = $('.view-dom-id-' + settings.view_dom_id);
@@ -86,3 +25,61 @@ Drupal.behaviors.searchlight = function(context) {
}).addClass('searchlightProcessed');
}
};
+
+$.fn.drupalSearchlight = function(method, params) {
+ switch (method) {
+ case 'ajaxViewLink':
+ var settings = params.settings;
+ var view = params.view;
+
+ // If there are multiple views this might've ended up showing up multiple times.
+ var ajax_path = Drupal.settings.views.ajax_path;
+ if (ajax_path.constructor.toString().indexOf("Array") != -1) {
+ ajax_path = ajax_path[0];
+ }
+
+ $(this).each(function() {
+ var viewData = {};
+ var link = $(this);
+
+ // Construct an object using the settings defaults and then overriding
+ // with data specific to the link.
+ $.extend(
+ viewData,
+ Drupal.Views.parseQueryString(link.attr('href')),
+ // Extract argument data from the URL.
+ Drupal.Views.parseViewArgs(link.attr('href'), settings.view_base_path),
+ // Settings must be used last to avoid sending url aliases to the server.
+ settings
+ );
+
+ var ajax = new Drupal.ajax(false, link, {
+ url: ajax_path,
+ submit: viewData,
+ event: 'click',
+ selector: view
+ });
+
+ // Override HTTP method type and beforeSerialize method.
+ // See note above.
+ ajax.options.type = 'GET';
+ ajax.beforeSerialize = function(element_settings, options) { return; };
+ });
+ break;
+ }
+ return this;
+};
+
+$.fn.drupalSearchlight.replace = function(selector, data) {
+ if (data.searchlightData) {
+ for (var target in data.searchlightData) {
+ if ($(target).size()) {
+ $(target).replaceWith(data.searchlightData[target]);
+ Drupal.attachBehaviors($(target));
+ }
+ }
+ }
+};
+
+})(jQuery);
+
diff --git a/searchlight.module b/searchlight.module
index 63d8455..206ab05 100644
--- a/searchlight.module
+++ b/searchlight.module
@@ -1,10 +1,10 @@
'Datasource',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_datasource'),
@@ -29,17 +29,17 @@ function searchlight_menu() {
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
- $items['admin/settings/search/datasource/list/%searchlight_datasource'] = array(
+ $items['admin/config/search/settings/datasource/%searchlight_datasource'] = array(
'title' => 'Datasource',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_datasource_edit', 5),
'access callback' => 'user_access',
'access arguments' => array('administer site configuration'),
'file' => 'searchlight.admin.inc',
- 'type' => MENU_CALLBACK,
+ 'type' => MENU_LOCAL_TASK,
'weight' => -10,
);
- $items['admin/settings/search/datasource/list/%searchlight_datasource/edit'] = array(
+ $items['admin/config/search/settings/datasource/%searchlight_datasource/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_datasource_edit', 5),
@@ -49,7 +49,7 @@ function searchlight_menu() {
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
- $items['admin/settings/search/datasource/list/%searchlight_datasource/delete'] = array(
+ $items['admin/config/search/settings/datasource/%searchlight_datasource/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_confirm', 'searchlight_datasource', 5, 'revert'),
@@ -58,7 +58,7 @@ function searchlight_menu() {
'file' => 'searchlight.admin.inc',
'type' => MENU_LOCAL_TASK,
);
- $items['admin/settings/search/datasource/list/%searchlight_datasource/revert'] = array(
+ $items['admin/config/search/settings/datasource/%searchlight_datasource/revert'] = array(
'title' => 'Revert',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_confirm', 'searchlight_datasource', 5, 'revert'),
@@ -67,16 +67,7 @@ function searchlight_menu() {
'file' => 'searchlight.admin.inc',
'type' => MENU_LOCAL_TASK,
);
- $items['admin/settings/search/datasource/ahah/%/%'] = array(
- 'page callback' => 'searchlight_admin_datasource_ahah',
- 'page arguments' => array(5, 6),
- 'access callback' => 'user_access',
- 'access arguments' => array('administer site configuration'),
- 'file' => 'searchlight.admin.inc',
- 'type' => MENU_CALLBACK,
- );
-
- $items['admin/settings/search/environment'] = array(
+ $items['admin/config/search/settings/environment'] = array(
'title' => 'Environment',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_environment'),
@@ -86,17 +77,17 @@ function searchlight_menu() {
'type' => MENU_LOCAL_TASK,
'weight' => -5,
);
- $items['admin/settings/search/environment/list/%searchlight_environment'] = array(
+ $items['admin/config/search/settings/environment/%searchlight_environment'] = array(
'title' => 'Environment',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_environment_edit', 5),
'access callback' => 'user_access',
'access arguments' => array('administer site configuration'),
'file' => 'searchlight.admin.inc',
- 'type' => MENU_CALLBACK,
+ 'type' => MENU_LOCAL_TASK,
'weight' => -10,
);
- $items['admin/settings/search/environment/list/%searchlight_environment/edit'] = array(
+ $items['admin/config/search/settings/environment/%searchlight_environment/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_environment_edit', 5),
@@ -106,7 +97,7 @@ function searchlight_menu() {
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
- $items['admin/settings/search/environment/list/%searchlight_environment/delete'] = array(
+ $items['admin/config/search/settings/environment/%searchlight_environment/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_confirm', 'searchlight_environment', 5, 'revert'),
@@ -115,7 +106,7 @@ function searchlight_menu() {
'file' => 'searchlight.admin.inc',
'type' => MENU_LOCAL_TASK,
);
- $items['admin/settings/search/environment/list/%searchlight_environment/revert'] = array(
+ $items['admin/config/search/settings/environment/%searchlight_environment/revert'] = array(
'title' => 'Revert',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_confirm', 'searchlight_environment', 5, 'revert'),
@@ -125,7 +116,7 @@ function searchlight_menu() {
'type' => MENU_LOCAL_TASK,
);
- $items['admin/settings/search/backend'] = array(
+ $items['admin/config/search/settings/backend'] = array(
'title' => 'Backend',
'page callback' => 'drupal_get_form',
'page arguments' => array('searchlight_admin_backend'),
@@ -138,27 +129,34 @@ function searchlight_menu() {
}
/**
- * Implementation of hook_menu_alter().
+ * Implements hook_menu_alter().
*/
function searchlight_menu_alter(&$items) {
- $items['admin/settings/search'] = $items['admin/settings/search/datasource'];
- $items['admin/settings/search']['title'] = 'Search';
- $items['admin/settings/search']['type'] = MENU_NORMAL_ITEM;
- unset($items['admin/settings/search']['weight']);
+ $items['admin/config/search/settings'] = $items['admin/config/search/settings/datasource'];
+ $items['admin/config/search/settings']['title'] = 'Search';
+ $items['admin/config/search/settings']['description'] = 'Configure relevance settings for search and other indexing options.';
+ $items['admin/config/search/settings']['type'] = MENU_NORMAL_ITEM;
+ unset($items['admin/config/search/settings']['weight']);
}
/**
- * Implementation of hook_block().
+ * Implements hook_block_info().
*/
-function searchlight_block($op = 'list', $delta = 0, $edit = array()) {
- if ($op === 'list') {
+function searchlight_block_info() {
+ if (TRUE) {
$list = array();
foreach (searchlight_environment_load() as $environment) {
- $list['facets_'. $environment->name] = array('info' => t('@name: Search facets', array('@name' => $environment->name)));
+ $list['facets_' . $environment->name] = array('info' => t('@name: Search facets', array('@name' => $environment->name)));
}
return $list;
}
- else if ($op === 'view' && strpos($delta, '_') !== FALSE) {
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function searchlight_block_view($delta) {
+ if (TRUE && strpos($delta, '_') !== FALSE) {
list($delta, $name) = explode('_', $delta, 2);
if (in_array($delta, array('facets'), TRUE) && $environment = searchlight_environment_load($name)) {
return $environment->getBlock($delta);
@@ -167,50 +165,92 @@ function searchlight_block($op = 'list', $delta = 0, $edit = array()) {
}
/**
- * Implementation of hook_nodeapi().
+ * Implements hook_node_insert().
*/
-function searchlight_nodeapi($node, $op) {
- switch ($op) {
- case 'insert':
- db_query("INSERT INTO {searchlight_search} (type, id, status) VALUES ('node', %d, %d)", $node->nid, 0);
- break;
- case 'update':
- db_query("UPDATE {searchlight_search} SET status = 0 WHERE type='node' and id=%d", $node->nid);
- break;
- case 'delete':
- db_query("UPDATE {searchlight_search} SET status = -1 WHERE type='node' and id=%d", $node->nid);
- break;
- }
+function searchlight_node_insert($node) {
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("INSERT INTO {searchlight_search} (type, id, status) VALUES ('node', %d, %d)", $node->nid, 0) */
+ $id = db_insert('searchlight_search')
+ ->fields(array(
+ 'type' => 'node',
+ 'id' => $node->nid,
+ 'status' => 0,
+ ))
+ ->execute();
}
/**
- * Implementation of hook_comment().
+ * Implements hook_node_update().
*/
-function searchlight_comment(&$a1, $op) {
- $update_node = FALSE;
- switch ($op) {
- case 'insert':
- db_query("INSERT INTO {searchlight_search} (type, id, status) VALUES ('comments', %d, %d)", $a1['cid'], 0);
- $update_node = TRUE;
- break;
- case 'update':
- db_query("UPDATE {searchlight_search} SET status = 0 WHERE type = 'comments' AND id = %d", $a1['cid']);
- $update_node = TRUE;
- break;
- case 'delete':
- db_query("UPDATE {searchlight_search} SET status = -1 WHERE type = 'comments' and id = %d", $a1['cid']);
- $update_node = TRUE;
- break;
- }
- if ($update_node) {
- // Mark the parent node as needing an update. Changes in node comments
- // can affect the node as well (e.g. node_comment_statistics).
- db_query("UPDATE {searchlight_search} SET status = 0 WHERE type='node' and id=%d", $a1['nid']);
- }
+function searchlight_node_update($node) {
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("UPDATE {searchlight_search} SET status = 0 WHERE type='node' and id=%d", $node->nid) */
+ db_update('searchlight_search')
+ ->fields(array( 'status' => 0,))
+ ->condition('type', 'node')
+ ->condition('id', $node->nid)
+ ->execute();
}
/**
- * Implementation of hook_theme().
+ * Implements hook_node_delete().
+ */
+function searchlight_node_delete($node) {
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("UPDATE {searchlight_search} SET status = -1 WHERE type='node' and id=%d", $node->nid) */
+ db_update('searchlight_search')
+ ->fields(array( 'status' => -1,))
+ ->condition('type', 'node')
+ ->condition('id', $node->nid)
+ ->execute();
+}
+
+/**
+ * Implements hook_comment_insert().
+ */
+function searchlight_comment_insert($comment) {
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("INSERT INTO {searchlight_search} (type, id, status) VALUES ('comments', %d, %d)", $a1['cid'], 0) */
+ $id = db_insert('searchlight_search')
+ ->fields(array(
+ 'type' => 'comments',
+ 'id' => $comment->cid,
+ 'status' => 0,
+ ))
+ ->execute();
+ $update_node = TRUE;
+}
+
+/**
+ * Implements hook_comment_update().
+ */
+function searchlight_comment_update($comment) {
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("UPDATE {searchlight_search} SET status = 0 WHERE type = 'comments' AND id = %d", $a1['cid']) */
+ db_update('searchlight_search')
+ ->fields(array('status' => 0,))
+ ->condition('type', 'comments')
+ ->condition('id', $comment->cid)
+ ->execute();
+ $update_node = TRUE;
+}
+
+/**
+ * Implements hook_comment_delete().
+ */
+function searchlight_comment_delete($comment) {
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("UPDATE {searchlight_search} SET status = -1 WHERE type = 'comments' and id = %d", $a1['cid']) */
+ db_update('searchlight_search')
+ ->fields(array('status' => -1, ))
+ ->condition('type', 'comments')
+ ->condition('id', $comment->cid)
+ ->execute();
+ $update_node = TRUE;
+}
+
+/**
+ * Implements hook_theme().
*/
function searchlight_theme() {
return array(
@@ -220,78 +260,87 @@ function searchlight_theme() {
),
'searchlight_sphinx_conf' => array(
'template' => 'searchlight-sphinx-conf',
- 'arguments' => array('searchd' => array()),
+ 'variables' => array('searchd' => array()),
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_sphinx_index_conf' => array(
'template' => 'searchlight-sphinx-index-conf',
- 'arguments' => array('datasource' => array()),
+ 'variables' => array('datasource' => array()),
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_solr_schema' => array(
'template' => 'searchlight-solr-schema',
- 'arguments' => array('datasource' => array()),
+ 'variables' => array('datasource' => array()),
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_solr_config' => array(
'template' => 'searchlight-solr-config',
- //'arguments' => array('datasource' => array()),
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_solr_cores' => array(
'template' => 'searchlight-solr-cores',
- 'arguments' => array('cores' => array()),
+ 'variables' => array('cores' => array()),
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_plugin_display_datasource' => array(
- 'arguments' => array('form' => array()),
+ 'render element' => 'form',
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_facet' => array(
'path' => drupal_get_path('module', 'searchlight') . '/theme',
+ 'variables' => array('facet' => array()),
'file' => 'searchlight.theme.inc',
),
'searchlight_facet_link' => array(
'path' => drupal_get_path('module', 'searchlight') . '/theme',
+ 'variables' => array('field' => NULL, 'item' => array()),
'file' => 'searchlight.theme.inc',
),
'searchlight_facet_active' => array(
'path' => drupal_get_path('module', 'searchlight') . '/theme',
+ 'variables' => array('field' => NULL, 'item' => array()),
'file' => 'searchlight.theme.inc',
),
'searchlight_admin_list' => array(
'path' => drupal_get_path('module', 'searchlight') . '/theme',
+ 'render element' => 'form',
'file' => 'searchlight.theme.inc',
),
'searchlight_admin_datasource' => array(
'template' => 'searchlight-admin-datasource',
- 'arguments' => array('form' => array()),
+ 'render element' => 'form',
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_admin_datasource_fields' => array(
- 'arguments' => array('form' => array()),
+ 'render element' => 'form',
+ 'path' => drupal_get_path('module', 'searchlight') . '/theme',
+ 'file' => 'searchlight.theme.inc',
+ ),
+ 'searchlight_admin_datasource_relations' => array(
+ 'render element' => 'form',
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
'searchlight_admin_environment' => array(
'template' => 'searchlight-admin-environment',
- 'arguments' => array('form' => array()),
+ 'render element' => 'form',
'path' => drupal_get_path('module', 'searchlight') . '/theme',
'file' => 'searchlight.theme.inc',
),
);
}
+
+
/**
* Preprocessor for theme('page').
- */
function searchlight_preprocess_page(&$vars) {
if ($global_search = variable_get('searchlight_global_search', FALSE)) {
list($path, $identifier) = explode(':', $global_search);
@@ -303,10 +352,13 @@ function searchlight_preprocess_page(&$vars) {
'no_redirect' => TRUE,
'input' => array(),
);
- $vars['search_box'] = drupal_build_form('searchlight_search_form', $form_state);
+ // $vars['search_box'] = drupal_build_form('searchlight_search_form', $form_state);
}
+
}
+ */
+
/**
* Form builder for Searchlight GET form. Should be used with
* drupal_build_form(), the function used in Views for exposed filter forms.
@@ -317,7 +369,10 @@ function searchlight_search_form(&$form_state) {
$form['#id'] = 'searchlight-search-form';
if (!variable_get('clean_url', FALSE)) {
- $form['q'] = array('#type' => 'hidden', '#value' => $form_state['path']);
+ $form['q'] = array(
+ '#type' => 'hidden',
+ '#value' => $form_state['path'],
+ );
}
$form[$form_state['identifier']] = array(
@@ -329,23 +384,23 @@ function searchlight_search_form(&$form_state) {
'#name' => '', // prevent from showing up in $_GET.
'#type' => 'submit',
'#value' => t('Search'),
- '#id' => form_clean_id('edit-submit-searchlight-search-form'),
+ '#id' => drupal_clean_css_identifier('edit-submit-searchlight-search-form'),
);
return $form;
}
/**
- * Implementation of hook_views_api().
+ * Implements hook_views_api().
*/
function searchlight_views_api() {
return array(
- 'api' => 2,
+ 'api' => '3.0-alpha1',
'path' => drupal_get_path('module', 'searchlight') . '/views',
);
}
/**
- * Implementation of hook_ctools_plugin_api().
+ * Implements hook_ctools_plugin_api().
*/
function searchlight_ctools_plugin_api($module = NULL, $api = NULL) {
if ($module === 'searchlight') {
@@ -361,31 +416,35 @@ function searchlight_ctools_plugin_api($module = NULL, $api = NULL) {
}
/**
- * Implementation of hook_ctools_plugin_plugins().
+ * Implements hook_ctools_plugin_plugins().
*/
-function searchlight_ctools_plugin_plugins() {
+function searchlight_ctools_plugin_type() {
return array(
- 'cache' => TRUE,
- 'use hooks' => TRUE,
+ 'plugins' => array(
+ 'cache' => TRUE,
+ 'use hooks' => TRUE,
+ 'classes' => array('handler'),
+ ),
);
}
+
/**
- * Implementation of hook_searchlight_plugins().
+ * Implements hook_searchlight_plugins().
* This is a CTools plugin API hook.
*/
function searchlight_searchlight_plugins() {
return array(
'SearchlightBackend' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightBackend.inc',
'class' => 'SearchlightBackend',
),
),
'SearchlightBackendSphinx' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightBackendSphinx.inc',
'class' => 'SearchlightBackendSphinx',
'parent' => 'SearchlightBackend',
@@ -393,7 +452,7 @@ function searchlight_searchlight_plugins() {
),
'SearchlightBackendSolr' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightBackendSolr.inc',
'class' => 'SearchlightBackendSolr',
'parent' => 'SearchlightBackend',
@@ -401,14 +460,14 @@ function searchlight_searchlight_plugins() {
),
'SearchlightFacet' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightFacet.inc',
'class' => 'SearchlightFacet',
),
),
'SearchlightFacetSearchQuery' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightFacetSearchQuery.inc',
'class' => 'SearchlightFacetSearchQuery',
'parent' => 'SearchlightFacet',
@@ -416,7 +475,7 @@ function searchlight_searchlight_plugins() {
),
'SearchlightFacetTerm' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightFacetTerm.inc',
'class' => 'SearchlightFacetTerm',
'parent' => 'SearchlightFacet',
@@ -424,7 +483,7 @@ function searchlight_searchlight_plugins() {
),
'SearchlightFacetDatatypeTimestamp' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightFacetDatatypeTimestamp.inc',
'class' => 'SearchlightFacetDatatypeTimestamp',
'parent' => 'SearchlightFacet',
@@ -432,7 +491,7 @@ function searchlight_searchlight_plugins() {
),
'SearchlightFacetLanguage' => array(
'handler' => array(
- 'path' => drupal_get_path('module', 'searchlight') .'/plugins',
+ 'path' => drupal_get_path('module', 'searchlight') . '/plugins',
'file' => 'SearchlightFacetLanguage.inc',
'class' => 'SearchlightFacetLanguage',
'parent' => 'SearchlightFacet',
@@ -442,7 +501,7 @@ function searchlight_searchlight_plugins() {
}
/**
- * Implementation of hook_searchlight_registry().
+ * Implements hook_searchlight_registry().
*/
function searchlight_searchlight_registry() {
return array(
@@ -465,7 +524,7 @@ function searchlight_searchlight_registry() {
'title' => t('Search query'),
'plugin' => 'SearchlightFacetSearchQuery',
),
- 'term_data_tid' => array(
+ 'taxonomy_index_tid' => array(
'title' => t('Taxonomy term'),
'plugin' => 'SearchlightFacetTerm',
),
@@ -482,45 +541,33 @@ function searchlight_searchlight_registry() {
}
/**
- * Implementation of hook_form_alter() for 'views_exposed_form'.
+ * Implements hook_form_alter() for 'views_exposed_form'().
* Ensure that Searchlight facet components are preserved when Views exposed
* filters are submitted.
*/
function searchlight_form_views_exposed_form_alter(&$form, &$form_state) {
$key = variable_get('searchlight_facet_key', 'sl');
if (!isset($form[$key]) && isset($_GET[$key])) {
- $form[$key] = array('#type' => 'hidden', '#value' => $_GET[$key]);
+ $form[$key] = array(
+ '#type' => 'hidden',
+ '#value' => $_GET[$key],
+ );
}
}
/**
- * Implementation of hook_ajax_data_alter().
- *
- * This hook is called by Views (and some other modules) when returning AJAX
- * data to the client. It provides an event for other modules to hook into to
- * alter the AJAX data returned and register additional *javascript* callbacks
- * to be used once the AJAX response is received.
- */
-function searchlight_ajax_data_alter(&$object, $type, $metadata) {
- if ($type === 'views') {
- $view = $metadata;
- // If this is a searchlight view with AJAX, add a callback for updating any
- // associated facet blocks.
- if (isset($view->query) && !empty($view->query->searchlight)) {
- $environment = searchlight_environment_active(NULL, $view->name, $view->current_display);
- if ($environment) {
- $block = $environment->getBlock('facets');
- $object->searchlightData = array(".searchlight-environment-{$environment->name}" => $block['content']);
-
- // Add searchlight replace callback.
- $object->__callbacks[] = '$().drupalSearchlight.replace';
- }
- }
+ * Implements hook_ajax_render_alter().
+ */
+function searchlight_ajax_render_alter(&$commands) {
+ $environment = searchlight_environment_active();
+ if ($environment) {
+ $block = $environment->getBlock('facets');
+ $commands[] = ajax_command_replace(".searchlight-environment-{$environment->name}", $block['content']);
}
}
/**
- * Implementation of hook_searchlight_node_access_realms_alter().
+ * Implements hook_searchlight_node_access_realms_alter().
* Provide realms for commonly used node_access modules.
*/
function searchlight_searchlight_node_access_realms_alter(&$realms) {
@@ -622,7 +669,7 @@ function searchlight_get_datasource($base_table = NULL) {
views_include('admin');
$active_datasources = array();
foreach (array_keys(views_fetch_base_tables()) as $base_table) {
- $name = variable_get("searchlight_datasource_{$base_table}", "searchlight_{$base_table}");
+ $name = variable_get("searchlight_datasource_{$base_table}", "search_{$base_table}");
if (!empty($name) && $datasource = searchlight_datasource_load($name)) {
$active_datasources[$name] = $datasource;
}
@@ -630,7 +677,7 @@ function searchlight_get_datasource($base_table = NULL) {
return $active_datasources;
}
else {
- $name = variable_get("searchlight_datasource_{$base_table}", "searchlight_{$base_table}");
+ $name = variable_get("searchlight_datasource_{$base_table}", "search_{$base_table}");
if (!empty($name) && $datasource = searchlight_datasource_load($name)) {
return $datasource;
}
@@ -641,11 +688,11 @@ function searchlight_get_datasource($base_table = NULL) {
/**
* Retrieve a new inited Searchlight query.
*/
-function searchlight_get_query($base_table, $base_field, $backend = NULL) {
+function searchlight_get_query($base_table, $base_field, $options = array(), $backend = NULL) {
$backend = !isset($backend) ? searchlight_get_backend() : $backend;
if ($backend) {
$query = views_get_plugin('query', 'searchlight');
- $query->init($base_table, $base_field, $backend);
+ $query->init($base_table, $base_field, $options, $backend);
return $query;
}
return FALSE;
@@ -754,7 +801,11 @@ function searchlight_datasource_save($datasource, $editing = FALSE) {
*/
function searchlight_datasource_delete($datasource) {
if (isset($datasource->name) && ($datasource->export_type & EXPORT_IN_DATABASE)) {
- db_query("DELETE FROM {searchlight_datasource} WHERE name = '%s'", $datasource->name);
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("DELETE FROM {searchlight_datasource} WHERE name = '%s'", $datasource->name) */
+ db_delete('searchlight_datasource')
+ ->condition('name', $datasource->name)
+ ->execute();
searchlight_invalidate_cache();
return TRUE;
}
@@ -767,7 +818,17 @@ function searchlight_datasource_delete($datasource) {
function searchlight_environment_pack($value) {
$keyvals = array();
foreach ($value as $k => $v) {
- $keyvals[] = "{$k}-{$v}";
+ if (is_array($v)) {
+ $mv_string = '';
+ foreach ($v as $mvkey => $mv) {
+ $mv_string .= "{$mv}|";
+ }
+ $mv_string = substr($mv_string,0,-1);
+ $keyvals[] = "{$k}-{$mv_string}";
+ }
+ else {
+ $keyvals[] = "{$k}-{$v}";
+ }
}
return urlencode(implode(',', $keyvals));
}
@@ -782,7 +843,13 @@ function searchlight_environment_unpack($value) {
foreach ($split as $chunk) {
$keyval = explode('-', $chunk, 2);
if (count($keyval) === 2) {
- $parsed[$keyval[0]] = $keyval[1];
+ $multivalues = explode('|', $keyval[1]);
+ if (count($multivalues) > 1) {
+ $parsed[$keyval[0]] = $multivalues;
+ }
+ else {
+ $parsed[$keyval[0]] = $keyval[1];
+ }
}
}
return $parsed;
@@ -829,13 +896,18 @@ function searchlight_environment_active($environment = NULL, $view = NULL, $disp
}
// Match both view & display. Note that a lazy matched environment is not
// static cached as multiple may be active on the same page.
+ // EXCEPTION: In the context of an views AJAX response do static cache the
+ // active environment to allow the AJAX payload to be altered.
+ // See searchlight_ajax_render_alter().
else if (isset($view, $display)) {
foreach (searchlight_environment_load() as $environment) {
list($environment_view, $environment_display) = explode(':', $environment->view_display);
if ($environment->view_display === "{$view}:{$display}") {
+ $active = isset($_REQUEST['view_name'], $_REQUEST['view_display_id']) ? $environment : $active;
return $environment;
}
else if ($environment_view === $view) {
+ $active = isset($_REQUEST['view_name'], $_REQUEST['view_display_id']) ? $environment : $active;
return $environment;
}
}
@@ -917,7 +989,11 @@ function searchlight_environment_save($environment) {
*/
function searchlight_environment_delete($environment) {
if (isset($environment->name) && ($environment->export_type & EXPORT_IN_DATABASE)) {
- db_query("DELETE FROM {searchlight_environment} WHERE name = '%s'", $environment->name);
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("DELETE FROM {searchlight_environment} WHERE name = '%s'", $environment->name) */
+ db_delete('searchlight_environment')
+ ->condition('name', $environment->name)
+ ->execute();
searchlight_invalidate_cache();
return TRUE;
}
@@ -970,10 +1046,15 @@ function searchlight_invalidate_index($base_table = NULL) {
// Let the backend respond to a rebuild index command.
$backend->invalidateIndex($datasource);
- db_query("DELETE FROM {searchlight_search} WHERE type = '%s'", $datasource->base_table);
+ // TODO Please review the conversion of this statement to the D7 database API syntax.
+ /* db_query("DELETE FROM {searchlight_search} WHERE type = '%s'", $datasource->base_table) */
+ db_delete('searchlight_search')
+ ->condition('type', $datasource->base_table)
+ ->execute();
$views_data = views_fetch_data($datasource->base_table);
$base_field = $views_data['table']['base']['field'];
- db_query("INSERT INTO {searchlight_search} (type, id, status) SELECT '". $datasource->base_table ."', ". $base_field .", 0 FROM {". $datasource->base_table ."}");
+ // TODO Please convert this statement to the D7 database API syntax.
+ db_query("INSERT INTO {searchlight_search} (type, id, status) SELECT '" . $datasource->base_table . "', " . $base_field . ", 0 FROM {" . $datasource->base_table . "}");
}
}
}
diff --git a/searchlight_basic/searchlight_basic.defaults.inc b/searchlight_basic/searchlight_basic.defaults.inc
index ef6ddb5..a238732 100644
--- a/searchlight_basic/searchlight_basic.defaults.inc
+++ b/searchlight_basic/searchlight_basic.defaults.inc
@@ -34,14 +34,6 @@ function _searchlight_basic_searchlight_default_datasources() {
'name' => 'node_title',
'usage' => 'content',
),
- 'node_revisions_body' => array(
- 'label' => 'Node: Body (body)',
- 'datatype' => 'text',
- 'table' => 'node_revisions',
- 'field' => 'body',
- 'name' => 'node_revisions_body',
- 'usage' => 'content',
- ),
'node_status' => array(
'label' => 'Node: Published (status)',
'datatype' => 'int',
@@ -64,7 +56,7 @@ function _searchlight_basic_searchlight_default_datasources() {
'table' => 'users',
'field' => 'name',
'name' => 'users_name',
- 'usage' => 'attribute',
+ 'usage' => 'content',
),
'users_uid' => array(
'label' => 'User: Name (uid)',
@@ -82,6 +74,22 @@ function _searchlight_basic_searchlight_default_datasources() {
'name' => 'node_type',
'usage' => 'attribute',
),
+ 'field_data_body_entity_id' => array(
+ 'label' => 'Fields: body (entity_id)',
+ 'datatype' => 'int',
+ 'table' => 'field_data_body',
+ 'field' => 'entity_id',
+ 'name' => 'field_data_body_entity_id',
+ 'usage' => 'attribute',
+ ),
+ 'field_data_body_body_value' => array(
+ 'label' => 'Fields: body (body_value)',
+ 'datatype' => 'text',
+ 'table' => 'field_data_body',
+ 'field' => 'body_value',
+ 'name' => 'field_data_body_body_value',
+ 'usage' => 'content',
+ ),
);
$searchlight_datasource->filters = array();
$searchlight_datasource->options = array(
diff --git a/searchlight_basic/searchlight_basic.features.inc b/searchlight_basic/searchlight_basic.features.inc
index 562d2d4..a5e0908 100644
--- a/searchlight_basic/searchlight_basic.features.inc
+++ b/searchlight_basic/searchlight_basic.features.inc
@@ -1,7 +1,7 @@
is_cacheable = FALSE;
$view->api_version = '3.0-alpha1';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
-
-/* Display: Defaults */
+
+ /* Display: Defaults */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['cache']['type'] = 'none';
@@ -77,19 +77,21 @@ function _searchlight_basic_views_default_views() {
$handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['title']['alter']['html'] = 0;
$handler->display->display_options['fields']['title']['link_to_node'] = 1;
- /* Field: Node: Teaser */
- $handler->display->display_options['fields']['teaser']['id'] = 'teaser';
- $handler->display->display_options['fields']['teaser']['table'] = 'node_revisions';
- $handler->display->display_options['fields']['teaser']['field'] = 'teaser';
- $handler->display->display_options['fields']['teaser']['label'] = '';
- $handler->display->display_options['fields']['teaser']['alter']['alter_text'] = 0;
- $handler->display->display_options['fields']['teaser']['alter']['make_link'] = 0;
- $handler->display->display_options['fields']['teaser']['alter']['trim'] = 1;
- $handler->display->display_options['fields']['teaser']['alter']['max_length'] = '150';
- $handler->display->display_options['fields']['teaser']['alter']['word_boundary'] = 1;
- $handler->display->display_options['fields']['teaser']['alter']['ellipsis'] = 1;
- $handler->display->display_options['fields']['teaser']['alter']['strip_tags'] = 1;
- $handler->display->display_options['fields']['teaser']['alter']['html'] = 0;
+ /* Field: Fields: body */
+ $handler->display->display_options['fields']['entity_id']['id'] = 'entity_id';
+ $handler->display->display_options['fields']['entity_id']['table'] = 'field_data_body';
+ $handler->display->display_options['fields']['entity_id']['field'] = 'entity_id';
+ $handler->display->display_options['fields']['entity_id']['alter']['alter_text'] = 0;
+ $handler->display->display_options['fields']['entity_id']['alter']['make_link'] = 0;
+ $handler->display->display_options['fields']['entity_id']['alter']['absolute'] = 0;
+ $handler->display->display_options['fields']['entity_id']['alter']['trim'] = 0;
+ $handler->display->display_options['fields']['entity_id']['alter']['word_boundary'] = 1;
+ $handler->display->display_options['fields']['entity_id']['alter']['ellipsis'] = 1;
+ $handler->display->display_options['fields']['entity_id']['alter']['strip_tags'] = 0;
+ $handler->display->display_options['fields']['entity_id']['alter']['html'] = 0;
+ $handler->display->display_options['fields']['entity_id']['hide_empty'] = 0;
+ $handler->display->display_options['fields']['entity_id']['empty_zero'] = 0;
+
/* Sort criterion: Search: Searchlight */
$handler->display->display_options['sorts']['search']['id'] = 'search';
$handler->display->display_options['sorts']['search']['table'] = 'searchlight';
@@ -108,8 +110,8 @@ function _searchlight_basic_views_default_views() {
$handler->display->display_options['filters']['facets']['id'] = 'facets';
$handler->display->display_options['filters']['facets']['table'] = 'searchlight';
$handler->display->display_options['filters']['facets']['field'] = 'facets';
-
-/* Display: Page: search */
+
+ /* Display: Page: search */
$handler = $view->new_display('page', 'Page: search', 'page_1');
$handler->display->display_options['path'] = 'search';
diff --git a/searchlight_basic/searchlight_basic.info b/searchlight_basic/searchlight_basic.info
index 03fe735..6c99cb8 100644
--- a/searchlight_basic/searchlight_basic.info
+++ b/searchlight_basic/searchlight_basic.info
@@ -1,4 +1,4 @@
-core = "6.x"
+core = 7.x
dependencies[] = "searchlight"
description = "Basic default configuration for Searchlight indexing and views."
features[ctools][] = "searchlight_datasource"
@@ -8,3 +8,12 @@ features[searchlight_environment][] = "search_node"
features[views][] = "search_node"
name = "Searchlight basic"
package = "Search"
+
+
+
+
+
+files[] = searchlight_basic.defaults.inc
+files[] = searchlight_basic.features.inc
+files[] = searchlight_basic.features.views.inc
+files[] = searchlight_basic.module
diff --git a/theme/searchlight-admin-datasource.tpl.php b/theme/searchlight-admin-datasource.tpl.php
index 801c79c..6421834 100644
--- a/theme/searchlight-admin-datasource.tpl.php
+++ b/theme/searchlight-admin-datasource.tpl.php
@@ -1,5 +1,5 @@
-
+
@@ -18,5 +18,5 @@
-
-
\ No newline at end of file
+
+
diff --git a/theme/searchlight-admin-environment.tpl.php b/theme/searchlight-admin-environment.tpl.php
index caa2aff..18c579a 100644
--- a/theme/searchlight-admin-environment.tpl.php
+++ b/theme/searchlight-admin-environment.tpl.php
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
+
+
diff --git a/theme/searchlight-solr-config.tpl.php b/theme/searchlight-solr-config.tpl.php
index 628f203..71b0f6a 100644
--- a/theme/searchlight-solr-config.tpl.php
+++ b/theme/searchlight-solr-config.tpl.php
@@ -31,6 +31,15 @@
+
+
+
+
+ standard
+ solrpingquery
+ all
+
+
diff --git a/theme/searchlight.theme.inc b/theme/searchlight.theme.inc
index 5d5ff93..4273bb3 100644
--- a/theme/searchlight.theme.inc
+++ b/theme/searchlight.theme.inc
@@ -25,11 +25,11 @@ function template_preprocess_searchlight_solr_schema(&$vars) {
$defaults = array(
'indexed' => 'true',
'stored' => 'true',
- 'multiValued' => 'false'
+ 'multiValued' => 'false',
);
- foreach($vars['datasource']['schema'] as $id => $field) {
+ foreach ($vars['datasource']['schema'] as $id => $field) {
// Populate defaults.
- foreach($defaults as $k => $v) {
+ foreach ($defaults as $k => $v) {
if (!isset($field[$k])) {
$vars['datasource']['schema'][$id][$k] = $v;
}
@@ -47,7 +47,7 @@ function template_preprocess_searchlight_solr_schema(&$vars) {
* Theme function for searchlight global search form.
* As this is a GET form, FormAPI related data can be excluded.
*/
-function theme_searchlight_search_form($form) {
+function theme_searchlight_search_form() {
$output = '';
foreach (element_children($form) as $key) {
if (!in_array($key, array('form_build_id', 'form_token', 'form_id'))) {
@@ -60,7 +60,9 @@ function theme_searchlight_search_form($form) {
/**
* Theme function for searchlight datasource display form.
*/
-function theme_searchlight_plugin_display_datasource($form) {
+function theme_searchlight_plugin_display_datasource($variables) {
+ $variables = $variables['form'];
+ $form = $variables['form'];
$output = '';
$rows = array();
foreach (element_children($form) as $key) {
@@ -68,27 +70,36 @@ function theme_searchlight_plugin_display_datasource($form) {
$row[] = $form[$key]['#title'];
foreach (element_children($form[$key]) as $cell) {
if (isset($form[$key][$cell]['#type']) && !in_array($form[$key][$cell]['#type'], array('hidden', 'value'))) {
- $row[] = drupal_render($form[$key][$cell]);
+ $row[] = drupal_render_children($form[$key][$cell]);
}
}
$rows[] = $row;
}
- $output = theme('table', array(t('Field'), t('Datatype'), t('Usage'), t('Show facet'), ''), $rows);
- $output .= drupal_render($form);
+ $output = theme('table', array('header' => array(t('Field'), t('Datatype'), t('Usage'), t('Show facet'), ''),
+ 'rows' => $rows,
+ ));
+ $output .= drupal_render_children($form);
return $output;
}
/**
* Theme function for a facet.
*/
-function theme_searchlight_facet($facet) {
- return theme('item_list', $facet['items'], $facet['label'], 'ul', array('class' => 'searchlight-facet-'. $facet['delta']));
+function theme_searchlight_facet($variables) {
+ $facet = $variables['facet'];
+ return theme('item_list', array(
+ 'items' => $facet['items'],
+ 'title' => $facet['label'],
+ 'type' => 'ul',
+ 'attributes' => array('class' => array('searchlight-facet-' . $facet['delta'])),
+ ));
}
/**
* Theme function for an individual (inactive) facet link.
*/
-function theme_searchlight_facet_link($field, $item) {
+function theme_searchlight_facet_link($variables) {
+ $item = $variables['item'];
$class = isset($item['class']) ? $item['class'] : '';
return "{$item['link']} {$item['count']}
";
}
@@ -96,23 +107,30 @@ function theme_searchlight_facet_link($field, $item) {
/**
* Theme function for an individual (active) facet link.
*/
-function theme_searchlight_facet_active($field, $item) {
+function theme_searchlight_facet_active($variables) {
+ $item = $variables['item'];
$class = isset($item['class']) ? $item['class'] : '';
- return "{$item['title']} {$item['link']}
";
+ $title = check_plain($item['title']);
+ return "{$title} {$item['link']}
";
}
/**
* Generates the main datasource admin page.
*/
-function theme_searchlight_admin_list($form) {
- drupal_add_css(drupal_get_path("module", "searchlight") ."/searchlight.admin.css");
+function theme_searchlight_admin_list($variables) {
+ $form = $variables['form'];
+ drupal_add_css(drupal_get_path("module", "searchlight") . "/searchlight.admin.css");
$rows = array();
// Generate listing of existing objects
foreach ($form['#objects'] as $group => $objects) {
if (!empty($group)) {
- $rows[] = array(array('data' => check_plain($group), 'colspan' => 4, 'header' => TRUE));
+ $rows[] = array(array(
+ 'data' => check_plain($group),
+ 'colspan' => 4,
+ 'header' => TRUE,
+ ),);
}
foreach ($objects as $object) {
if ($object instanceof SearchlightDatasource) {
@@ -122,7 +140,7 @@ function theme_searchlight_admin_list($form) {
$name_label = t('Active datasource');
$extra_label = t('Base table');
}
- else if ($object instanceof SearchlightEnvironment) {
+ elseif ($object instanceof SearchlightEnvironment) {
$extra = $object->view_display;
$type = 'environment';
$path = 'environment';
@@ -141,73 +159,124 @@ function theme_searchlight_admin_list($form) {
if ($type === 'datasource') {
$row[] = array(
'data' => drupal_render($form['active'][$object->base_table][$object->name]),
- 'class' => 'object-name',
+ 'class' => array('object-name'),
);
}
else {
- $row[] = array('data' => $object->name, 'class' => 'object-name');
+ $row[] = array(
+ 'data' => $object->name,
+ 'class' => array('object-name'),
+ );
}
- $row[] = array('data' => $extra, 'class' => 'object-extra');
- $row[] = array('data' => $storage, 'class' => 'object-storage');
+ $row[] = array(
+ 'data' => $extra,
+ 'class' => array('object-extra'),
+ );
+ $row[] = array(
+ 'data' => $storage,
+ 'class' => array('object-storage'),
+ );
// Actions
$links = array(
- 'edit' => l(t('Edit'), "admin/settings/search/{$path}/list/{$object->name}"),
- 'delete' => l(t('Delete'), "admin/settings/search/{$path}/list/{$object->name}/delete"),
- 'revert' => l(t('Revert'), "admin/settings/search/{$path}/list/{$object->name}/revert"),
+ 'edit' => l(t('Edit'), "admin/config/search/settings/{$path}/{$object->name}"),
+ 'delete' => l(t('Delete'), "admin/config/search/settings/{$path}/{$object->name}/delete"),
+ 'revert' => l(t('Revert'), "admin/config/search/settings/{$path}/{$object->name}/revert"),
);
foreach (array_keys($links) as $key) {
if (!searchlight_task_access($object, $key)) {
unset($links[$key]);
}
}
- $row[] = array('data' => implode(' | ', $links), 'class' => 'object-links');
+ $row[] = array(
+ 'data' => implode(' | ', $links),
+ 'class' => array('object-links'),
+ );
$rows[] = $row;
}
}
$row = array();
foreach (element_children($form['new']) as $key) {
if ($form['new'][$key]['#type'] === 'submit') {
- $row[] = array('data' => drupal_render($form['new'][$key]), 'colspan' => 2);
+ $row[] = array(
+ 'data' => drupal_render($form['new'][$key]),
+ 'colspan' => 2,
+ );
}
else {
$row[] = drupal_render($form['new'][$key]);
}
}
$rows[] = $row;
- $output = theme('table', array($name_label, $extra_label, t('Storage'), t('Operations')), $rows, array('class' => 'object-admin'));
- $output .= drupal_render($form);
+ $output = theme('table', array(
+ 'header' => isset($name_label) ? array($name_label, $extra_label, t('Storage'), t('Operations')) : array(),
+ 'rows' => $rows,
+ 'attributes' => array(
+ 'class' => array('object-admin'),
+ ),
+ ));
+ $output .= drupal_render_children($form);
return $output;
}
/**
* Theme function for searchlight datasource display form.
*/
-function theme_searchlight_admin_datasource_fields($form) {
+function theme_searchlight_admin_datasource_fields($variables) {
+// $variables = $variables['form'];
+ $form = $variables['form'];
$output = '';
$rows = array();
+ drupal_add_js('misc/tableselect.js');
// New fields header.
if (!empty($form['new'])) {
- $rows[] = array(array('data' => t('Add field'), 'colspan' => 4, 'header' => TRUE));
+ $rows[] = array(array(
+ 'data' => t('Add field'),
+ 'colspan' => 5,
+ 'header' => TRUE,
+ ),);
$rows[] = array(
- array('data' => drupal_render($form['new']['field']), 'colspan' => 3),
+ array(
+ 'data' => drupal_render($form['new']['field']),
+ 'colspan' => 4,
+ ),
array('data' => drupal_render($form['new']['add'])),
);
}
-
// Existing fields.
+ // TODO Please change this theme call to use an associative array for the
+ // $variables parameter.
$rows[] = array(
- theme('table_select_header_cell') + array('header' => TRUE),
- array('data' => t('Field'), 'header' => TRUE),
- array('data' => t('Datatype'), 'header' => TRUE),
- array('data' => t('Usage'), 'header' => TRUE)
+ array(
+ 'class' => array('select-all'),
+ 'header' => TRUE,
+ ),
+ array(
+ 'data' => t('Relation'),
+ 'header' => TRUE,
+ ),
+ array(
+ 'data' => t('Field'),
+ 'header' => TRUE,
+ ),
+ array(
+ 'data' => t('Datatype'),
+ 'header' => TRUE,
+ ),
+ array(
+ 'data' => t('Usage'),
+ 'header' => TRUE,
+ ),
);
foreach (element_children($form['fields']) as $key) {
if ($key !== 'new') {
$row = array();
foreach (element_children($form['fields'][$key]) as $cell) {
- if (isset($form['fields'][$key][$cell]['#type']) && !in_array($form['fields'][$key][$cell]['#type'], array('hidden', 'value'))) {
+ if (isset($form['fields'][$key][$cell]['#markup']) ||
+ (isset($form['fields'][$key][$cell]['#type']) &&
+ !in_array($form['fields'][$key][$cell]['#type'], array('hidden', 'value')))) {
+
$row[] = drupal_render($form['fields'][$key][$cell]);
}
}
@@ -215,25 +284,118 @@ function theme_searchlight_admin_datasource_fields($form) {
}
}
if (!element_children($form['fields'])) {
- $rows[] = array(array('data' => t('No fields found.'), 'colspan' => 4));
+ $rows[] = array(array(
+ 'data' => t('No fields found.'),
+ 'colspan' => 5,
+ ),);
+ }
+ // Remove fields footer.
+ if (!empty($form['remove'])) {
+ $rows[] = array(array(
+ 'data' => drupal_render($form['remove']),
+ 'colspan' => 5,
+ 'header' => TRUE,
+ ),);
}
+ $output = theme('table', array(
+ 'header' => array(),
+ 'rows' => $rows,
+ 'attributes' => array(),
+ 'caption' => $form['#title'],
+ ));
+
+ $output .= drupal_render_children($form);
+
+ return $output;
+}
+
+/**
+ * Theme function for searchlight datasource display form.
+ */
+function theme_searchlight_admin_datasource_relations($variables) {
+ $form = $variables['form'];
+ $output = '';
+ $rows = array();
+ drupal_add_js('misc/tableselect.js');
+
+ // New fields header.
+ if (!empty($form['new'])) {
+ $rows[] = array(array(
+ 'data' => t('Add relation'),
+ 'colspan' => 3,
+ 'header' => TRUE,
+ ),);
+ $rows[] = array(
+ array(
+ 'data' => drupal_render($form['new']['relation']),
+ 'colspan' => 2,
+ ),
+ array('data' => drupal_render($form['new']['add'])),
+ );
+ }
+ // Existing fields.
+ // TODO Please change this theme call to use an associative array for the
+ // $variables parameter.
+ $rows[] = array(
+ array(
+ 'class' => array('select-all'),
+ 'header' => TRUE,
+ ),
+ array(
+ 'data' => t('Relation'),
+ 'header' => TRUE,
+ ),
+ array(
+ 'data' => t('Required'),
+ 'header' => TRUE,
+ ),
+ );
+ foreach (element_children($form['relations']) as $key) {
+ if ($key !== 'new') {
+ $row = array();
+ foreach (element_children($form['relations'][$key]) as $cell) {
+ if (isset($form['relations'][$key][$cell]['#markup']) ||
+ (isset($form['relations'][$key][$cell]['#type']) &&
+ !in_array($form['relations'][$key][$cell]['#type'], array('hidden', 'value')))) {
+
+ $row[] = drupal_render($form['relations'][$key][$cell]);
+ }
+ }
+ $rows[] = $row;
+ }
+ }
+ if (!element_children($form['relations'])) {
+ $rows[] = array(array(
+ 'data' => t('No relations found.'),
+ 'colspan' => 3,
+ ),);
+ }
// Remove fields footer.
if (!empty($form['remove'])) {
- $rows[] = array(array('data' => drupal_render($form['remove']), 'colspan' => 4, 'header' => TRUE));
+ $rows[] = array(array(
+ 'data' => drupal_render($form['remove']),
+ 'colspan' => 3,
+ 'header' => TRUE,
+ ),);
}
- $output = theme('table', array(), $rows, array(), $form['#title']);
- $output .= drupal_render($form);
+ $output = theme('table', array(
+ 'header' => array(),
+ 'rows' => $rows,
+ 'attributes' => array(),
+ 'caption' => $form['#title'],
+ ));
+
+ $output .= drupal_render_children($form);
+
return $output;
}
/**
* Preprocessor for theme('searchlight_admin_environment').
*/
-function template_preprocess_searchlight_admin_environment($vars) {
- drupal_add_js(drupal_get_path('module', 'searchlight') .'/searchlight.admin.js');
- drupal_add_css(drupal_get_path("module", "searchlight") ."/searchlight.admin.css");
+function template_preprocess_searchlight_admin_environment(&$vars) {
drupal_add_tabledrag('searchlight-environment', 'order', 'sibling', 'searchlight-environment-weight', NULL, NULL, TRUE);
// Basic environment info.
@@ -245,8 +407,14 @@ function template_preprocess_searchlight_admin_environment($vars) {
$facets = '';
$rows = array();
$rows[] = array(
- array('data' => drupal_render($vars['form']['view_display']['view_display']), 'colspan' => 3),
- array('data' => drupal_render($vars['form']['view_display']['update']), 'colspan' => 3),
+ array(
+ 'data' => drupal_render($vars['form']['view_display']['view_display']),
+ 'colspan' => 3,
+ ),
+ array(
+ 'data' => drupal_render($vars['form']['view_display']['update']),
+ 'colspan' => 3,
+ ),
);
// Build facets table.
@@ -261,7 +429,10 @@ function template_preprocess_searchlight_admin_environment($vars) {
// Handle element title as table header.
if (empty($header_row[$cell])) {
$header_cell = !empty($vars['form']['facets'][$key][$cell]['#title']) ? check_plain($vars['form']['facets'][$key][$cell]['#title']) : '';
- $header_row[$cell] = array('data' => $header_cell, 'header' => TRUE);
+ $header_row[$cell] = array(
+ 'data' => $header_cell,
+ 'header' => TRUE,
+ );
}
if (isset($vars['form']['facets'][$key][$cell]['#title'])) {
unset($vars['form']['facets'][$key][$cell]['#title']);
@@ -269,7 +440,7 @@ function template_preprocess_searchlight_admin_environment($vars) {
// Handling for specific elements.
switch ($cell) {
case 'weight':
- $vars['form']['facets'][$key][$cell]['#attributes']['class'] = 'searchlight-environment-weight';
+ $vars['form']['facets'][$key][$cell]['#attributes']['class'] = array('searchlight-environment-weight');
$row[] = drupal_render($vars['form']['facets'][$key][$cell]);
break;
case 'settings':
@@ -277,7 +448,7 @@ function template_preprocess_searchlight_admin_environment($vars) {
$element_settings_id = "searchlight-facet-{$key}";
if (!empty($element_settings)) {
$element_settings_form = "";
- $element_settings_form .= l(t('Edit'), $_GET['q'], array('attributes' => array('class' => 'environment-settings-link'), 'fragment' => $element_settings_id));
+ $element_settings_form .= l(t('Edit'), $_GET['q'], array( 'attributes' => array('class' => array('environment-settings-link')),'fragment' => $element_settings_id));
$element_settings_form .= "
{$element_settings}
";
$element_settings_form .= "
";
$row[] = $element_settings_form;
@@ -291,14 +462,20 @@ function template_preprocess_searchlight_admin_environment($vars) {
break;
}
}
- $facet_rows[] = array('data' => $row, 'class' => 'draggable');
+ $facet_rows[] = array(
+ 'data' => $row,
+ 'class' => array('draggable'),
+ );
}
$rows[] = $header_row;
$rows = array_merge($rows, $facet_rows);
-
// Facet table.
- $facets .= theme('table', array(), $rows, array('id' => 'searchlight-environment'));
+ $facets .= theme('table', array(
+ 'header' => array(),
+ 'rows' => $rows,
+ 'attributes' => array('id' => 'searchlight-environment'),
+ ));
$vars['facets'] = $facets;
// Per-facet settings.
@@ -308,8 +485,8 @@ function template_preprocess_searchlight_admin_environment($vars) {
/**
* Preprocessor for theme('searchlight_admin_datasource').
*/
-function template_preprocess_searchlight_admin_datasource($vars) {
- drupal_add_css(drupal_get_path("module", "searchlight") ."/searchlight.admin.css");
+function template_preprocess_searchlight_admin_datasource(&$vars) {
+ drupal_add_css(drupal_get_path("module", "searchlight") . "/searchlight.admin.css");
$datasource = $vars['form']['#datasource'];
$base_tables = views_fetch_base_tables();
diff --git a/views/searchlight.views.inc b/views/searchlight.views.inc
index ac86cb0..62cbf57 100644
--- a/views/searchlight.views.inc
+++ b/views/searchlight.views.inc
@@ -1,25 +1,15 @@
searchlight)) {
- $query->build($view);
- $query->execute($view);
- }
-}
/**
- * Implementation of hook_views_plugins().
+ * Implements hook_views_plugins().
*/
function searchlight_views_plugins() {
return array(
'query' => array(
'searchlight' => array(
- 'file' => (views_api_version() == '2.0') ? 'searchlight_plugin_query_v2.inc' : 'searchlight_plugin_query_v3.inc',
+ 'file' => 'searchlight_plugin_query_v3.inc',
'path' => drupal_get_path('module', 'searchlight') . '/views',
'title' => t('Searchlight'),
'help' => t('Searchlight query plugin.'),
@@ -57,11 +47,11 @@ function searchlight_views_plugins() {
}
/**
- * Implementation of hook_views_handlers().
+ * Implements hook_views_handlers().
*/
function searchlight_views_handlers() {
return array(
- 'info' => array('path' => drupal_get_path('module', 'searchlight') .'/views'),
+ 'info' => array('path' => drupal_get_path('module', 'searchlight') . '/views'),
'handlers' => array(
'searchlight_handler_argument_search' => array('parent' => 'views_handler_argument'),
'searchlight_handler_filter_search' => array('parent' => 'views_handler_filter'),
@@ -74,7 +64,7 @@ function searchlight_views_handlers() {
}
/**
- * Implementation of hook_views_data().
+ * Implements hook_views_data().
*/
function searchlight_views_data() {
$data = array();
@@ -103,7 +93,7 @@ function searchlight_views_data() {
}
/**
- * Implementation of hook_views_data_alter().
+ * Implements hook_views_data_alter().
*/
function searchlight_views_data_alter(&$data) {
if (!empty($data['node_access']['nid']) && empty($data['node_access']['nid']['field'])) {
@@ -113,11 +103,27 @@ function searchlight_views_data_alter(&$data) {
);
}
+ // A special handler for taxonomy_index table. Taxonomy views integration
+ // in D7 sometimes makes use of `taxonomy_term_data` but when used for
+ // arguments, filters, etc. directly queries against `taxonomy_index`.
+ if (module_exists('taxonomy')) {
+ $data['taxonomy_index']['searchlight_tid'] = array(
+ 'title' => t('Term ID (Searchlight)'),
+ 'help' => t('The taxonomy term ID'),
+ 'real field' => 'tid',
+ 'field' => array(
+ 'field' => 'tid',
+ 'handler' => 'views_handler_field_numeric',
+ 'click sortable' => TRUE,
+ ),
+ );
+ }
+
// OG UID field handler. Needed to allow filtering directly against OG UID.
if (module_exists('og_views')) {
$data['og_uid']['nid']['field'] = array(
'title' => t('Group ID'),
- 'handler' => 'views_handler_field'
+ 'handler' => 'views_handler_field',
);
}
@@ -163,15 +169,16 @@ function searchlight_views_init_query(&$view) {
// Check that an active datasource can be found for this base table.
if (searchlight_get_datasource($view->base_table)) {
// Add Searchlight JS.
- drupal_add_js(drupal_get_path('module', 'searchlight') .'/searchlight.js');
+ drupal_add_js(drupal_get_path('module', 'searchlight') . '/searchlight.js');
- $view->query = searchlight_get_query($view->base_table, $view->base_field);
+ $query_options = $view->display_handler->get_option('query');
+ $view->query = searchlight_get_query($view->base_table, $view->base_field, $query_options['options']);
}
}
}
/**
- * Implementation of hook_views_default_views().
+ * Implements hook_views_default_views().
*/
function searchlight_views_default_views() {
$views = array();
@@ -181,7 +188,7 @@ function searchlight_views_default_views() {
//
$realms = array();
$result = db_query("SELECT realm FROM {node_access} GROUP BY realm");
- while ($row = db_fetch_object($result)) {
+ foreach ($result as $row) {
$realms[$row->realm] = $row->realm;
}
// Allow modules to declare their realms in an alter hook. This allows
@@ -236,12 +243,44 @@ function searchlight_views_default_views() {
$view->base_table = 'node';
$view->api_version = '3.0-alpha1';
$handler = $view->new_display('default', 'Default', 'default');
+ /* Display: All terms */
+ $handler = $view->new_display('searchlight_multivalue', 'all', 'searchlight_multivalue_all');
+ $handler->override_option('arguments', array());
+ $handler->override_option('relationships', array());
+ $handler->override_option('sorts', array());
+ $handler->override_option('fields', array(
+ 'nid' => array(
+ 'id' => 'nid',
+ 'table' => 'node',
+ 'field' => 'nid',
+ 'relationship' => 'none',
+ ),
+ 'seachlight_tid' => array(
+ 'id' => 'searchlight_tid',
+ 'table' => 'taxonomy_index',
+ 'field' => 'searchlight_tid',
+ 'relationship' => 'none',
+ 'label' => t('Term ID'),
+ ),
+ 'name' => array(
+ 'id' => 'name',
+ 'table' => 'taxonomy_term_data',
+ 'field' => 'name',
+ 'relationship' => 'none',
+ 'label' => t('All terms'),
+ ),
+ ));
+ $handler->override_option('searchlight_multivalue', array(
+ 'field' => 'taxonomy_index_tid',
+ 'label_field' => 'taxonomy_term_data_name',
+ 'override' => array(
+ 'name' => 'taxonomy_index_tid',
+ 'label' => t('Taxonomy (all)'),
+ ),
+ ));
foreach (taxonomy_get_vocabularies() as $vocab) {
- $identifier = !empty($vocab->module) && $vocab->module !== 'taxonomy' ? $vocab->module : $vocab->vid;
- $identifier = strtr($identifier, ' -:', '___');
-
/* Display: Vocabulary */
- $handler = $view->new_display('searchlight_multivalue', $vocab->name, 'searchlight_multivalue_'. $identifier);
+ $handler = $view->new_display('searchlight_multivalue', $vocab->name, 'searchlight_multivalue_' . $vocab->machine_name);
$handler->override_option('arguments', array());
$handler->override_option('relationships', array());
$handler->override_option('sorts', array());
@@ -252,43 +291,34 @@ function searchlight_views_default_views() {
'field' => 'nid',
'relationship' => 'none',
),
+ 'seachlight_tid' => array(
+ 'id' => 'searchlight_tid',
+ 'table' => 'taxonomy_index',
+ 'field' => 'searchlight_tid',
+ 'relationship' => 'none',
+ 'label' => t('Term ID'),
+ ),
'name' => array(
'id' => 'name',
- 'table' => 'term_data',
+ 'table' => 'taxonomy_term_data',
'field' => 'name',
'relationship' => 'none',
'label' => $vocab->name,
),
));
-
- // If Views can handle the Taxonomy vocab module field for supporting
- // exportable vocabularies, use it.
- $data = views_fetch_data('vocabulary');
- if (isset($data['module']) && !is_numeric($identifier)) {
- $handler->override_option('filters', array(
- 'module' => array(
- 'id' => 'module',
- 'table' => 'vocabulary',
- 'field' => 'module',
- 'value' => array($vocab->module => $vocab->module),
- ),
- ));
- }
- else {
- $handler->override_option('filters', array(
- 'vid' => array(
- 'id' => 'vid',
- 'table' => 'term_data',
- 'field' => 'vid',
- 'value' => array($vocab->vid => $vocab->vid),
- ),
- ));
- }
+ $handler->override_option('filters', array(
+ 'machine_name' => array(
+ 'id' => 'machine_name',
+ 'table' => 'taxonomy_vocabulary',
+ 'field' => 'machine_name',
+ 'value' => array($vocab->machine_name => $vocab->machine_name),
+ ),
+ ));
$handler->override_option('searchlight_multivalue', array(
- 'field' => 'term_data_tid',
- 'label_field' => 'term_data_name',
+ 'field' => 'taxonomy_index_tid',
+ 'label_field' => 'taxonomy_term_data_name',
'override' => array(
- 'name' => 'term_data_tid_'. $identifier,
+ 'name' => 'taxonomy_index_tid_' . $vocab->machine_name,
'label' => $vocab->name,
),
));
@@ -296,214 +326,5 @@ function searchlight_views_default_views() {
$views[$view->name] = $view;
}
- //
- // Content profile ==========================================================
- //
- if (module_exists('content_profile')) {
- $view = new view;
- $view->name = 'searchlight_content_profile';
- $view->tag = 'searchlight';
- $view->base_table = 'users';
- $view->api_version = '3.0-alpha1';
- $handler = $view->new_display('default', 'Default', 'default');
- foreach(array_keys(content_profile_get_types()) as $profile_type) {
- foreach (taxonomy_get_vocabularies() as $vocab) {
- if (isset($vocab->nodes[$profile_type])) {
- $identifier = !empty($vocab->module) && $vocab->module !== 'taxonomy' ? $vocab->module : $vocab->vid;
- $identifier = strtr($identifier, ' -:', '___');
-
- /* Display: Vocabulary */
- $handler = $view->new_display('searchlight_multivalue', "{$profile_type}: {$vocab->name}", "searchlight_multivalue_{$profile_type}_{$identifier}");
- $handler->override_option('arguments', array());
- $handler->override_option('sorts', array());
- $handler->override_option('relationships', array(
- 'content_profile_rel' => array(
- 'required' => 1,
- 'type' => $profile_type,
- 'id' => 'content_profile_rel',
- 'table' => 'users',
- 'field' => 'content_profile_rel',
- 'relationship' => 'none',
- ),
- ));
- $handler->override_option('fields', array(
- 'uid' => array(
- 'id' => 'uid',
- 'table' => 'users',
- 'field' => 'uid',
- 'relationship' => 'none',
- ),
- 'name' => array(
- 'id' => 'name',
- 'table' => 'term_data',
- 'field' => 'name',
- 'relationship' => 'content_profile_rel',
- 'label' => $vocab->name,
- ),
- ));
-
- // If Views can handle the Taxonomy vocab module field for supporting
- // exportable vocabularies, use it.
- $data = views_fetch_data('vocabulary');
- if (isset($data['module']) && !is_numeric($identifier)) {
- $handler->override_option('filters', array(
- 'module' => array(
- 'id' => 'module',
- 'table' => 'vocabulary',
- 'field' => 'module',
- 'value' => array($vocab->module => $vocab->module),
- 'relationship' => 'content_profile_rel',
- ),
- ));
- }
- else {
- $handler->override_option('filters', array(
- 'vid' => array(
- 'id' => 'vid',
- 'table' => 'term_data',
- 'field' => 'vid',
- 'value' => array($vocab->vid => $vocab->vid),
- 'relationship' => 'content_profile_rel',
- ),
- ));
- }
- $handler->override_option('searchlight_multivalue', array(
- 'field' => 'node_users__term_data_tid',
- 'label_field' => 'node_users__term_data_name',
- 'override' => array(
- 'name' => "term_data_tid_{$profile_type}_{$identifier}",
- 'label' => $vocab->name,
- ),
- ));
- }
- }
- }
- $views[$view->name] = $view;
- }
-
- //
- // Organic Groups ===========================================================
- //
- if (module_exists('og_views')) {
- $view = new view;
- $view->name = 'searchlight_og_ancestry';
- $view->tag = 'searchlight';
- $view->base_table = 'node';
- $view->api_version = '3.0-alpha1';
- $handler = $view->new_display('default', 'Default', 'default');
-
- /* Display: Node's groups */
- $handler = $view->new_display('searchlight_multivalue', 'Organic Groups', 'searchlight_multivalue_og');
- $handler->override_option('arguments', array());
- $handler->override_option('sorts', array());
- $handler->override_option('relationships', array(
- 'group_nid' => array(
- 'required' => 1,
- 'id' => 'group_nid',
- 'table' => 'og_ancestry',
- 'field' => 'group_nid',
- 'relationship' => 'none',
- ),
- ));
- $handler->override_option('fields', array(
- 'nid' => array(
- 'id' => 'nid',
- 'table' => 'node',
- 'field' => 'nid',
- 'relationship' => 'none',
- ),
- 'title' => array(
- 'id' => 'title',
- 'table' => 'node',
- 'field' => 'title',
- 'label' => 'Groups',
- 'relationship' => 'group_nid',
- ),
- ));
- $handler->override_option('searchlight_multivalue', array(
- 'field' => 'node_og_ancestry_nid',
- 'label_field' => 'node_og_ancestry_title',
- 'override' => array(
- 'label' => 'Organic Groups',
- 'table' => 'og_ancestry',
- 'name' => 'group_nid',
- ),
- ));
- $views[$view->name] = $view;
-
- $view = new view;
- $view->name = 'searchlight_og_uid';
- $view->tag = 'searchlight';
- $view->base_table = 'users';
- $view->api_version = '3.0-alpha1';
- $handler = $view->new_display('default', 'Default', 'default');
-
- /* Display: User's groups */
- $handler = $view->new_display('searchlight_multivalue', 'Organic Groups', 'searchlight_multivalue_og');
- $handler->override_option('arguments', array());
- $handler->override_option('sorts', array());
- $handler->override_option('relationships', array(
- 'nid' => array(
- 'required' => 1,
- 'id' => 'nid',
- 'table' => 'og_uid',
- 'field' => 'nid',
- 'relationship' => 'none',
- ),
- ));
- $handler->override_option('fields', array(
- 'uid' => array(
- 'id' => 'uid',
- 'table' => 'users',
- 'field' => 'uid',
- 'relationship' => 'none',
- ),
- 'title' => array(
- 'id' => 'title',
- 'table' => 'node',
- 'field' => 'title',
- 'label' => 'Groups',
- 'relationship' => 'nid',
- ),
- ));
- $handler->override_option('searchlight_multivalue', array(
- 'field' => 'node_og_uid_nid',
- 'label_field' => 'node_og_uid_title',
- 'override' => array(
- 'label' => 'Organic Groups',
- 'table' => 'og_uid',
- 'name' => 'nid',
- ),
- ));
-
- /* Display: User's groups */
- $handler = $view->new_display('searchlight_multivalue', 'Organic Groups (filter)', 'searchlight_multivalue_og_uid');
- $handler->override_option('arguments', array());
- $handler->override_option('sorts', array());
- $handler->override_option('relationships', array());
- $handler->override_option('fields', array(
- 'uid' => array(
- 'id' => 'uid',
- 'table' => 'users',
- 'field' => 'uid',
- 'relationship' => 'none',
- ),
- 'nid' => array(
- 'id' => 'nid',
- 'table' => 'og_uid',
- 'field' => 'nid',
- 'label' => 'Groups',
- ),
- ));
- $handler->override_option('searchlight_multivalue', array(
- 'field' => 'og_uid_nid',
- 'label_field' => 'og_uid_nid',
- 'override' => array(
- 'label' => 'Organic Groups (nid)',
- ),
- ));
- $views[$view->name] = $view;
- }
-
return $views;
}
diff --git a/views/searchlight_handler_field_facet_link.inc b/views/searchlight_handler_field_facet_link.inc
index c94ece0..981fd54 100644
--- a/views/searchlight_handler_field_facet_link.inc
+++ b/views/searchlight_handler_field_facet_link.inc
@@ -1,15 +1,18 @@
array(0 => '---') + drupal_map_assoc(array_keys($this->get_render_tokens(array()))),
'#default_value' => $this->options['field_token'],
);
+ $form['text_token'] = array(
+ '#title' => t('Display as link'),
+ '#type' => 'select',
+ '#options' => array(0 => '---') + drupal_map_assoc(array_keys($this->get_render_tokens(array()))),
+ '#default_value' => $this->options['text_token'],
+ );
$form['absolute'] = array(
'#title' => t('Absolute URL'),
'#type' => 'checkbox',
'#default_value' => $this->options['absolute'],
);
+ $form['exclude'] = array(
+ '#title' => t('Exclude this field'),
+ '#type' => 'checkbox',
+ '#default_value' => $this->options['exclude'],
+ );
}
function render($values) {
@@ -52,7 +66,13 @@ class searchlight_handler_field_facet_link extends views_handler_field {
$path = $environment->getURLPath();
$options = $environment->getURLOptions('add', $facet, $tokens[$this->options['field_token']]);
$options['absolute'] = $this->options['absolute'];
- return url($path, $options);
+ // TODO The second parameter to this function call should be an array.
+ if (!empty($this->options['text_token'])) {
+ return l(check_plain($tokens[$this->options['text_token']]), $path, $options);
+ }
+ else {
+ return url($path, $options);
+ }
}
}
return '';
diff --git a/views/searchlight_handler_field_node_access.inc b/views/searchlight_handler_field_node_access.inc
index 4b0a33b..3ff2f98 100644
--- a/views/searchlight_handler_field_node_access.inc
+++ b/views/searchlight_handler_field_node_access.inc
@@ -11,10 +11,13 @@ class searchlight_handler_field_node_access extends views_handler_field {
parent::options_form($form, $form_state);
$options = array();
$result = db_query("SELECT realm FROM {node_access} GROUP BY realm");
- while ($row = db_fetch_object($result)) {
+ foreach ($result as $row) {
$options[$row->realm] = check_plain($row->realm);
}
- $form['realm'] = array('#type' => 'select', '#options' => $options);
+ $form['realm'] = array(
+ '#type' => 'select',
+ '#options' => $options,
+ );
}
function construct() {
@@ -26,8 +29,8 @@ class searchlight_handler_field_node_access extends views_handler_field {
parent::query();
$table = $this->ensure_my_table();
if (!empty($this->options['realm'])) {
- $this->query->add_where('AND', "$table.realm = '%s'", $this->options['realm']);
- $this->query->add_where('AND', "$table.grant_view >= 1");
+ $this->query->add_where('AND', "$table.realm = '" . $this->options['realm'] . "'", array(), 'formula');
+ $this->query->add_where('AND', "$table.grant_view >= -1", array(), 'formula');
}
}
@@ -42,5 +45,7 @@ class searchlight_handler_field_node_access extends views_handler_field {
}
}
- function allow_advanced_render() { return FALSE; }
+ function allow_advanced_render() {
+ return FALSE;
+ }
}
diff --git a/views/searchlight_handler_filter_facets.inc b/views/searchlight_handler_filter_facets.inc
index a9305c0..0edff8f 100644
--- a/views/searchlight_handler_filter_facets.inc
+++ b/views/searchlight_handler_filter_facets.inc
@@ -21,5 +21,7 @@ class searchlight_handler_filter_facets extends views_handler_filter {
}
}
- function can_expose() { return FALSE; }
+ function can_expose() {
+ return FALSE;
+ }
}
diff --git a/views/searchlight_handler_sort_search.inc b/views/searchlight_handler_sort_search.inc
index 51e4e72..14016c8 100644
--- a/views/searchlight_handler_sort_search.inc
+++ b/views/searchlight_handler_sort_search.inc
@@ -9,9 +9,10 @@ class searchlight_handler_sort_search extends views_handler_sort {
if (isset($this->query->fields['searchlight_weight'])) {
unset($this->query->fields['searchlight_weight']);
- $key = array_search('searchlight_weight '. $this->options['order'], $this->query->orderby);
- if ($key !== FALSE) {
- unset($this->query->orderby[$key]);
+ foreach ($this->query->orderby as $key => $info) {
+ if ($info['field'] == 'searchlight_weight') {
+ unset($this->query->orderby[$key]);
+ }
}
}
}
diff --git a/views/searchlight_plugin_display_multivalue.inc b/views/searchlight_plugin_display_multivalue.inc
index 29f2500..4f338da 100644
--- a/views/searchlight_plugin_display_multivalue.inc
+++ b/views/searchlight_plugin_display_multivalue.inc
@@ -34,20 +34,26 @@ class searchlight_plugin_display_multivalue extends views_plugin_display {
}
}
+ $class = get_class($handler);
+
+ // Allow custom handlers to specity the data_type in definition
+ if (isset($handler->definition['data_type'])) {
+ return $handler->definition['data_type'];
+ }
+
$schema = drupal_get_schema($table);
if ($schema && isset($field, $schema['fields'][$field])) {
- $class = get_class($handler);
// Get the datasource attribute type.
// We use the handler class for special cases like timestamp where DB
// column type is not enough information to determine the usage of the
// field.
$map = array(
- 'serial' => 'int',
- 'int' => 'int',
+ 'serial' => 'int',
+ 'int' => 'int',
'varchar' => 'text',
- 'text' => 'text',
- 'float' => 'float',
+ 'text' => 'text',
+ 'float' => 'float',
);
if (isset($map[$schema['fields'][$field]['type']])) {
$column_type = $map[$schema['fields'][$field]['type']];
@@ -69,7 +75,6 @@ class searchlight_plugin_display_multivalue extends views_plugin_display {
$clone->set_display($this->view->current_display);
$clone->build();
$handlers = $clone->display_handler->get_handlers('field');
-
$fields = array();
foreach ($handlers as $handler) {
if (!empty($handler->relationship) || $handler->real_field !== $handler->view->base_field) {
@@ -91,7 +96,8 @@ class searchlight_plugin_display_multivalue extends views_plugin_display {
$table = isset($info['table']) ? $info['table'] : $table;
$field = $info['field'];
}
- if (!empty($handler->relationship) || $field !== $handler->view->base_field || $table !== $handler->view->base_table) {
+
+ if ((!empty($handler->relationship) || ($field !== $handler->view->base_field) || ($table !== $handler->view->base_table)) && !empty($handler->aliases[$field])) {
$fields[$handler->aliases[$field]] = array(
'label' => $handler->ui_name() . " ({$field})",
'datatype' => $this->get_datatype($handler, $table, $field),
@@ -118,17 +124,29 @@ class searchlight_plugin_display_multivalue extends views_plugin_display {
);
$options = $this->get_option($this->my_name());
$fields = $this->get_fields();
+
foreach ($fields as $name => $info) {
- if ($options['field'] === $name) {
- $info['usage'] = 'multivalue';
- $multivalue = array_merge($multivalue, $info);
- }
- else if ($options['label_field'] === $name) {
+
+// Why should fields without label_field not
+// be added to the multivalue array ????????
+//
+// if ($options['field'] === $name) {
+// $info['usage'] = 'multivalue';
+// $multivalue = array_merge($multivalue, $info);
+// }
+// elseif ($options['label_field'] === $name) {
+// $info['usage'] = 'multivalue';
+// $multivalue['label_field'] = $info;
+// }
+ if ($options['label_field'] === $name) {
$info['usage'] = 'multivalue';
$multivalue['label_field'] = $info;
}
+ else {
+ $info['usage'] = 'multivalue';
+ $multivalue = array_merge($multivalue, $info);
+ }
}
-
// Override explicitly specified properties if available.
if (!empty($options['override'])) {
foreach ($options['override'] as $key => $value) {
@@ -137,13 +155,14 @@ class searchlight_plugin_display_multivalue extends views_plugin_display {
}
}
}
+
return $multivalue;
}
/**
* Override of option_definition().
*/
- function option_definition () {
+ function option_definition() {
$options = parent::option_definition();
$options[$this->my_name()]['field'] = array('default' => NULL);
$options[$this->my_name()]['label_field'] = array('default' => NULL);
diff --git a/views/searchlight_plugin_display_solr.inc b/views/searchlight_plugin_display_solr.inc
index f179d22..a647a5f 100644
--- a/views/searchlight_plugin_display_solr.inc
+++ b/views/searchlight_plugin_display_solr.inc
@@ -3,7 +3,7 @@
class searchlight_plugin_display_solr extends views_plugin_display {
function render() {
$return = array();
- foreach ($this->view->result as $row) {
+ foreach ($this->view->result as $row) {
$render = array();
foreach ($this->view->field as $id => $field) {
$render[$id] = $field->advanced_render($row);
diff --git a/views/searchlight_plugin_query_v2.inc b/views/searchlight_plugin_query_v2.inc
deleted file mode 100644
index 0be88e1..0000000
--- a/views/searchlight_plugin_query_v2.inc
+++ /dev/null
@@ -1,391 +0,0 @@
-pager = new searchlight_plugin_pager($view);
- }
-
- /**
- * Override of init().
- */
- function init($base_table = 'node', $base_field = 'nid', $backend) {
- parent::views_query($base_table, $base_field);
-
- $this->datasource = searchlight_get_datasource($base_table);
- $this->datasource->init();
- $this->datasource_id = $this->datasource->id;
-
- $this->backend = $backend;
- $this->client = $backend->initClient($this->datasource);
-
- $this->search_buildmode = NULL;
- $this->search_facets = array();
- $this->search_filter = array();
- $this->search_options = array();
- $this->search_result = array();
- $this->search_sort = array();
- $this->search_query = '';
-
- // This flag lets others know we are a searchlight-based view.
- $this->searchlight = TRUE;
- }
-
- /**
- * Override of add_where().
- */
- function add_where($group, $clause) {
- $where_args = func_get_args();
- $where_args = $this->get_args($where_args);
-
- // Call the parent method to add the filter SQL side.
- parent::add_where($group, $clause, $where_args);
-
- $split = preg_split('/[ ]([<>=!]*)|(\sIN\s)|(\sIS\s)|(\sNOT IN\s)|(\sIS NOT\s)/i', trim($clause), NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
- if (count($split) >= 2) {
- $field = explode('.', trim(array_shift($split)));
- $operator = strtoupper(trim(array_shift($split)));
- $possible_args = count($split) ? array_shift($split) : '';
- if (count($field) === 2) {
- $table = $field[0];
- $field = $field[1];
- foreach ($this->datasource->fields as $name => $info) {
- if ($name === "{$table}_{$field}") {
- // Get the arguments for this where clause.
- $args = array();
- // If arguments have been specified using query placeholders,
- // simply grab as many as there have been placeholders specified.
- $argnum = substr_count($clause, '%');
- if ($argnum && count($where_args) >= $argnum) {
- $args = array_slice($where_args, 0, $argnum);
- }
- // We may be working with a NULL check...
- elseif ($operator == 'IS' && $possible_args == 'NULL') {
- $operator = 'IN';
- $args[] = 0; // This may only work with numeric fields...
- }
- elseif ($operator == 'IS NOT' && $possible_args == 'NULL') {
- $operator = 'IN';
- $args[] = 1; // This may only work with numeric fields...
- }
- // Otherwise, groan, breath deeply & try to retrieve arguments from
- // the query.
- else {
- $matches = array();
- preg_match_all('/[A-Z*_]*|\w+|\d+/', $possible_args, $matches);
- if (!empty($matches)) {
- foreach ($matches as $match) {
- foreach ($match as $chunk) {
- if ($chunk !== '') {
- $args[] = $chunk;
- }
- }
- }
- }
- }
-
- // Done.
- $this->search_filter[] = array('field' => $name, 'operator' => $operator, 'args' => $args);
- return;
- }
- }
- }
- }
- }
-
- function add_orderby($table, $field, $order, $alias = '', $params = array()) {
- // Call the parent method to add the orderby SQL side.
- parent::add_orderby($table, $field, $order, $alias, $params);
-
- if ($field === 'searchlight_weight') {
- $this->search_sort[] = array('field' => 'searchlight_weight', 'order' => $order); // "@weight {$order}";
- }
- else {
- // Field is aliased. Use query fields to retrieve actual table, field.
- if (!empty($alias) && isset($this->fields[$alias])) {
- $table = $this->fields[$alias]['table'];
- $field = $this->fields[$alias]['field'];
- }
- // Use table field info to retrieve datasource field name and add sort.
- if (isset($table, $field)) {
- foreach ($this->datasource->fields as $name => $info) {
- if ($name === "{$table}_{$field}" && $info['usage'] !== 'content') {
- $this->search_sort[] = array('field' => $name, 'order' => $order); // "{$name} {$order}";
- break;
- }
- }
- }
- // If no table was specified or found, this is probably a function.
- // Use the alias directly if it is available.
- else if (empty($table) && isset($this->datasource->fields[$alias]) && $this->datasource->fields[$alias]['usage'] !== 'content') {
- $this->search_sort[] = array('field' => $alias, 'order' => $order);
- }
- }
- }
-
- function add_search_facet($name, $limit = 5, $options = array()) {
- $this->search_facets[] = array('field' => $name, 'limit' => $limit) + $options;
- }
-
- /**
- * Set the Search build mode behavior.
- *
- * @param string $mode
- * One of the following modes:
- * 'default': Build the Search for facets, etc. but use the View's default
- * result set.
- * 'search': Build the Search for facets, etc. and use the search backend
- * to generate the result set.
- * 'empty': Build the Search for facets, etc. but blank this View's
- * result set.
- * @param boolean $force
- * Force the mode specified. Otherwise, will only set the build mode if no
- * other mode has been set yet.
- */
- function set_search_buildmode($mode = 'default', $force = FALSE) {
- if (!isset($this->search_buildmode) || $force) {
- $this->search_buildmode = $mode;
- }
- }
-
- function set_search_options($options) {
- $this->search_options = $options;
- }
-
- function set_search_query($query) {
- $this->search_query = $query;
- }
-
- function get_search_facet($facet) {
- return isset($this->search_result_facets[$facet]) ? $this->search_result_facets[$facet] : array();
- }
-
- protected function get_args($args, $offset = 2) {
- $args = array_slice($args, $offset);
- if (count($args) == 1 && is_array(reset($args))) {
- return current($args);
- }
- return $args;
- }
-
- function build(&$view) {
- $this->set_search_buildmode();
-
- // Fail the rest of the build entirely if the hideEmpty option is true and
- // there is no search query available. We don't exit right here in order
- // to allow facet queries to run.
- if (empty($this->fields) || $this->search_buildmode === 'empty') {
- parent::add_where(0, "FALSE");
- }
-
- // Views pager initialization.
- if ($this->search_buildmode === 'search') {
- $this->init_pager($view);
- if (!empty($this->pager)) {
- // I'm not sure the consequences of collaping these two tests, nor can
- // I think of a time the pager will be present but use_pager not set
- // however, there are some things better left unknown, lest you end up
- // like the Dwarves in Moria...
- if ($this->pager->use_pager()) {
- $this->pager->set_current_page($view->current_page);
- }
- // Let the pager modify the query to add limits.
- $this->pager->query();
- }
- }
-
- // Views query token replacements.
- $replacements = module_invoke_all('views_query_substitutions', $view);
-
- // Do token replacement against filter fields & args.
- if (!empty($replacements)) {
- foreach ($this->search_filter as $j => $filter) {
- $this->search_filter[$j]['field'] = str_replace(array_keys($replacements), $replacements, $this->search_filter[$j]['field']);
- foreach ($this->search_filter[$j]['args'] as $k => $arg) {
- $this->search_filter[$j]['args'][$k] = str_replace(array_keys($replacements), $replacements, $arg);
- }
- }
- }
-
- // Set backend client options.
- $this->backend->setOptions($this->client, $this->datasource, $this->search_options);
- $this->backend->setSort($this->client, $this->datasource, $this->search_sort);
- $this->backend->setFilter($this->client, $this->datasource, $this->search_filter);
- $this->backend->setPager($this->client, $this->offset, $this->limit);
- if ($this->base_table === 'node' && !user_access('administer nodes') && !empty($this->datasource->options['node_access'])) {
- $this->backend->setNodeAccess($this->client, node_access_grants('view'));
- }
-
- // Main query execution.
- $this->search_result = $this->backend->executeQuery($this->client, $this->datasource, $this->search_query);
-
- // Build facets.
- $this->search_result_facets = $this->backend->facetBuild($this->client, $this->datasource, $this->search_query, $this->search_facets);
-
- if ($this->search_buildmode === 'search') {
- if ($this->search_result) {
- $placeholders = db_placeholders($this->search_result['result']);
- parent::add_where(0, "{$this->base_table}.{$this->base_field} IN ({$placeholders})", $this->search_result['result']);
-
- $view->build_info['query'] = $this->query();
- $view->build_info['count_query'] = "SELECT FALSE";
- $view->build_info['query_args'] = $this->get_where_args();
- $view->built = TRUE;
- }
- elseif (!empty($this->search_query)) {
- parent::add_where(0, "FALSE");
- }
- }
- }
-
- function execute(&$view) {
- if ($this->search_buildmode === 'search') {
- // Store values prior to execute().
- $offset = $this->offset;
- $limit = $this->limit;
- $current_page = $this->pager->current_page;
- $this->offset = $this->limit = 0;
-
- if (!empty($this->search_result)) {
- $view->total_rows = $this->pager->total_items = $this->search_result['total'];
- $this->pager->set_current_page($current_page);
- $this->pager->update_page_info();
- }
-
- // Restore original values.
- $this->offset = $offset;
- $this->limit = $limit;
-
- if ($view->built && !empty($this->search_result)) {
- // 2.x: Actually execute the View and process the result set order.
- $view->execute();
-
- // Ensure the order of the result set from Views matches that of the
- // search backend. Don't attempt to do this for aggregate queries.
- if (empty($this->has_aggregate)) {
- $sortmap = array();
- $positions = array_flip(array_values($this->search_result['result']));
- $i = count($positions);
- foreach ($view->result as $num => $row) {
- $key = $row->{$view->base_field};
- // If in search results use its position in the resultset.
- if (isset($positions[$key])) {
- $sortmap[$num] = $positions[$key];
- }
- // If not, move to the end of the stack.
- else {
- $sortmap[$num] = $i;
- $i++;
- }
- }
- array_multisort($sortmap, $view->result);
- }
- }
- }
- }
-}
-
-/**
- * Reimplementation of the Views 3 pager class.
- * Many of the methods here are taken from views_plugin_pager_full.
- */
-class searchlight_plugin_pager {
- var $view;
- var $options;
- var $current_page;
-
- function __construct($view) {
- $this->view = $view;
- $this->options = $view->pager;
- $this->options['id'] = $this->options['element'];
- }
-
- function use_pager() {
- return !empty($this->options['items_per_page']);
- }
-
- function set_current_page($number = NULL) {
- if (isset($number)) {
- $this->current_page = $number;
- return;
- }
-
- // If the current page number was not prespecified, default to pulling it from 'page'
- // based upon
- global $pager_page_array;
- // Extract the ['page'] info.
- $pager_page_array = isset($_GET['page']) ? explode(',', $_GET['page']) : array();
-
- $this->current_page = 0;
- if (!empty($pager_page_array[$this->options['id']])) {
- $this->current_page = intval($pager_page_array[$this->options['id']]);
- }
- }
-
- function get_items_per_page() {
- return isset($this->options['items_per_page']) ? $this->options['items_per_page'] : 0;
- }
-
- function update_page_info() {
- if (!empty($this->options['total_pages'])) {
- if (($this->options['total_pages'] * $this->options['items_per_page']) < $this->total_items) {
- $this->total_items = $this->options['total_pages'] * $this->options['items_per_page'];
- }
- }
-
- // Don't set pager settings for items per page = 0.
- $items_per_page = $this->get_items_per_page();
- if (!empty($items_per_page)) {
- // Dump information about what we already know into the globals.
- global $pager_page_array, $pager_total, $pager_total_items;
- // Set the item count for the pager.
- $pager_total_items[$this->options['id']] = $this->total_items;
- // Calculate and set the count of available pages.
- $pager_total[$this->options['id']] = ceil($pager_total_items[$this->options['id']] / $this->get_items_per_page());
-
- // See if the requested page was within range:
- if ($this->current_page < 0) {
- $this->current_page = 0;
- }
- else if ($this->current_page >= $pager_total[$this->options['id']]) {
- // Pages are numbered from 0 so if there are 10 pages, the last page is 9.
- $this->current_page = $pager_total[$this->options['id']] - 1;
- }
-
- // Put this number in to guarantee that we do not generate notices when the pager
- // goes to look for it later.
- $pager_page_array[$this->options['id']] = $this->current_page;
- }
-
- // This prevents our pager information from being overwritten by
- // $view->execute() after our work is done.
- $this->view->pager['items_per_page'] = NULL;
- }
-
- function query() {
- $limit = $this->options['items_per_page'];
- $offset = $this->current_page * $this->options['items_per_page'] + $this->options['offset'];
- $this->view->query->limit = $limit;
- $this->view->query->offset = $offset;
- }
-}
-
diff --git a/views/searchlight_plugin_query_v3.inc b/views/searchlight_plugin_query_v3.inc
index 97d43e7..b2c07d8 100644
--- a/views/searchlight_plugin_query_v3.inc
+++ b/views/searchlight_plugin_query_v3.inc
@@ -17,8 +17,8 @@ class searchlight_plugin_query extends views_plugin_query_default {
/**
* Override of init().
*/
- function init($base_table = 'node', $base_field = 'nid', $backend) {
- parent::init($base_table, $base_field);
+ function init($base_table = 'node', $base_field = 'nid', $options = array(), $backend) {
+ parent::init($base_table, $base_field, $options);
// Init the fields array on behalf of the parent.
$this->fields = isset($this->fields) ? $this->fields : array();
@@ -30,6 +30,8 @@ class searchlight_plugin_query extends views_plugin_query_default {
$this->backend = $backend;
$this->client = $backend->initClient($this->datasource);
+ $this->offset = NULL;
+ $this->limit = NULL;
$this->search_buildmode = NULL;
$this->search_facets = array();
$this->search_filter = array();
@@ -41,66 +43,22 @@ class searchlight_plugin_query extends views_plugin_query_default {
// This flag lets others know we are a searchlight-based view.
$this->searchlight = TRUE;
}
-
/**
* Override of add_where().
*/
- function add_where($group, $clause) {
- $where_args = func_get_args();
- $where_args = $this->get_args($where_args);
-
+ function add_where($group, $field, $value = NULL, $operator = NULL) {
// Call the parent method to add the filter SQL side.
- parent::add_where($group, $clause, $where_args);
-
- $split = preg_split('/[ ]([<>=!]*)|(\sIN\s)|(\sIS\s)|(\sNOT IN\s)|(\sIS NOT\s)/i', trim($clause), NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
- if (count($split) >= 2) {
- $field = explode('.', trim(array_shift($split)));
- $operator = strtoupper(trim(array_shift($split)));
- $possible_args = count($split) ? array_shift($split) : '';
- if (count($field) === 2) {
- $table = $field[0];
- $field = $field[1];
- foreach ($this->datasource->fields as $name => $info) {
- if ($name === "{$table}_{$field}") {
- // Get the arguments for this where clause.
- $args = array();
-
- // If arguments have been specified using query placeholders,
- // simply grab as many as there have been placeholders specified.
- $argnum = substr_count($clause, '%');
- if ($argnum && count($where_args) >= $argnum) {
- $args = array_slice($where_args, 0, $argnum);
- }
- // We may be working with a NULL check...
- elseif ($operator == 'IS' && $possible_args == 'NULL') {
- $operator = 'IN';
- $args[] = 0; // This may only work with numeric fields...
- }
- elseif ($operator == 'IS NOT' && $possible_args == 'NULL') {
- $operator = 'IN';
- $args[] = 1; // This may only work with numeric fields...
- }
- // Otherwise, groan, breath deeply & try to retrieve arguments from
- // the query.
- else {
- $matches = array();
- preg_match_all('/[A-Z*_]*|\w+|\d+/', $possible_args, $matches);
- if (!empty($matches)) {
- foreach ($matches as $match) {
- foreach ($match as $chunk) {
- if ($chunk !== '') {
- $args[] = $chunk;
- }
- }
- }
- }
- }
-
- // Done.
- $this->search_filter[] = array('field' => $name, 'operator' => $operator, 'args' => $args);
- return;
- }
- }
+ parent::add_where($group, $field, $value, $operator);
+
+ foreach ($this->datasource->fields as $name => $info) {
+ $match = str_replace(".", "_", $field);
+ if ($name === $match || "{$info['table']}_{$info['field']}" === $match) {
+ $this->search_filter[] = array(
+ 'field' => $name,
+ 'operator' => !empty($operator) ? strtoupper($operator) : 'IN',
+ 'args' => $value
+ );
+ return;
}
}
}
@@ -110,7 +68,10 @@ class searchlight_plugin_query extends views_plugin_query_default {
parent::add_orderby($table, $field, $order, $alias, $params);
if ($field === 'searchlight_weight') {
- $this->search_sort[] = array('field' => 'searchlight_weight', 'order' => $order); // "@weight {$order}";
+ $this->search_sort[] = array(
+ 'field' => 'searchlight_weight',
+ 'direction' => $order,
+ );
}
else {
// Field is aliased. Use query fields to retrieve actual table, field.
@@ -122,7 +83,10 @@ class searchlight_plugin_query extends views_plugin_query_default {
if (isset($table, $field)) {
foreach ($this->datasource->fields as $name => $info) {
if ($name === "{$table}_{$field}" && $info['usage'] !== 'content') {
- $this->search_sort[] = array('field' => $name, 'order' => $order); // "{$name} {$order}";
+ $this->search_sort[] = array(
+ 'field' => $name,
+ 'direction' => $order,
+ );;
break;
}
}
@@ -130,13 +94,19 @@ class searchlight_plugin_query extends views_plugin_query_default {
// If no table was specified or found, this is probably a function.
// Use the alias directly if it is available.
else if (empty($table) && isset($this->datasource->fields[$alias]) && $this->datasource->fields[$alias]['usage'] !== 'content') {
- $this->search_sort[] = array('field' => $alias, 'order' => $order);
+ $this->search_sort[] = array(
+ 'field' => $alias,
+ 'direction' => $order,
+ );
}
}
}
function add_search_facet($name, $limit = 5, $options = array()) {
- $this->search_facets[] = array('field' => $name, 'limit' => $limit) + $options;
+ $this->search_facets[] = array(
+ 'field' => $name,
+ 'limit' => $limit,
+ ) + $options;
}
/**
@@ -216,8 +186,13 @@ class searchlight_plugin_query extends views_plugin_query_default {
if (!empty($replacements)) {
foreach ($this->search_filter as $j => $filter) {
$this->search_filter[$j]['field'] = str_replace(array_keys($replacements), $replacements, $this->search_filter[$j]['field']);
- foreach ($this->search_filter[$j]['args'] as $k => $arg) {
- $this->search_filter[$j]['args'][$k] = str_replace(array_keys($replacements), $replacements, $arg);
+ if (is_array($this->search_filter[$j]['args'])) {
+ foreach ($this->search_filter[$j]['args'] as $k => $arg) {
+ $this->search_filter[$j]['args'][$k] = str_replace(array_keys($replacements), $replacements, $arg);
+ }
+ }
+ else {
+ $this->search_filter[$j]['args'] = str_replace(array_keys($replacements), $replacements, $this->search_filter[$j]['args']);
}
}
}
@@ -236,15 +211,27 @@ class searchlight_plugin_query extends views_plugin_query_default {
// Build facets.
$this->search_result_facets = $this->backend->facetBuild($this->client, $this->datasource, $this->search_query, $this->search_facets);
+
+ // Count the number of groups from the facet result to determine the total when using result grouping
+ if (!empty($this->datasource->options['groupfield'])) {
+ $this->search_result['total'] = count($this->search_result['result']);
+ }
if ($this->search_buildmode === 'search') {
- if ($this->search_result) {
- $placeholders = db_placeholders($this->search_result['result']);
- parent::add_where(0, "{$this->base_table}.{$this->base_field} IN ({$placeholders})", $this->search_result['result']);
+ if (isset($this->search_result, $this->search_result['result'])) {
+ // Make the query distinct if the option was set.
+ if (!empty($this->options['distinct'])) {
+ $this->set_distinct();
+ }
+
+ parent::add_where(0, "{$this->base_table}.{$this->base_field}", $this->search_result['result'], 'IN');
$view->build_info['query'] = $this->query();
- $view->build_info['count_query'] = "SELECT FALSE";
- $view->build_info['query_args'] = $this->get_where_args();
+ $view->build_info['count_query'] = $this->query();
+ }
+ else {
+ // we did not return any search results. Return no result.
+ $this->search_buildmode = 'empty';
}
}
elseif ($this->search_buildmode === 'default') {
@@ -253,7 +240,10 @@ class searchlight_plugin_query extends views_plugin_query_default {
}
function execute(&$view) {
- if ($this->search_buildmode === 'default') {
+ if ($this->search_buildmode === 'empty') {
+ //
+ }
+ elseif ($this->search_buildmode === 'default') {
parent::execute($view);
}
elseif ($this->search_buildmode === 'search') {
@@ -299,3 +289,4 @@ class searchlight_plugin_query extends views_plugin_query_default {
}
}
}
+