You are here

facetapi_luceneapi.module in Facet API 6

The Search Lucene API module's implementation of the the Facet API.

File

contrib/facetapi_luceneapi/facetapi_luceneapi.module
View source
<?php

/**
 * @file
 * The Search Lucene API module's implementation of the the Facet API.
 */

// Loads term frequency cache.
module_load_include('inc', 'facetapi_luceneapi', 'facetapi_luceneapi.cache');

/**
 * Implementation of hook_menu().
 */
function facetapi_luceneapi_menu() {
  $items = array();

  // Iterates over all searchable modules, adds menu items.
  foreach (luceneapi_searchable_module_list() as $searcher => $name) {
    $items['admin/settings/' . $searcher . '/facetapi'] = array(
      'title' => 'Facets',
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'facetapi_admin_settings_form',
        $searcher,
      ),
      'access arguments' => array(
        'administer search',
      ),
      'type' => MENU_LOCAL_TASK,
      'file' => 'facetapi.admin.inc',
      'file path' => drupal_get_path('module', 'facetapi'),
      'weight' => 10,
    );
  }
  return $items;
}

/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function facetapi_luceneapi_form_facetapi_admin_settings_form_alter(&$form, $form_state) {
  if ('luceneapi_node' == $form['storage']['#value']['searcher']) {
    $form['storage']['#value']['enabled'] = facetapi_enabled_facets_get($form['storage']['#value']['searcher']);
    $form['#submit'][] = 'facetapi_luceneapi_form_facetapi_admin_settings_form';
  }
}

/**
 * Processes facetapi_admin_settings_form form submissions.
 */
function facetapi_luceneapi_form_facetapi_admin_settings_form(&$form, &$form_state) {
  $searcher = $form['storage']['#value']['searcher'];

  // Gets the newly enabled facets.
  $enabled_facets = array_diff_key(facetapi_enabled_facets_get($searcher, NULL, TRUE), $form['storage']['#value']['enabled']);

  // If facets have been enabled, re-populates termFreqs cache.
  if (!empty($enabled_facets)) {
    $batch = array(
      'operations' => array(),
      'title' => t('Rebuilding termFreqs cache'),
      'init_message' => t('Populating ...'),
      'progress_message' => t('Batch @current out of @total'),
      'error_message' => t('An error occurred populating the cache.'),
    );

    // Iterates over facets, adds batch process to populate termFreqs cache.
    foreach ($enabled_facets as $facet) {
      $variable = 'facetapi:termfreqs_cached:' . $searcher . ':::' . $facet['field'];
      variable_set($variable, TRUE);
      $batch['operations'][] = array(
        'facetapi_luceneapi_termfreqs_populate',
        array(
          $searcher,
          $facet['field'],
        ),
      );
    }

    // Let the batch begin!
    batch_set($batch);
    drupal_set_message(t('The termFreqs cache has been rebuilt.'));
  }
}

/**
 * Implementation of hook_facetapi_facet_info_alter().
 */
function facetapi_luceneapi_facetapi_facet_info_alter(array &$facets, $searcher, $type) {
  if ('luceneapi_node' == $searcher) {
    foreach ($facets as &$facet) {
      if (preg_match('/^vocabulary_(\\d+)$/', $facet['name'], $matches)) {
        $facet['field'] = 'category_' . $matches[1];
        $facet['field alias'] = 'category';
      }
    }
    unset($facet);
  }
}

/**
 * Implementation of hook_facetapi_facets_alter().
 *
 * Re-implements the logic in facetapi_facetapi_facets_alter() because
 * Search Lucene API uses a different name for the general taxonomy field.
 *
 * @see facetapi_facetapi_facets_alter()
 */
function facetapi_luceneapi_facetapi_facet_alter(&$built, $adapter, $realm) {

  /*
  if ('fieldset' == $realm_name && 'node' == $type && isset($built['category'])) {
    $built['category']['#title']       = t('Only in the category(s)');
    $built['category']['#type']        = 'select';
    $built['category']['#multiple']    = TRUE;
    $built['category']['#description'] = '';
    if (isset($built['category']['#weight']) && is_array($built['category']['#weight'])) {
      $built['category']['#weight'] = min($built['category']['#weight']);
    }
  }
  */
}

/**
 * Implementation of hook_facetapi_adapter_info().
 */
function facetapi_luceneapi_facetapi_adapter_info() {
  $adapters = array();

  // Iterates over searchable Search Lucene API modules, builds adapter information.
  foreach (luceneapi_searchable_module_list() as $searcher => $name) {
    $adapters[$searcher] = array(
      'class' => 'FacetapiLuceneapiAdapter',
      'type' => luceneapi_index_type_get($searcher),
      'file' => 'facetapi_luceneapi.adapter.inc',
    );
  }
  return $adapters;
}

/**
 * Converts all timestamps in an array to dates in ISO 8601 format.
 *
 * @param &$value
 *   An integer containing the timestamp.
 * @param $key
 *   An integer containing the array key.
 * @param $gap
 *   A string containing the gap, see FACETAPI_DATE_* constants for valid
 *   values. Defaults to FACETAPI_DATE_SECOND.
 */
function facetapi_luceneapi_timestamp_convert(&$value, $key, $gap) {
  $value = facetapi_isodate($value, $gap);
}

/**
 * Implementation of hook_apachesolr_prepare_query().
 */
function facetapi_luceneapi_luceneapi_query_alter(Zend_Search_Lucene_Search_Query $query, $module, $type = NULL) {
  facetapi_query_type_hooks_invoke($module, $query);
}

/**
 * Implementation of hook_facetapi_query_TYPE_process().
 */
function facetapi_luceneapi_facetapi_query_term_process(FacetapiAdapter $adapter, array $facet, Zend_Search_Lucene_Search_Query $query) {
  $values = $adapter
    ->getActiveFacets($facet['field alias']);
  if (empty($values)) {
    return;
  }
  try {
    if (!($multiterm = luceneapi_query_get('multiterm'))) {
      throw new LuceneAPI_Exception(t('Error instantiating multiterm query.'));
    }

    // Gets the operator.
    $operator = facetapi_setting_get('operator', $adapter
      ->getSearcher(), '', $facet['name']);
    $sign = FACETAPI_OPERATOR_OR != $operator ? 'required' : 'neither';
    foreach ($values as $value => $filter_string) {
      $term = luceneapi_term_get((string) $value, $facet['field'], TRUE);
      luceneapi_term_add($multiterm, $term, $sign, TRUE);
    }

    // If there are terms, appends subquery.
    if (count($multiterm
      ->getTerms())) {
      $multiterm
        ->setBoost(LUCENEAPI_IRRELEVANT);
      luceneapi_subquery_add($query, $multiterm, 'required', TRUE);
    }
  } catch (LuceneAPI_Exception $e) {
    luceneapi_throw_error($e, WATCHDOG_ERROR, 'facetapi_luceneapi');
  }
}

/**
 * Implementation of hook_facetapi_query_TYPE_process().
 */
function facetapi_luceneapi_facetapi_query_date_process(FacetapiAdapter $adapter, array $facet, Zend_Search_Lucene_Search_Query $query) {
  $values = $adapter
    ->getActiveFacets($facet['field alias']);
  if (empty($values)) {
    return;
  }
  try {

    // Gets the facet's operator.
    if (!($boolean = luceneapi_query_get('boolean'))) {
      throw new Exception(t('Error instantiating boolean query.'));
    }
    foreach ($values as $value => $filter_string) {
      $range = explode(' TO ', trim($value, '{[]}'));

      // Adds subquery if ranges were extracted.
      if (2 == count($range)) {
        $range = array_map('strtotime', $range);
        if ($subquery = luceneapi_query_get('range', $range[0], $range[1], FALSE, $facet['field'])) {
          luceneapi_subquery_add($boolean, $subquery, 'required', TRUE);
        }
      }
    }

    // Makes query irrelevant in scoring, appends subquery.
    $boolean
      ->setBoost(LUCENEAPI_IRRELEVANT);
    luceneapi_subquery_add($query, $boolean, 'required');
  } catch (Exception $e) {
    luceneapi_throw_error($e, WATCHDOG_ERROR, 'facetapi_luceneapi');
  }
}

/**
 * Implementation of hook_luceneapi_document_alter().
 */
function facetapi_luceneapi_luceneapi_document_alter(Zend_Search_Lucene_Document $doc, $node, $module, $type = NULL) {
  static $fields;
  if ('luceneapi_node' == $module) {

    // Maintains taxonomy ancestry for hierarchical browsing. Parent term counts
    // should also include child terms counts.
    $terms = array();
    if (isset($node->taxonomy) && is_array($node->taxonomy)) {
      foreach ($node->taxonomy as $term) {
        $ancestors = taxonomy_get_parents_all($term->tid);
        foreach ($ancestors as $ancestor) {
          $terms[$ancestor->vid][$ancestor->tid] = $ancestor->tid;
        }
      }
    }

    // Changes the field definition for categories, rebuilds the field's value
    // with all parent and child terms.
    foreach ($terms as $vid => $tids) {
      try {
        $field = $doc
          ->getField('category_' . $vid);
        $field->isStored = FALSE;
        $field->isIndexed = TRUE;
        $field->isTokenized = TRUE;
        $field->value = join(' ', $tids);
      } catch (Exception $e) {
        luceneapi_throw_error($e, WATCHDOG_ERROR, 'facetapi_luceneapi');
      }
    }

    // @todo This is nasty. We need a better way to do this.  Unfortunately, we
    // have to wait until this functionality is integrated into the core Search
    // Lucene API module.
    if (NULL === $fields) {
      $fields = array();
      foreach (facetapi_enabled_facets_get($module) as $facet) {
        $fields[] = $facet['field'];
      }
    }
    foreach ($fields as $field) {
      $variable = 'facetapi:termfreqs_cached:' . $module . ':::' . $field;
      variable_del($variable);
    }
  }
}

/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function facetapi_luceneapi_form_facetapi_facet_settings_form_alter(&$form, &$form_state) {
  $arg = arg(2);
  $modules = luceneapi_searchable_module_list();
  if (isset($modules[$arg])) {
    $breadcrumb = drupal_get_breadcrumb();
    $breadcrumb[] = l($modules[$arg], "admin/settings/{$arg}");
    $breadcrumb[] = l(t('Facets'), "admin/settings/{$arg}/facetapi");
    drupal_set_breadcrumb($breadcrumb);
  }
}

Functions

Namesort descending Description
facetapi_luceneapi_facetapi_adapter_info Implementation of hook_facetapi_adapter_info().
facetapi_luceneapi_facetapi_facet_alter Implementation of hook_facetapi_facets_alter().
facetapi_luceneapi_facetapi_facet_info_alter Implementation of hook_facetapi_facet_info_alter().
facetapi_luceneapi_facetapi_query_date_process Implementation of hook_facetapi_query_TYPE_process().
facetapi_luceneapi_facetapi_query_term_process Implementation of hook_facetapi_query_TYPE_process().
facetapi_luceneapi_form_facetapi_admin_settings_form Processes facetapi_admin_settings_form form submissions.
facetapi_luceneapi_form_facetapi_admin_settings_form_alter Implementation of hook_form_FORM_ID_alter().
facetapi_luceneapi_form_facetapi_facet_settings_form_alter Implementation of hook_form_FORM_ID_alter().
facetapi_luceneapi_luceneapi_document_alter Implementation of hook_luceneapi_document_alter().
facetapi_luceneapi_luceneapi_query_alter Implementation of hook_apachesolr_prepare_query().
facetapi_luceneapi_menu Implementation of hook_menu().
facetapi_luceneapi_timestamp_convert Converts all timestamps in an array to dates in ISO 8601 format.