facetapi_apachesolr.module in Facet API 6
The Apache Solr Search Integration module's implementation of the the Facet API.
File
contrib/facetapi_apachesolr/facetapi_apachesolr.moduleView source
<?php
/**
* @file
* The Apache Solr Search Integration module's implementation of the the Facet
* API.
*/
/**
* Implementation of hook_menu().
*/
function facetapi_apachesolr_menu() {
$items = array();
$items['admin/settings/apachesolr/facets'] = array(
'title' => 'Facets',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_admin_settings_form',
'apachesolr_search',
),
'access arguments' => array(
'administer search',
),
'type' => MENU_LOCAL_TASK,
'file' => 'facetapi.admin.inc',
'file path' => drupal_get_path('module', 'facetapi'),
'weight' => -9,
);
return $items;
}
/**
* Implementation of hook_menu_alter().
*/
function facetapi_apachesolr_menu_alter(&$items) {
$items['admin/settings/apachesolr/enabled-filters']['access callback'] = FALSE;
}
/**
* Implementation of hook_facetapi_adapter_info().
*/
function facetapi_apachesolr_facetapi_adapter_info() {
return array(
'apachesolr_search' => array(
'class' => 'FacetapiApachesolrAdapter',
'type' => 'node',
'file' => 'facetapi_apachesolr.adapter.inc',
),
);
}
/**
* Implementation of hook_facetapi_facet_info_alter().
*
* Modifies fields for vocabulary facets.
*/
function facetapi_apachesolr_facetapi_facet_info_alter(array &$facets, $searcher, $type) {
if ('apachesolr_search' == $searcher) {
foreach ($facets as &$facet) {
if (preg_match('/^vocabulary_(\\d+)$/', $facet['name'], $matches)) {
$facet['field'] = 'im_vid_' . $matches[1];
$facet['field alias'] = 'tid';
}
}
unset($facet);
}
}
/**
* Implementation of hook_apachesolr_prepare_query().
*
* Invokes type hooks, adds filters.
*/
function facetapi_apachesolr_apachesolr_prepare_query($query, &$params, $caller) {
facetapi_query_type_hooks_invoke('apachesolr_search', $params, $query);
// Gets enabled facets, adds filter queries to $params.
$adapter = facetapi_adapter_load('apachesolr_search');
foreach (facetapi_enabled_facets_get('apachesolr_search') as $facet) {
$queries = array();
foreach ($adapter
->getActiveItems($facet) as $value => $item) {
$queries[] = $facet['field alias'] . ':' . $value;
}
if (!empty($queries)) {
$params['fq'][$facet['field alias']] = $queries;
}
}
}
/**
* Implementation of hook_facetapi_query_QUERY_TYPE_prepare().
*/
function facetapi_apachesolr_facetapi_query_term_prepare(FacetapiAdapter $adapter, array $facet, &$params, $query) {
$searcher = $adapter
->getSearcher();
// Adds the operator parameter.
$operator = facetapi_setting_get('operator', $searcher, '', $facet['name']);
$ex = FACETAPI_OPERATOR_OR != $operator ? '' : "{!ex={$facet['field']}}";
$params['facet.field'][] = $ex . $facet['field'];
// Adds "hard limit" parameter to prevent too many return values.
$limit = facetapi_setting_get('hard_limit', $searcher, '', $facet['name']);
$params['f.' . $facet['field'] . '.facet.limit'] = $limit !== NULL ? (int) $limit : 20;
}
/**
* Implementation of hook_facetapi_query_QUERY_TYPE_prepare().
*/
function facetapi_apachesolr_facetapi_query_date_prepare(FacetapiAdapter $adapter, array $facet, &$params, $query) {
$searcher = $adapter
->getSearcher();
// Gets the data range in formats that Solr understands.
list($start, $end, $gap) = facetapi_apachesolr_date_range($query, $facet['field']);
$params['facet.date'][] = $facet['field'];
$params['f.' . $facet['field'] . '.facet.date.start'] = $start;
$params['f.' . $facet['field'] . '.facet.date.end'] = $end;
$params['f.' . $facet['field'] . '.facet.date.gap'] = $gap;
// Adds "hard limit" parameter to prevent too many return values.
$limit = facetapi_setting_get('hard_limit', $searcher, '', $facet['name']);
$params['f.' . $facet['field'] . '.facet.limit'] = $limit !== NULL ? (int) $limit : 20;
}
/**
* Gets the range of dates we are using.
*
* @param $query
* A Solr_Base_Query object.
* @param $facet_field
* A string containing the name of the facet field.
*
* @return
* An array containing the gap and range information.
*
* @todo integrate this into facetapi_apachesolr_facetapi_date_range_prepare()
* once we have a "range limit callback".
*/
function facetapi_apachesolr_date_range(Solr_Base_Query $query, $facet_field) {
// Captures adapter, facet.
// @todo Do we need some defensive coding here?
// @todo Is facet field the facet name or the field alias?
$adapter = facetapi_adapter_load('apachesolr_search');
$enabled_facets = facetapi_enabled_facets_get('apachesolr_search');
$facet = $enabled_facets[$facet_field];
// Attempts to get next gap from passed date filters.
$return = NULL;
foreach ($adapter
->getActiveItems($facet) as $value => $item) {
if ($gap = facetapi_date_gap_get($item['start'], $item['end'])) {
$next_gap = facetapi_next_date_gap_get($gap, FACETAPI_DATE_MINUTE);
if ($next_gap == $gap) {
$next_gap = NULL;
}
$return = array(
"{$item['start']}/{$next_gap}",
"{$item['end']}+1{$next_gap}/{$next_gap}",
"+1{$next_gap}",
);
}
}
// If no filters were passed, get default range.
if (NULL === $return) {
// Builds SQL that gets minimum and maximum values from node table.
$minimum = $maximum = FALSE;
if (!empty($facet['min callback']) && function_exists($facet['min callback'])) {
$minimum = $facet['min callback']($facet);
}
if (!empty($facet['max callback']) && function_exists($facet['max callback'])) {
$maximum = $facet['max callback']($facet);
}
// Gets the default gap.
$gap = FACETAPI_DATE_YEAR;
if ($minimum && $maximum) {
$gap = facetapi_timestamp_gap_get($minimum, $maximum);
$minimum = facetapi_isodate($minimum, $gap);
$maximum = facetapi_isodate($maximum, $gap);
$return = array(
"{$minimum}/{$gap}",
"{$maximum}+1{$gap}/{$gap}",
"+1{$gap}",
);
}
}
// Returns the range information.
return $return;
}
/**
* Implementation of hook_facetapi_facet_QUERY_TYPE_build().
*/
function facetapi_apachesolr_facetapi_facet_term_build(FacetapiAdapter $adapter, array $facet) {
$build = array();
if ($response = apachesolr_static_response_cache()) {
$values = (array) $response->facet_counts->facet_fields->{$facet['field']};
foreach ($values as $value => $count) {
$build[$value] = array(
'#count' => $count,
);
}
}
return $build;
}
/**
* Implementation of hook_facetapi_facet_QUERY_TYPE_build().
*/
function facetapi_apachesolr_facetapi_facet_date_build(FacetapiAdapter $adapter, array $facet) {
$build = array();
if (!($response = apachesolr_static_response_cache())) {
return array();
}
// Gets total number of documents matched in search.
// NOTE: We need a Solr_Base_Query::get_solr() method.
static $total;
if (NULL === $total) {
if ($raw_response = json_decode($response
->getRawResponse())) {
$total = $raw_response->response->numFound;
}
else {
$total = 0;
}
}
// Gets the active date facets, starts to builds the "parent - child"
// relationships.
$parent = NULL;
foreach ($adapter
->getActiveItems($facet) as $value => $item) {
// Builds the raw facet "value", the count for selected items will be the
// total number of rows returned in the query.
$build[$value] = array(
'#count' => $total,
);
// If there is a previous item, there is a parent, uses a reference so the
// arrays are populated when they are updated.
if (NULL !== $parent) {
$build[$parent]['#item_children'][$value] =& $build[$value];
$build[$value]['#item_parents'][$parent] = $parent;
}
// Stores the last value iterated over.
$parent = $value;
}
// Gets raw facet data from the Solr server.
if (isset($response->facet_counts->facet_dates)) {
$raw_data = (array) $response->facet_counts->facet_dates->{$facet['field']};
}
else {
$raw_data = array();
}
$end = !empty($raw_data['end']) ? $raw_data['end'] : '';
$gap = !empty($raw_data['gap']) ? $raw_data['gap'] : '';
unset($raw_data['end']);
unset($raw_data['gap']);
// Treat each date facet as a range start, and use the next date facet
// as range end. Use 'end' for the final end.
$range_end = array();
$previous = NULL;
foreach ($raw_data as $value => $count) {
if (isset($previous)) {
$range_end[$previous] = $value;
}
$previous = $value;
}
$range_end[$previous] = $end;
// Builds facet counts object used by the server.
foreach ($raw_data as $value => $count) {
if ($count) {
$new_value = '[' . $value . ' TO ' . $range_end[$value] . ']';
$build[$new_value] = array(
'#count' => $count,
'#active' => 0,
);
if (NULL !== $parent) {
$build[$parent]['#item_children'][$new_value] =& $build[$new_value];
$build[$new_value]['#item_parents'][$parent] = $parent;
}
}
}
return $build;
}
/**
* Implementation of hook_form_FORM_ID_alter().
*
* Adds breadcrumb trail for Apache Solr administrative pages.
*/
function facetapi_apachesolr_form_facetapi_facet_settings_form_alter(&$form, &$form_state) {
if ('apachesolr_search' == arg(2)) {
$breadcrumb = drupal_get_breadcrumb();
$breadcrumb[] = l(t('Apache Solr'), 'admin/settings/apachesolr');
$breadcrumb[] = l(t('Facets'), 'admin/settings/apachesolr/facets');
drupal_set_breadcrumb($breadcrumb);
}
}
/**
* Implementation of hook_form_FORM_ID_alter().
*
* Hides Apache Solr core facet settings.
*/
function facetapi_apachesolr_form_apachesolr_settings_alter(&$form, &$form_state) {
$form['apachesolr_facetstyle'] = array(
'#type' => 'value',
'#value' => $form['apachesolr_facetstyle']['#default_value'],
);
$form['apachesolr_search_browse'] = array(
'#type' => 'value',
'#value' => $form['apachesolr_search_browse']['#default_value'],
);
}