You are here

search_api_live_results.module in Search API live results 7

File

search_api_live_results.module
View source
<?php

define('SEARCH_API_LIVE_RESULTS_METHOD_OR', 1);
define('SEARCH_API_LIVE_RESULTS_METHOD_AND', 2);
define('SEARCH_API_LIVE_RESULTS_METHOD_KEYWORD', 3);

// Include the files with the module-specific implementations.
require_once 'search_api_live_results.search_api_page.inc';
require_once 'search_api_live_results.search_api_views.inc';

/**
 * Implements hook_menu().
 */
function search_api_live_results_menu() {
  $path = drupal_get_path('module', 'search_api_live_results');

  // Autocompletion path
  $items['search_api_live_results/%search_api_live_results_search'] = array(
    'title' => 'Search API live results',
    'page callback' => 'search_api_live_results_json',
    'page arguments' => array(
      1,
    ),
    'access arguments' => array(
      'use_search_api_live_results',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'search_api_live_results.pages.inc',
    'file path' => $path . '/includes',
  );

  // Admin UI
  $items['admin/config/search/search_api/index/%search_api_index/live-results'] = array(
    'title' => 'Live results',
    'description' => 'Add live results to searches for this index.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'search_api_live_results_admin_overview',
      5,
    ),
    'access arguments' => array(
      'administer search_api',
    ),
    'weight' => -1,
    'type' => MENU_LOCAL_TASK,
    'context' => MENU_CONTEXT_INLINE | MENU_CONTEXT_PAGE,
    'file' => 'search_api_live_results.admin.inc',
    'file path' => $path . '/includes',
  );
  $items['admin/config/search/search_api/index/%/live-results/%search_api_live_results_search/edit'] = array(
    'title' => 'Edit live results settings',
    'description' => 'Edit the live results settings of a search.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'search_api_live_results_admin_search_edit',
      7,
    ),
    'access arguments' => array(
      'administer search_api',
    ),
    'file' => 'search_api_live_results.admin.inc',
    'file path' => $path . '/includes',
  );
  $items['admin/config/search/search_api/index/%/live-results/%search_api_live_results_search/delete'] = array(
    'title' => 'Delete live results settings',
    'description' => 'Delete the live results settings of a search.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'search_api_live_results_admin_search_delete',
      7,
    ),
    'access arguments' => array(
      'administer search_api',
    ),
    'file' => 'search_api_live_results.admin.inc',
    'file path' => $path . '/includes',
  );
  return $items;
}

/**
 * Implements hook_entity_info().
 */
function search_api_live_results_entity_info() {
  $info['search_api_live_results_search'] = array(
    'label' => t('Live results search'),
    'controller class' => 'EntityAPIControllerExportable',
    'entity class' => 'SearchApiLiveResultsSearch',
    'base table' => 'search_api_live_results_search',
    'uri callback' => 'search_api_live_results_search_url',
    'module' => 'search_api_live_results',
    'exportable' => TRUE,
    'entity keys' => array(
      'id' => 'id',
      'name' => 'machine_name',
      'label' => 'name',
    ),
  );
  return $info;
}

/**
 * Implements hook_permission().
 */
function search_api_live_results_permission() {
  return array(
    'use_search_api_live_results' => array(
      'title' => t('Use live result search'),
    ),
  );
}

/**
 * Implements hook_theme().
 */
function search_api_live_results_theme($existing, $type, $theme, $path) {
  return array(
    'live_results_search' => array(
      'render element' => 'element',
    ),
  );
}

/**
 * Theme callback for the live results form element
 * @param type $variables
 * @return type 
 */
function theme_live_results_search($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'text';
  element_set_attributes($element, array(
    'id',
    'name',
    'value',
    'size',
    'maxlength',
  ));
  _form_set_class($element, array(
    'form-text',
  ));
  $extra = '';
  if ($element['#autocomplete_path']) {
    $parts = explode("/", $element['#autocomplete_path']);

    //'search_api_live_results/search_api_page_1',
    $search = search_api_live_results_search_load(array_pop($parts));
    drupal_add_library('system', 'drupal.autocomplete');
    drupal_add_js(drupal_get_path('module', 'search_api_live_results') . '/js/search_api_live_results.js');
    drupal_add_js(array(
      'search_api_live_results' => array(
        'min_length' => $search->options['min_length'] != NULL ? intval($search->options['min_length']) : 3,
        'auto_hide' => isset($search->options['auto_hide']) && $search->options['auto_hide'] == 0 ? FALSE : TRUE,
      ),
    ), 'setting');
    $element['#attributes']['class'][] = 'form-autocomplete';
    $element['#attributes']['class'][] = 'live-results-search-textfield';
    $attributes = array();
    $attributes['type'] = 'hidden';
    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
    $query = array();
    if (isset($element['#autocomplete_query'])) {
      $query = $element['#autocomplete_query'];
      $element['#attributes']['class'][] = 'caching-method-enabled';
    }
    $attributes['value'] = url($element['#autocomplete_path'], array(
      'absolute' => TRUE,
      'query' => $query,
    ));
    $attributes['disabled'] = 'disabled';
    $attributes['class'][] = 'live-result-autocomplete';
    $extra = '<input' . drupal_attributes($attributes) . ' />';
  }
  $output = '<input' . drupal_attributes($element['#attributes']) . ' />';
  return $output . $extra;
}

/**
* Implements hook_entity_info_alter().
*/
function search_api_live_results_entity_info_alter(&$entity_info) {
  $entity_info['node']['view modes']['live_results_search'] = array(
    'label' => t('Live results search'),
    'custom settings' => TRUE,
  );

  // @TODO ADD to all entities.
}

/**
 * Implements hook_element_info().
 */
function search_api_live_results_element_info() {
  return array(
    'live_results_search' => array(
      '#input' => TRUE,
      '#size' => 60,
      '#maxlength' => 128,
      '#autocomplete_path' => FALSE,
      '#process' => array(
        'ajax_process_form',
      ),
      '#theme' => 'live_results_search',
    ),
  );
}

/**
 * Implements hook_search_api_index_delete().
 */
function search_api_live_results_search_api_index_delete(SearchApiIndex $index) {
  if (!$index
    ->hasStatus(ENTITY_IN_CODE)) {
    $ids = db_query('SELECT id FROM {search_api_live_results_search} WHERE index_id = :id', array(
      ':id' => $index->machine_name,
    ))
      ->fetchCol();
    if ($ids) {
      entity_delete_multiple('search_api_live_results_search', $ids);
    }
  }
}

/**
 * Implements hook_search_api_live_results_types().
 *
 * Adds search types for search pages and views. The actual implementations lie
 * in the above include files.
 */
function search_api_live_results_search_api_live_results_types() {
  $types = array();
  if (module_exists('search_api_page')) {
    $types['search_api_page'] = array(
      'name' => t('Search pages'),
      'description' => t('Searches provided by the <em>Search pages</em> module.'),
      'list searches' => 'search_api_live_results_pages_searches',
      'create query' => 'search_api_live_results_pages_query',
    );
  }
  if (module_exists('search_api_views')) {
    $types['search_api_views'] = array(
      'name' => t('Search views'),
      'description' => t('Searches provided by the <em>Search views</em> module.'),
      'list searches' => 'search_api_live_results_views_searches',
      'create query' => 'search_api_live_results_views_query',
    );
  }
  return $types;
}

/**
 * Get information about all search types, or a specific one.
 *
 * @param $type
 *   (optional) The name of a type.
 *
 * @return
 *   If $type was not given, an array containing information about all search
 *   types. Otherwise, either information about the specified type, or NULL if
 *   the type is not known.
 *
 * @see hook_search_api_autocomplete_types()
 */
function search_api_live_results_get_types($type = NULL) {
  $types =& drupal_static(__FUNCTION__);
  if (!isset($types)) {
    $types = module_invoke_all('search_api_live_results_types');
    drupal_alter('search_api_live_results_types', $types);
  }
  if (isset($type)) {
    return isset($types[$type]) ? $types[$type] : NULL;
  }
  return $types;
}

/**
 * Loads an live results search entity.
 *
 * @param $id
 *   Either the ID or machine name of an live results search.
 * @param $reset
 *   Whether to reset the internal cache.
 *
 * @return SearchApiLiveResultsSearch
 *   The specified live result search entity, or FALSE if it doesn't exist.
 */
function search_api_live_results_search_load($id, $reset = FALSE) {
  $ret = search_api_live_results_search_load_multiple(array(
    $id,
  ), array(), $reset);
  return $ret ? reset($ret) : FALSE;
}

/**
 * Loads live results search entities.
 *
 * @param $ids
 *   An array of IDs or machine names, or FALSE to load all searches.
 * @param $conditions
 *   An associative array of conditions on the {search_api_live_results_search}
 *   table.
 * @param $reset
 *   Whether to reset the internal cache.
 *
 * @return array
 *   An array of all live results search entities that meet the criteria.
 *
 * @see entity_load()
 */
function search_api_live_results_search_load_multiple($ids = FALSE, array $conditions = array(), $reset = FALSE) {
  return entity_load_multiple_by_name('search_api_live_results_search', $ids, $conditions, $reset);
}

/**
 * Class describing the settings for a certain search for which autocompletion
 * is available.
 */
class SearchApiLiveResultsSearch extends Entity {

  // Entity properties, loaded from the database:

  /**
   * @var integer
   */
  public $id;

  /**
   * @var string
   */
  public $machine_name;

  /**
   * @var string
   */
  public $name;

  /**
   * @var integer
   */
  public $index_id;

  /**
   * @var string
   */
  public $type;

  /**
   * @var boolean
   */
  public $enabled;

  /**
   * An array of options for this search, containing any of the following:
   * - results: Boolean indicating whether to also list the estimated number of
   *   results for each suggestion (if possible).
   * - custom: An array of type-specific settings.
   *
   * @var array
   */
  public $options = array();

  // Inferred properties, for caching:

  /**
   * @var SearchApiIndex
   */
  protected $index;

  /**
   * @var SearchApiServer
   */
  protected $server;

  /**
   * Constructor.
   *
   * @param array $values
   *   The entity properties.
   */
  public function __construct(array $values = array()) {
    parent::__construct($values, 'search_api_live_results_search');
  }

  /**
   * @return SearchApiIndex
   *   The index this search belongs to.
   */
  public function index() {
    if (!isset($this->index)) {
      $this->index = search_api_index_load($this->index_id);
      if (!$this->index) {
        $this->index = FALSE;
      }
    }
    return $this->index;
  }

  /**
   * @return SearchApiServer
   *   The server this search would at the moment be executed on.
   */
  public function server() {
    if (!isset($this->server)) {
      if (!$this
        ->index() || !$this
        ->index()->server) {
        $this->server = FALSE;
      }
      else {
        $this->server = $this
          ->index()
          ->server();
        if (!$this->server) {
          $this->server = FALSE;
        }
      }
    }
    return $this->server;
  }

  /**
   * Helper method for altering a textfield form element to use live results.
   */
  public function alterElement(array &$element) {
    if (user_access('use_search_api_live_results')) {
      $element['#type'] = 'live_results_search';
      if (isset($this->options['caching']) && $this->options['caching']) {
        $element['#autocomplete_path'] = drupal_get_path('module', 'search_api_live_results') . '/search_api_live_results.results.php';
        $element['#autocomplete_query'] = array(
          'search' => $this->machine_name,
        );
      }
      else {
        $element['#autocomplete_path'] = 'search_api_live_results/' . $this->machine_name;
      }
    }
  }

  /**
   * Create the query that would be issued for this search for the complete keys.
   *
   * @param $complete
   *   A string containing the complete search keys.
   * @param $incomplete
   *   A string containing the incomplete last search key.
   *
   * @return SearchApiQueryInterface
   *   The query that would normally be executed when only $complete was entered
   *   as the search keys for this search.
   */
  public function getQuery($keys) {
    $info = search_api_live_results_get_types($this->type);
    if (empty($info['create query'])) {
      return NULL;
    }
    $query = $info['create query']($this, $keys);
    return $query;
  }

}

Functions

Constants

Classes

Namesort descending Description
SearchApiLiveResultsSearch Class describing the settings for a certain search for which autocompletion is available.