Index: apachesolr.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.module,v retrieving revision 1.1.2.12.2.172 diff -u -p -r1.1.2.12.2.172 apachesolr.module --- apachesolr.module 15 Nov 2009 14:52:28 -0000 1.1.2.12.2.172 +++ apachesolr.module 21 Nov 2009 04:50:58 -0000 @@ -1467,8 +1467,11 @@ function theme_apachesolr_facet_list($it drupal_add_js(drupal_get_path('module', 'apachesolr') . '/apachesolr.js'); // Split items array into displayed and hidden. $hidden_items = array_splice($items, $display_limit); - foreach ($hidden_items as $link) { - $items[] = array('data' => $link, 'class' => 'apachesolr-hidden-facet'); + foreach ($hidden_items as $hidden_item) { + if (!is_array($hidden_item)) { + $hidden_item = array('data' => $hidden_item); + } + $items[] = $hidden_item + array('class' => 'apachesolr-hidden-facet'); } } $admin_link = ''; Index: apachesolr_search.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr_search.module,v retrieving revision 1.1.2.6.2.119 diff -u -p -r1.1.2.6.2.119 apachesolr_search.module --- apachesolr_search.module 20 Nov 2009 17:19:05 -0000 1.1.2.6.2.119 +++ apachesolr_search.module 21 Nov 2009 04:50:58 -0000 @@ -575,79 +575,13 @@ function apachesolr_search_block($op = ' $limit_default = variable_get('apachesolr_facet_query_initial_limit_default', 10); // Handle taxonomy vocabulary facets - if ((strpos($delta, 'im_vid_') === 0) && module_exists('taxonomy')) { - - if (is_object($response->facet_counts->facet_fields->$delta)) { - $contains_active = FALSE; - $terms = array(); - - foreach ($response->facet_counts->facet_fields->$delta as $tid => $count) { - $options = array(); - if ($tid == '_empty_') { - // TODO - for now we don't handle facet missing. - continue; - } - $unclick_link = ''; - unset($active); - $term = taxonomy_get_term($tid); - $new_query = clone $query; - if ($active = $query->has_filter('tid', $tid)) { - $contains_active = TRUE; - $new_query->remove_filter('tid', $term->tid); - $options['query'] = $new_query->get_url_queryvalues(); - $link = theme('apachesolr_unclick_link', $term->name, $new_query->get_path(), $options); - } - else { - $new_query->add_filter('tid', $term->tid); - $options['query'] = $new_query->get_url_queryvalues(); - $link = theme('apachesolr_facet_link', $term->name, $new_query->get_path(), $options, $count, $active, $response->response->numFound); - } - $countsort = $count == 0 ? '' : 1 / $count; - $countsort += .000001; - $countsort = number_format($countsort, 6); - - // if numdocs == 1 and !active, don't add. - if ($response->response->numFound > 1 || $active) { - $terms[$term->vid][$active ? $countsort . $term->name : 1 + $countsort . $term->name] = $link; - } - } - } - $vid = substr($delta, 7); - $vocab = taxonomy_vocabulary_load($vid); - if (is_numeric($vid) && is_array($terms) && isset($terms[$vid]) && is_array($terms[$vid])) { - ksort($terms[$vid]); - $limit = isset($initial_limits['apachesolr_search'][$delta]) ? $initial_limits['apachesolr_search'][$delta] : $limit_default; - return array( - 'subject' => t('Filter by @name', array('@name' => $vocab->name)), - 'content' => theme('apachesolr_facet_list', $terms[$vid], $limit), - ); - } - return; + if ((strpos($delta, 'im_vid_') === 0)) { + return apachesolr_search_taxonomy_facet_block($response, $query, $delta); } switch ($delta) { case 'currentsearch': - $fields = $query->get_filters(); - $path = $query->get_path(); - $options = array(); - if (!$fields) { - $options['attributes']['class'] = 'active'; - } - $links[] = apachesolr_l($query->get_query_basic(), $path, $options); - foreach($fields as $field) { - if ($field['#name']) { - $new_query = clone $query; - $new_query->remove_filter($field['#name'], $field['#value']); - $options['query'] = $new_query->get_url_queryvalues(); - $fielddisplay = theme("apachesolr_breadcrumb_". $field['#name'], $field['#value']); - if (!$fielddisplay) { - $fielddisplay = $field['#value']; - } - $links[] = theme('apachesolr_unclick_link', $fielddisplay, $new_query->get_path(), $options); - } - } - $content = theme('apachesolr_currentsearch', $response->response->numFound, $links); - return array('subject' => t('Current search'), 'content' => $content); + return apachesolr_search_currentsearch_block($query); case 'is_book_bid': return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by book'), 'apachesolr_search_get_book'); case 'language': @@ -690,6 +624,132 @@ function apachesolr_search_block($op = ' } /** + * Generate the facet block for a taxonomy vid delta. + */ +function apachesolr_search_taxonomy_facet_block($response, $query, $delta) { + $vid = substr($delta, 7); + if (!module_exists('taxonomy') || !is_numeric($vid)) { + return; + } + + // Check that we have a response and a valid vid. + if (is_object($response->facet_counts->facet_fields->$delta) && ($vocab = taxonomy_vocabulary_load($vid))) { + $reflect_hierarchy = apachesolr_search_get_hierarchical_vocabularies(); + $contains_active = FALSE; + $terms = array(); + + foreach ($response->facet_counts->facet_fields->$delta as $tid => $count) { + if ($tid == '_empty_') { + // TODO - for now we don't handle facet missing. + continue; + } + $unclick_link = ''; + unset($active); + $parents = array(); + if ($reflect_hierarchy[$vocab->vid]) { + $parents = taxonomy_get_parents_all($tid); + // We don't display children unless the parent is clicked. + if (!empty($parents[1]) && !$query->has_filter('tid', $parents[1]->tid)) { + continue; + } + } + else if ($term = taxonomy_get_term($tid)) { + $parents[] = $term; + } + $parents = array_reverse($parents); + + foreach ($parents as $key => $term) { + $parents[$key] = $term; + } + + $options = array(); + $active = $query->has_filter('tid', $tid); + if ($active) { + $remove = array(array('#name' => 'tid', '#value' => $tid)); + + if ($reflect_hierarchy[$vocab->vid]) { + $childs = taxonomy_get_tree($vid, $tid); + foreach ($childs as $child) { + $remove[] = array('#name' => 'tid', '#value' => $child->tid); + } + } + + $link = apachesolr_search_get_unclick_link($query, $term->name, $remove); + } + else { + $new_query = clone $query; + $new_query->add_filter('tid', $tid); + $options = array('query' => $new_query->get_url_queryvalues()); + $link = theme('apachesolr_facet_link', $term->name, $new_query->get_path(), $options, $count, $active, $response->response->numFound); + } + + // if numdocs == 1 and !active, don't add. + if ($response->response->numFound > 1 || $active) { + $sort_key = ''; + $term = NULL; + foreach ($parents as $term) { + $count = $response->facet_counts->facet_fields->$delta->{$term->tid}; + $countsort = $count == 0 ? '' : 1 / $count; + $countsort = $query->has_filter('tid', $term->tid) ? $countsort : 1 + $countsort; + $countsort += .000001; + $countsort = number_format($countsort, 6); + $sort_key .= ($sort_key ? '|' : '') . $countsort . ':' . $term->name; + } + $terms[$sort_key] = $link; + } + } + + // Process all terms into an item list + if ($terms) { + // Create array of nested items + $items = apachesolr_search_nested_facet_items($terms); + $limit = isset($initial_limits['apachesolr_search'][$delta]) ? $initial_limits['apachesolr_search'][$delta] : $limit_default; + return array( + 'subject' => t('Filter by @name', array('@name' => $vocab->name)), + 'content' => theme('apachesolr_facet_list', $items, $limit), + ); + } + } +} + +/** + * Creates a link to trigger a new search, removing at least one of the active + * search filters. + * + * @param $query + * A Solr query object. + * @param $facet_text + * Facet value shown to the user. + * @param $remove + * Array of field names and values to remove upon clicking link to build. + * @return + * A string containing the themed unclick link. + */ +function apachesolr_search_get_unclick_link($query, $facet_text, $remove) { + static $unclick_queries = array(); + + sort($remove); + $unclick_query_key = array_reduce($remove, 'apachesolr_search_get_unclick_query_key'); + $new_query = clone $query; + + if (empty($unclick_queries[$unclick_query_key])) { + foreach($remove as $field) { + $new_query->remove_filter($field['#name'], $field['#value']); + } + $unclick_queries[$unclick_query_key]['query'] = $new_query->get_url_queryvalues(); + } + + return theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $unclick_queries[$unclick_query_key]); +} + +/** + * Callback for array_reduce() in apachesolr_search_get_unclick_link(). + */ +function apachesolr_search_get_unclick_query_key($result, $val) { + return $result . $val['#name'] . $val['#value']; +} + +/** * Callback function for the 'Filter by book' facet block. */ function apachesolr_search_get_book($facet, &$options) { @@ -703,6 +763,33 @@ function apachesolr_search_get_book($fac } /** + * Recursive function that returns a nested array of facet values for use with + * theme_item_list(). + * + * @param $links_array + * Array of links to nest; each element's index denotes its plcae in hierarchy. + * @param $parent + * String with name of current level to process. + * @param $level + * Integer with the current level to process. + */ +function apachesolr_search_nested_facet_items($links_array, $parent = '', $level = 0) { + ksort($links_array); + $result = array(); + foreach ($links_array as $key => $item) { + // For items on current level, and their $key is son of $parent + if (substr_count($key, "|") == $level && ($parent == '' || strpos($key, $parent) === 0)) { + // Add this item and all items on next level + $result[$key] = array( + 'data' => $item, + 'children' => apachesolr_search_nested_facet_items($links_array, $key, $level + 1) + ); + } + } + return $result; +} + +/** * Callback function for the 'Filter by name' facet block. */ function apachesolr_search_get_username($facet) { @@ -996,11 +1083,15 @@ function theme_apachesolr_breadcrumb_uid } /** - * Return the term name from $tid. + * Return the term name from $tid, or $tid as a fallback. */ function theme_apachesolr_breadcrumb_tid($tid) { - $term = taxonomy_get_term($tid); - return $term->name; + if (function_exists('taxonomy_get_term')) { + if ($term = taxonomy_get_term($tid)) { + return $term->name; + } + } + return $tid; } /** @@ -1040,3 +1131,100 @@ function theme_apachesolr_search_snippet return implode(' ... ', $snippets) .' ...'; } +/** + * Return the contents of the "Current search" block. + * + * @param $query + * The Solr query object. + */ +function apachesolr_search_currentsearch_block($query) { + $content = ''; + $response = apachesolr_static_response_cache(); + $reflect_hierarchy = apachesolr_search_get_hierarchical_vocabularies(); + $fields = $query->get_filters(); + $links = array(); + $active_facets = array(); + $active_facets_unclick = array(); + // If current search has keys, offer current search without them + if ($keys = $query->get_query_basic()) { + $links[] = theme('apachesolr_unclick_link', $keys, $query->get_path(''), array('query' => $query->get_url_queryvalues())); + } + foreach($fields as $field) { + if ($field['#name']) { + $processed = FALSE; + + if ('tid' == $field['#name'] && module_exists('taxonomy')) { + $term = taxonomy_get_term($field['#value']); + if ($reflect_hierarchy[$term->vid]) { + + // Build data to theme this active facet hierarchically (using this term's parents) + $key = ''; + $parents = taxonomy_get_parents_all($term->tid); + $parents = array_reverse($parents); + foreach ($parents as $parent) { + + // Build field values to remove (the term's children and itself) + $children = taxonomy_get_tree($parent->vid, $parent->tid); + $children[] = $parent; + $remove = array(); + foreach ($children as $child) { + $remove[] = array('#name' => 'tid', '#value' => $child->tid); + } + // Key is a string denoting hierarchy, and includes the term name + // so it can be sorted for UX clarity. + $key .= ($key != '' ? '|' : '') . $parent->name . ':tid:' . $parent->tid; + + // Generate unclick link + $fielddisplay = theme('apachesolr_breadcrumb_tid', $parent->tid); + if (!$fielddisplay) { + $fielddisplay = $parent->tid; + } + $active_facets_unclick[$facet_fieldname][$key] = apachesolr_search_get_unclick_link($query, $fielddisplay, $remove); + } + $processed = TRUE; + } + } + + // If not a hierarchical taxonomy term, or not a taxonomy term, add to $links[] now + if (!$processed) { + $remove = array($field); + if (!($fielddisplay = theme('apachesolr_breadcrumb_' . $field['#name'], $field['#value']))) { + $fielddisplay = $field['#value']; + } + $links[] = apachesolr_search_get_unclick_link($query, $fielddisplay, $remove); + } + } + } + + // Process each $active_facets_unclick[vid] into $links[] + foreach ($active_facets_unclick as $facet_unclick) { + $links += apachesolr_search_nested_facet_items($facet_unclick); + } + + $content = theme('apachesolr_currentsearch', $response->response->numFound, $links); + return array('subject' => t('Current search'), 'content' => $content); +} + +/** + * Return an array of taxonomy facets that should be displayed hierarchically. + */ +function apachesolr_search_get_hierarchical_vocabularies() { + static $result; + + if (!isset($result)) { + $result = array(); + if (function_exists('taxonomy_get_vocabularies')) { + $vocabularies = taxonomy_get_vocabularies(); + $force_flat = variable_get('apachesolr_search_force_flat_vocabularies', array()); + foreach ($vocabularies as $voc) { + // If the vocabulary is not multiple-parent hierarchical and not + // freetagging and not designated to be forced to display flat. + if ($voc->hierarchy != 2 && $voc->tags != 1 && empty($force_flat[$voc->vid])) { + $result[$voc->vid] = 1; + } + } + } + } + + return $result; +} Index: Solr_Base_Query.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/Solr_Base_Query.php,v retrieving revision 1.1.4.43 diff -u -p -r1.1.4.43 Solr_Base_Query.php --- Solr_Base_Query.php 14 Oct 2009 13:28:40 -0000 1.1.4.43 +++ Solr_Base_Query.php 21 Nov 2009 04:50:58 -0000 @@ -332,7 +332,7 @@ class Solr_Base_Query implements Drupal_ * Optional. When set, this string overrides the query's current keywords. */ public function get_path($new_keywords = NULL) { - if ($new_keywords) { + if (isset($new_keywords)) { return $this->base_path . '/' . $new_keywords; } return $this->base_path . '/' . $this->get_query_basic();