Index: apachesolr.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.module,v retrieving revision 1.1.2.12.2.112 diff -u -r1.1.2.12.2.112 apachesolr.module --- apachesolr.module 20 Feb 2009 19:31:16 -0000 1.1.2.12.2.112 +++ apachesolr.module 27 Feb 2009 23:26:36 -0000 @@ -194,6 +194,13 @@ db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE nid IN (SELECT nid FROM {node} WHERE type = '%s' OR type = '%s')", time(), $info->old_type, $info->type); } } + +/** + * Implementation of hook_views_api(). + */ +function apachesolr_views_api() { + return array('api' => '2.0'); +} /** * Helper function for modules implmenting hook_search's 'status' op. Index: README.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/README.txt,v retrieving revision 1.1.2.1.2.11 diff -u -r1.1.2.1.2.11 README.txt --- README.txt 20 Feb 2009 15:20:38 -0000 1.1.2.1.2.11 +++ README.txt 27 Feb 2009 23:26:35 -0000 @@ -70,7 +70,19 @@ is visible in search. Enable blocks for facets first at Administer > Site configuration > Apache Solr > Enabled filters, -then position them as you like at Administer > Site building > Blocks. +then position them as you like at Administer > Site building > Blocks. + +Creating an Apache Solr view +---------------------------- + +Once this module is enabled, a new base table becomes available when creating a +new view. In Views > Add just select "Apache Solr" as the view type to create a +view which gets its data from the Solr search server. + +You can then go on to add fields, a style, etc., to the view, just like normal. +To create a view for normally searching with Apache Solr (just like in +search/apachesolr_search), add the "Apachesolr: Search" argument to the view. + Troubleshooting -------------- Index: handlers/apachesolr_views_handler_field_taxonomy.inc =================================================================== RCS file: handlers/apachesolr_views_handler_field_taxonomy.inc diff -N handlers/apachesolr_views_handler_field_taxonomy.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_field_taxonomy.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,76 @@ + TRUE); + return $options; + } + + /** + * Unset the link_to_node option and provide link_to_terms. + */ + public function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + if (isset($form['link_to_node'])) { + unset($form['link_to_node']); + } + $form['link_to_terms'] = array( + '#title' => t("Link each term to the term's overview page."), + '#type' => 'checkbox', + '#default_value' => !empty($this->options['link_to_terms']), + ); + } + + /** + * Tell the query object to retrieve this field. + */ + public function query() { + parent::query(); + $this->query->add_field('vid'); + } + + /** + * Render the taxonomy terms as links. + */ + public function render($values) { + $taxonomies = ''; + + if (is_array($values->tid)) { + $taxonomies = array(); + + if (!empty($this->options['link_to_terms'])) { + while (!empty($values->tid) && !empty($values->taxonomy_names)) { + $term = new stdClass(); + $term->tid = array_shift($values->tid); + $term->vid = array_shift($values->vid); + $url = taxonomy_term_path($term); + $name = array_shift($values->taxonomy_names); + + $taxonomies[] = l($name, $url, array('absolute' => TRUE)); + } + } + else { + $taxonomies = $values->taxonomy_name; + } + + $taxonomies = implode(', ', $taxonomies); + } + + return $taxonomies; + } + +} Index: handlers/apachesolr_views_handler_field.inc =================================================================== RCS file: handlers/apachesolr_views_handler_field.inc diff -N handlers/apachesolr_views_handler_field.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_field.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,59 @@ +field_alias = $this->real_field; + $this->query->add_field($this->real_field); + } + + /** + * Render whatever the data is as a link to the node. + * + * This is copied from views_handler_field_node, but without the indirection + * via the aliases table, since in Apache Solr there are no field aliases. + */ + public function render_link($data, $values) { + if (!empty($this->options['link_to_node']) + && $data !== NULL && $data !== '') { + $this->options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = $values->url; + } + return $data; + } + + /** + * Called when click-sorting. + */ + public function click_sort($order) { + /* These fields have a special "*_sort" field for sorting: */ + $special_sort_fields = array( + 'name' => 'name_sort', + 'title' => 'title_sort', + ); + + if (empty($special_sort_fields[$this->real_field])) { + $this->query->add_sort($this->real_field, strtolower($order), TRUE); + } + else { + $this->query->add_sort( + $special_sort_fields[$this->real_field], strtolower($order), TRUE); + } + } + +} Index: handlers/apachesolr_views_handler_field_generic.inc =================================================================== RCS file: handlers/apachesolr_views_handler_field_generic.inc diff -N handlers/apachesolr_views_handler_field_generic.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_field_generic.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,160 @@ +_original->$name)) { + return $this->_original->$name; + } + return NULL; + } + + /** + * Gets called when trying to set an undefined property. + */ + public function __set($name, $value) { + $this->_original->$name = $value; + } + + /** + * Gets called when calling isset() or empty() on an undefined property. + */ + public function __isset($name) { + return isset($this->_original->$name); + } + + /** + * Gets called when calling unser() on an undefined property. + */ + public function __unset($name) { + unset($this->_original->$name); + } + + /** + * Gets called when calling an undefined instance method. + */ + public function __call($name, $args) { + if (!method_exists($this->_original, $name)) { + trigger_error("tried to call undefined instance method $name", E_USER_ERROR); + } + return call_user_func_array(array($this->_original, $name), $args); + } + + /** + * Gets called when calling an undefined static method. + */ + public static function __callStatic($name, $args) { + $method = array(get_class($this->_original), $name); + if (!method_exists($method)) { + trigger_error("tried to call undefined static method $name", E_USER_ERROR); + } + call_user_func_array($method, $args); + } + + /* + * "Normal" methods + */ + + /** + * Loads the base handler and loads it with the specified definition. + * Throws an exception if unsuccessful. + */ + public function set_definition($definition) { + if (empty($definition['apachesolr base handler'])) { + watchdog('views', + 'no base handler specified for apachesolr field handler', array(), + WATCHDOG_ERROR); + } + $o = $definition['apachesolr base handler']; + $this->_original = views_get_handler($o['table'], $o['field'], 'field'); + if (empty($this->_original)) { + watchdog('views', + 'invalid base handler specified for apachesolr field handler: ' . + $o['table'] . '/' . $o['field'], array(), WATCHDOG_ERROR); + } + // Give the original handler the correct definition. + $this->_original->set_definition($definition); + } + + /** + * Construct a new apachesolr field handler. + */ + public function construct() { + $this->_original->construct(); + + $this->_original->aliases = drupal_map_assoc( + array('id', 'site', 'hash', 'url', 'title', 'body', 'type', 'type_name', + 'path', 'path_alias', 'uid', 'name', 'created', 'changed', + 'last_comment_or_change', 'nid', 'status', 'promote', 'moderate', + 'sticky', 'tnid', 'translate', 'language', 'comment_count', 'tid', + 'vid', 'timestamp' + )); + } + + /** + * We don't need to ensure any tables. + * So overwrite this method because it might be called by inherited methods. + */ + public function ensure_my_table() {} + + /** + * Tell the query object to retrieve this field. + */ + public function query() { + $this->_original->field_alias = $this->_original->real_field; + $this->_original->query->add_field($this->_original->real_field); + $this->add_additional_fields(); + } + + /** + * Add additionally required fields. + */ + public function add_additional_fields($fields = NULL) { + if (!empty($fields)) { + return $this->_original->add_additional_fields($fields); + } + foreach ($this->_original->additional_fields as $f) { + $this->_original->query->add_field($f); + } + } + + /** + * Called when click-sorting. + */ + public function click_sort($order) { + /* These fields have a special "*_sort" field for sorting: */ + $special_sort_fields = array( + 'name' => 'name_sort', + 'title' => 'title_sort', + ); + + if (empty($special_sort_fields[$this->real_field])) { + $this->_original->query->add_sort( + $this->_original->real_field, $order, TRUE); + } + else { + $this->_original->query->add_sort( + $special_sort_fields[$this->_original->real_field], $order, TRUE); + } + } + +} Index: handlers/apachesolr_views_handler_field_type.inc =================================================================== RCS file: handlers/apachesolr_views_handler_field_type.inc diff -N handlers/apachesolr_views_handler_field_type.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_field_type.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,19 @@ +render_link( + node_get_types('name', $values->{$this->real_field}), $values); + } + +} Index: handlers/apachesolr_views_handler_argument.inc =================================================================== RCS file: handlers/apachesolr_views_handler_argument.inc diff -N handlers/apachesolr_views_handler_argument.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_argument.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,18 @@ +query->add_term(apachesolr_views_query::escape_term($this->argument), + $this->real_field); + } + +} Index: apachesolr.views.inc =================================================================== RCS file: apachesolr.views.inc diff -N apachesolr.views.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ apachesolr.views.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,288 @@ + array( + 'path' => drupal_get_path('module', 'apachesolr') . '/handlers', + ), + 'handlers' => array( + 'apachesolr_views_handler_argument' => array( + 'parent' => 'views_handler_argument', + ), + 'apachesolr_views_handler_field' => array( + 'parent' => 'views_handler_field_node', + ), + 'apachesolr_views_handler_field_author' => array( + 'parent' => 'apachesolr_views_handler_field', + ), + 'apachesolr_views_handler_field_date' => array( + 'parent' => 'apachesolr_views_handler_field', + ), + 'apachesolr_views_handler_field_generic' => array( + 'parent' => 'views_object', + ), + 'apachesolr_views_handler_field_taxonomy' => array( + 'parent' => 'apachesolr_views_handler_field', + ), + 'apachesolr_views_handler_field_type' => array( + 'parent' => 'apachesolr_views_handler_field', + ), + 'apachesolr_views_handler_filter_author' => array( + 'parent' => 'views_handler_filter', + ), + 'apachesolr_views_handler_filter_search' => array( + 'parent' => 'views_handler_filter_string', + ), + 'apachesolr_views_handler_filter_type' => array( + 'parent' => 'views_handler_filter', + ), + 'apachesolr_views_handler_sort' => array( + 'parent' => 'views_handler_sort', + ), + ), + ); +} + +/** + * Implementation of hook_views_plugins(). + */ +function apachesolr_views_plugins() { + return array( + 'module' => 'apachesolr', + 'query' => array( + 'apachesolr_views_query' => array( + 'title' => t('Apache Solr Query'), + 'help' => t('Query that allows you to search with Apache Solr.'), + 'handler' => 'apachesolr_views_query', + 'parent' => 'views_query', + ), + ), + ); + +} + +/** + * Implementation of hook_views_data(). + */ +function apachesolr_views_data() { + $data['apachesolr']['table']['group'] = t('Apache Solr'); + + $data['apachesolr']['table']['base'] = array( + 'query class' => 'apachesolr_views_query', + 'title' => t('Apache Solr'), + 'help' => t('Searches the site with the Apache Solr search engine.'), + ); + + $data['apachesolr']['nid'] = array( + 'title' => t('Nid'), + 'help' => t('The node ID of the node.'), + 'field' => array( + 'name field' => 'title', + 'numeric' => TRUE, + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node', + 'field' => 'nid', + ), + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + $data['apachesolr']['title'] = array( + 'title' => t('Title'), + 'help' => t('The title of the node.'), + 'argument' => array( + 'handler' => 'apachesolr_views_handler_argument', + ), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node', + 'field' => 'title', + ), + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + $data['apachesolr']['created'] = array( + 'title' => t('Creation date'), + 'help' => t('The date the node was created.'), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node', + 'field' => 'created', + ), + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + $data['apachesolr']['changed'] = array( + 'title' => t('Updated date'), + 'help' => t('The date the node was last updated.'), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node', + 'field' => 'changed', + ), + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + $data['apachesolr']['type'] = array( + 'title' => t('Type'), + 'help' => t('The type of a node (for example, "blog entry", "forum post", "story", etc).'), + 'argument' => array( + 'handler' => 'apachesolr_views_handler_argument', + ), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node', + 'field' => 'type', + ), + ), + 'filter' => array( + 'handler' => 'views_handler_filter_apachesolr_type', + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + $data['apachesolr']['name'] = array( + 'title' => t('Author'), + 'help' => t("The node's author."), + 'argument' => array( + 'handler' => 'apachesolr_views_handler_argument', + ), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'additional fields' => array('uid'), + 'apachesolr base handler' => array( + 'table' => 'users', + 'field' => 'name', + ), + ), + 'filter' => array( + 'handler' => 'apachesolr_views_handler_filter_author', + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + $data['apachesolr']['uid'] = array( + 'title' => t('Author Uid'), + 'help' => t("The node's author's user ID."), + 'argument' => array( + 'handler' => 'apachesolr_views_handler_argument', + ), + 'field' => array( + 'name field' => 'name', + 'numeric' => TRUE, + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'users', + 'field' => 'uid', + ), + ), + ); + $data['apachesolr']['body'] = array( + 'title' => t('Body'), + 'help' => t("The node's content."), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => FALSE, + 'element type' => 'div', + 'apachesolr base handler' => array( + 'table' => 'node_revisions', + 'field' => 'body', + ), + ), + ); + $data['apachesolr']['comment_count'] = array( + 'title' => t('Comment count'), + 'help' => t('The number of comments that were posted to the node.'), + 'field' => array( + 'numeric' => TRUE, + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node_comment_statistics', + 'field' => 'comment_count', + ), + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + // TODO Get taxonomy fields to work + /*if (module_exists('taxonomy')) { + $data['apachesolr']['tid'] = array( + 'title' => t('Taxonomy terms'), + 'help' => t('Taxonomy terms associated with the node.'), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_taxonomy', + 'click sortable' => FALSE, + 'additional fields' => array('vid'), + 'apachesolr base handler' => array( + 'table' => 'vocabulary', + 'field' => 'name', + ), + ), + ); + }*/ + if (module_exists('translation')) { + $data['apachesolr']['language'] = array( + 'title' => t('Language'), + 'help' => t('The language the node is in.'), + 'argument' => array( + 'handler' => 'apachesolr_views_handler_argument', + ), + 'field' => array( + 'handler' => 'apachesolr_views_handler_field_generic', + 'click sortable' => TRUE, + 'apachesolr base handler' => array( + 'table' => 'node', + 'field' => 'language', + ), + ), + 'sort' => array( + 'handler' => 'apachesolr_views_handler_sort', + ), + ); + } + + $data['apachesolr']['text'] = array( + 'title' => t('Search'), + 'help' => t('Searches the content with Solr'), + 'argument' => array( + 'handler' => 'apachesolr_views_handler_argument', + ), + 'filter' => array( + 'handler' => 'apachesolr_views_handler_filter_search', + ), + ); + + return $data; +} Index: handlers/apachesolr_views_handler_field_date.inc =================================================================== RCS file: handlers/apachesolr_views_handler_field_date.inc diff -N handlers/apachesolr_views_handler_field_date.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_field_date.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,89 @@ + 'small'); + $options['custom_date_format'] = array('default' => ''); + + return $options; + } + + public function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + $time = time(); + + $form['date_format'] = array( + '#type' => 'select', + '#title' => t('Date format'), + '#options' => array( + 'small' => format_date($time, 'small'), + 'medium' => format_date($time, 'medium'), + 'large' => format_date($time, 'large'), + 'custom' => t('Custom'), + 'raw time ago' => t('Time ago'), + 'time ago' => t('Time ago (with "ago" appended)'), + ), + '#default_value' => + isset($this->options['date_format']) + ? $this->options['date_format'] + : 'small', + ); + $form['custom_date_format'] = array( + '#type' => 'textfield', + '#title' => t('Custom date format'), + '#description' => t('If "Custom", see ' . + 'the PHP docs for date formats. If "Time ago" this is the the ' . + 'number of different units to display, which defaults to two.', + array('!url' => 'http://us.php.net/manual/en/function.date.php')), + '#default_value' => + isset($this->options['custom_date_format']) + ? $this->options['custom_date_format'] + : '', + '#process' => array('views_process_dependency'), + '#dependency' => + array('edit-options-date-format' => array('custom', 'time ago')), + ); + } + + public function render($values) { + // Apache Solr sends the time as a time string, so first convert it back + $value = strtotime($values->{$this->real_field}); + + $format = $this->options['date_format']; + if ($format == 'custom' || $format == 'time ago' || $format == 'raw time ago') { + $custom_format = $this->options['custom_date_format']; + } + + switch ($format) { + case 'raw time ago': + return $value + ? format_interval(time() - $value, + is_numeric($custom_format) ? $custom_format : 2) + : theme('views_nodate'); + case 'time ago': + return $value + ? t('%time ago', array('%time' => format_interval(time() - $value, + is_numeric($custom_format) ? $custom_format : 2))) + : theme('views_nodate'); + case 'custom': + return $value + ? format_date($value, $format, $custom_format) + : theme('views_nodate'); + default: + return $value + ? format_date($value, $format) + : theme('views_nodate'); + } + } + +} Index: handlers/apachesolr_views_handler_filter_search.inc =================================================================== RCS file: handlers/apachesolr_views_handler_filter_search.inc diff -N handlers/apachesolr_views_handler_filter_search.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_filter_search.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,57 @@ + array( + 'title' => t('Append to query'), + 'short' => '', + 'method' => 'query', + 'values' => 1, + ), + ); + + return $operators; + } + + public function query() { + if (!empty($this->value)) { + $this->query->add_term($this->value); + } + } + + public function admin_summary() { + if (!empty($this->options['exposed'])) { + return t('exposed'); + } + + return $this->value; + } + +} Index: handlers/apachesolr_views_handler_sort.inc =================================================================== RCS file: handlers/apachesolr_views_handler_sort.inc diff -N handlers/apachesolr_views_handler_sort.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_sort.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,30 @@ + 'name_sort', + 'title' => 'title_sort', + ); + $order = strtolower($this->options['order']); + + if (empty($special_sort_fields[$this->real_field])) { + $this->query->add_sort($this->real_field, $order); + } + else { + $this->query->add_sort( + $special_sort_fields[$this->real_field], $order); + } + } + +} Index: handlers/apachesolr_views_handler_filter_author.inc =================================================================== RCS file: handlers/apachesolr_views_handler_filter_author.inc diff -N handlers/apachesolr_views_handler_filter_author.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_filter_author.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,87 @@ + 'one of'); + $options['value'] = array('default' => ''); + + return $options; + } + + public function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + $time = time(); + + $form['operator'] = array( + '#type' => 'select', + '#title' => t('Filter for'), + '#options' => array( + 'one of' => t('One of these'), + 'not one of' => t('Not one of these'), + 'current' => t('Current user'), + 'not current' => t('Not current user'), + ), + '#default_value' => + isset($this->options['operator']) + ? $this->options['operator'] + : 'one of', + ); + $form['value'] = array( + '#type' => 'textfield', + '#title' => t('Usernames'), + '#description' => t('Enter a comma seperated list of user names.'), + '#default_value' => + isset($this->options['value']) + ? $this->options['value'] + : '', + '#process' => array('views_process_dependency'), + '#dependency' => + array('edit-options-operator' => array('one of', 'not one of')), + ); + } + + public function query() { + if ($this->options['operator'] == 'current') { + global $user; + $this->query->add_term($user->uid, 'uid'); + } + else if ($this->options['operator'] == 'not current') { + global $user; + $this->query->add_term('NOT uid:' . $user->uid); + } + else { + $not = $this->options['operator'] == 'not one of'; + $names = array_map('trim', explode(',', $this->options['value'])); + foreach ($names as $i => $name) { + if (empty($name)) { + unset($names[$i]); + } + } + if (empty($names)) { + if (!$not) { + $this->query->add_term('nid:-1');//Add term that will yield no results + } + } + else if (count($names) == 1) { + $this->query->add_term(($not ? 'NOT ' : '') . 'name:' . + array_shift($names)); + } + else { + $key = 'name:' . array_shift($names); + foreach ($names as $name) { + $key .= ' OR name:' . $name; + } + $this->query->add_term($not ? 'NOT (' . $key . ')' : $key); + } + } + } + +} Index: handlers/apachesolr_views_handler_field_author.inc =================================================================== RCS file: handlers/apachesolr_views_handler_field_author.inc diff -N handlers/apachesolr_views_handler_field_author.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_field_author.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,47 @@ + TRUE); + return $options; + } + + /** + * Provide link_to_profile option + */ + public function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + if (isset($form['link_to_node'])) { + unset($form['link_to_node']); + } + $form['link_to_profile'] = array( + '#title' => t("Link the name to the user's profile."), + '#type' => 'checkbox', + '#default_value' => !empty($this->options['link_to_profile']), + ); + } + + /** + * If the link_to_profile option is set, render the field as a link to the + * user's profile. + */ + function render_link($data, $values) { + if (!empty($this->options['link_to_profile']) && $data !== NULL && $data !== '') { + $this->options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = "user/" . $values->uid; + } + return $data; + } + +} Index: handlers/apachesolr_views_handler_filter_type.inc =================================================================== RCS file: handlers/apachesolr_views_handler_filter_type.inc diff -N handlers/apachesolr_views_handler_filter_type.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ handlers/apachesolr_views_handler_filter_type.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,72 @@ + 'one of'); + $options['value'] = array('default' => ''); + + return $options; + } + + public function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + $time = time(); + + $form['operator'] = array( + '#type' => 'select', + '#title' => t('Filter for'), + '#options' => array( + 'one of' => t('One of these'), + 'not one of' => t('Not one of these'), + ), + '#default_value' => + isset($this->options['operator']) + ? $this->options['operator'] + : 'one of', + ); + $form['value'] = array( + '#type' => 'textfield', + '#title' => t('Usernames'), + '#description' => t('Enter a comma seperated list of types.'), + '#default_value' => + isset($this->options['value']) + ? $this->options['value'] + : '', + ); + } + + public function query() { + $not = $this->options['operator'] == 'not one of'; + $types = array_map('trim', explode(',', $this->options['value'])); + foreach ($types as $i => $type) { + if (empty($type)) { + unset($types[$i]); + } + } + if (empty($types)) { + if (!$not) { + $this->query->add_term('nid:-1');//Add term that will yield no results + } + } + else if (count($types) == 1) { + $this->query->add_term(($not ? 'NOT ' : '') . 'type:' . + array_shift($types)); + } + else { + $key = 'type:' . array_shift($types); + foreach ($types as $type) { + $key .= ' OR type:' . $type; + } + $this->query->add_term($not ? 'NOT (' . $key . ')' : $key); + } + } + +} Index: apachesolr_views_query.inc =================================================================== RCS file: apachesolr_views_query.inc diff -N apachesolr_views_query.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ apachesolr_views_query.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,379 @@ +_keys = array(); + // Always retrieve these fields: + $this->_used_fields = array( + 'id' => TRUE, + 'nid' => TRUE, + 'url' => TRUE, + ); + $this->_params = $this->_get_params(); + + // For use within the escape_term() method. + include_once(drupal_get_path('module', 'apachesolr') . + '/Drupal_Apache_Solr_Service.php'); + } + + /** + * Build the query object. + */ + public function build() { + if (empty($this->_keys)) { + $this->_query = FALSE; + return; + } + else if (count($this->_keys)) { + $this->_query = $this->_keys[0]; + } + else { + $this->_query = '(' . implode(') (', $this->_keys) . ')'; + } + + $this->_query_object = apachesolr_current_query($this->_query, '', + $this->get_param('sort')); + } + + /** + * Let modules modify the query just prior to finalizing it. + */ + public function alter(&$view) { + // TODO Do something here? (apachesolr_modify_query() is called later.) + } + + /** + * Executes the query and fills the associated view object with according + * values. + * + * Values to set: $view->result, $view->total_rows, $view->execute_time, + * $view->pager['current_page']. + */ + public function execute(&$view) { + $view->result = array(); + $start_time = views_microtime(); + $query = $this->_query_object; + $params = $this->_params; + $solr = $this->_solr; + + if (empty($query)) { + return; + } + + try { + // Get only the necessary fields. + $params['fl'] = implode(',', array_keys($this->_used_fields)); + + // Get the number of results to retrieve. + $params['rows'] = $view->pager['items_per_page']; + + // Since only now the query is known, we couldn't do this earlier + // (i.e., in _get_params()) + if (variable_get('apachesolr_search_spellcheck', FALSE)) { + //Add new parameter to the search request + $params['spellcheck.q'] = $this->_query_object->get_query_basic(); + $params['spellcheck'] = 'true'; + } + + // We default to getting snippets from the body. + $hl_fl = is_null($params['hl.fl']) ? 'body' : $params['hl.fl']; + + // This hook allows modules to modify the query and params objects. + apachesolr_modify_query($query, $params, 'apachesolr_search'); + if (!$query) { + return array(); + } + + $response = $solr->search($query->get_query_basic(), $params['start'], + $params['rows'], $params); + + $view->total_rows = $total = $response->response->numFound; + $view->pager['current_page'] = $params['start'] / $params['rows']; + + // The response is cached so that it is accessible to the blocks and + // anything else that needs it beyond the initial search. + apachesolr_static_response_cache($response); + apachesolr_has_searched(TRUE); + pager_query("SELECT %d", $params['rows'], 0, NULL, $total); + + if ($total > 0) { + $results = $response->response->docs; + + // Process dates + $date_fields = array('created', 'changed'); + foreach (array_values($date_fields) as $field) { + if (empty($this->_used_fields[$field])) { + unset($date_fields[$field]); + } + } + if (!empty($date_fields)) { + foreach ($results as $doc) { + foreach ($date_fields as $field) { + $doc->$field = strtotime($doc->$field); + } + } + } + + // Hook to allow modifications of the retrieved results + foreach (module_implements('apachesolr_process_results') as $module) { + $function = $module .'_apachesolr_process_results'; + call_user_func_array($function, array(&$results)); + } + + $view->result = $results; + } + } + catch (Exception $e) { + watchdog('Apache Solr', $e->getMessage(), NULL, WATCHDOG_ERROR); + apachesolr_failure(t('Solr search'), is_null($query) ? $this->_keys : $query->get_query_basic()); + } + + $view->execute_time = views_microtime() - $start_time; + } + + + /* + * Functions offered for apachesolr-specific handlers, etc. + */ + + /** Adds the specified term to the query. */ + public function add_term($term, $field = 'text') { + if ($field != 'text') { + $term = $field . ':' . $term; + } + $this->_keys[] = $term; + } + + /** + * Add a group of search terms to the query, which will be connected by OR + * operators. + * + * @param $terms an array where each entry must be either of the form + * array('term' => $term, 'field' => $field); + * (the 'field' entry can be omitted, in which case 'text' is assumed), or + * $term + */ + public function add_or_group($terms) { + if (count($terms) == 0 || !is_array($terms)) { + return; + } + $keys = array(); + foreach ($terms as $term) { + if (is_array($term)) { + if (empty($term['field']) || $term['field'] == 'text') { + $keys[] = $term['term']; + } + else { + $keys[] = $term['field'] . ':' . $term['term']; + } + } + else { + $keys[] = $term; + } + } + $this->_keys[] = '(' . implode(' OR ', $keys) . ')'; + } + + /** Sets the specified Solr search parameter to the specified value. */ + public function set_param($param, $value) { + $this->_params[$param] = $value; + } + + /** Get the specified Solr search parameter. */ + public function get_param($param) { + return isset($this->_params[$param]) ? $this->_params[$param] : ''; + } + + /** + * Adds the specified parameters to the Solr search parameters, overwriting + * old values where necessary. Parameters must be specified as + * $param => $value in the array. + */ + public function set_params($params) { + $this->_params = $params + $this->_params; + } + + /** + * Add a field to retrieve. + * + * $compat_field is used for compatibility with the views_plugin_query_default + * definition of this method - when $compat_field is set, $field is ignored + * and $compat_field used instead. + */ + public function add_field($field, $compat_field = NULL) { + if (!empty($compat_field)) { + $field = $compat_field; + } + if (is_array($field) && isset($field['field'])) { + $field = $field['field']; + } + if (empty($field) || !is_string($field)) { + return FALSE; + } + $this->_used_fields[$field] = TRUE; + return $field; + } + + /** + * Add a sorting directive. + * + * @param $single If TRUE, the results will only be sorted by this order. + */ + public function add_sort($field, $order, $single = FALSE) { + $sort = $field . ' ' . strtolower($order); + if (empty($this->_params['sort']) || $single) { + $this->_params['sort'] = $sort; + } + else { + $this->_params['sort'] .= ',' . $sort; + } + } + + + /* + * (Public and private) helper functions + */ + + /** Escapes a term for passing it to the query. */ + public static function escape_term($term) { + $term = trim($term); + if (empty($term)) { + return ''; + } + if (($term{0} == '"' && $term{strlen($term)-1} == '"') + || $term{0} == '(' && $term{strlen($term)-1} == ')') { + return $term; + } + + if (strpos($term, ' ') !== FALSE) { + return Drupal_Apache_Solr_Service::phrase($term); + } + return Drupal_Apache_Solr_Service::escape($term); + } + + /** + * Returns the parameters that will be handed to Solr along with the query. + */ + private function _get_params() { + // Whole method copied from + // apachesolr_search.module:101-209: apachesolr_search_search() + // TODO Refactor, so both this class and apachesolr_search_search() call new + // function, apachesolr_get_params(). + // (If apachesolr_search_get_params() is used, add apachesolr_search to + // dependencies in .info.) + $params = array( + 'fl' => 'id,nid,title,comment_count,type,created,changed,url,uid,name', + 'facet' => 'true', + 'facet.mincount' => 1, + 'facet.sort' => 'true', + 'hl' => 'false', + ); + + $facet_query_limits = variable_get('apachesolr_facet_query_limits', array()); + // Request all enabled facets. + foreach (apachesolr_get_enabled_facets() as $module => $module_facets) { + foreach($module_facets as $delta => $facet_field) { + $params['facet.field'][] = $facet_field; + // Facet limits + if (isset($facet_query_limits[$module][$delta])) { + $params['f.' . $facet_field . '.facet.limit'] = $facet_query_limits[$module][$delta]; + } + } + } + if (!empty($params['facet.field'])) { + // Add a default limit for fields where no limit was set. + $params['facet.limit'] = variable_get('apachesolr_facet_query_limit_default', 20); + } + + $page = isset($_GET['page']) ? $_GET['page'] : 0; + $params['start'] = $page * $params['rows']; + // This is the object that does the communication with the solr server. + $solr = $this->_solr = apachesolr_get_solr(); + + // Note - we have query fields set in solrconfig.xml, which will operate when + // none are set. + $qf = variable_get('apachesolr_search_query_fields', array()); + $fields = $solr->getFields(); + if ($qf && $fields) { + foreach ($fields as $field_name => $field) { + if (!empty($qf[$field_name])) { + if ($field_name == 'body') { + // Body is the only normed field. + $qf[$field_name] *= 40.0; + } + $params['qf'][] = $field_name . '^'. $qf[$field_name]; + } + } + } + // Note: we use 2 since 1 fails on Ubuntu Hardy. + $data = $solr->getLuke(2); + if (isset($data->index->numDocs)) { + $total = $data->index->numDocs; + } + else { + $total = db_result(db_query("SELECT COUNT(nid) FROM {node}")); + } + $date_settings = variable_get('apachesolr_search_date_boost', '4:200.0'); + list($date_steepness, $date_boost) = explode(':', $date_settings); + // Default date-biasing function, as suggested (but steeper) at + // http://wiki.apache.org/solr/DisMaxRequestHandler + // rord() returns 1 for the newset doc, and the number in the index for + // the oldest doc. The function is thus: $total/(rord()*$steepness + $total). + if ($date_boost) { + $params['bf'][] = "recip(rord(created),$date_steepness,$total,$total)^$date_boost"; + } + $comment_settings = variable_get('apachesolr_search_comment_boost', '4:200.0'); + list($comment_steepness, $comment_boost) = explode(':', $comment_settings); + // Default date-biasing function, as suggested (but steeper) at + // http://wiki.apache.org/solr/DisMaxRequestHandler + // rord() returns 1 for the newset doc, and the number in the index for + // the oldest doc. The function is thus: $total/(rord()*$steepness + $total). + if ($comment_boost) { + $params['bf'][] = "recip(rord(comment_count),$comment_steepness,$total,$total)^$comment_boost"; + } + + // Modify the weight of results according to the node types. + $type_boosts = variable_get('apachesolr_search_type_boosts', array()); + if (!empty($type_boosts)) { + foreach ($type_boosts as $type => $boost) { + $params['bq'][] = "type:$type^$boost"; + } + } + + return $params; + } + +}