facetapi.module in Facet API 7
Same filename and directory in other branches
An abstracted facet API that can be used by various search backends.
File
facetapi.moduleView source
<?php
/**
* @file
* An abstracted facet API that can be used by various search backends.
*/
/**
* Constant for the "AND" operator.
*/
define('FACETAPI_OPERATOR_AND', 'and');
/**
* Constant for the "OR" operator.
*/
define('FACETAPI_OPERATOR_OR', 'or');
/**
* String that represents a time gap of a year between two dates.
*/
define('FACETAPI_DATE_YEAR', 'YEAR');
/**
* String that represents a time gap of a month between two dates.
*/
define('FACETAPI_DATE_MONTH', 'MONTH');
/**
* String that represents a time gap of a day between two dates.
*/
define('FACETAPI_DATE_DAY', 'DAY');
/**
* String that represents a time gap of an hour between two dates.
*/
define('FACETAPI_DATE_HOUR', 'HOUR');
/**
* String that represents a time gap of a minute between two dates.
*/
define('FACETAPI_DATE_MINUTE', 'MINUTE');
/**
* String that represents a time gap of a second between two dates.
*/
define('FACETAPI_DATE_SECOND', 'SECOND');
/**
* Date string for ISO 8601 date formats.
*/
define('FACETAPI_DATE_ISO8601', 'Y-m-d\\TH:i:s\\Z');
/**
* Regex pattern for range queries.
*/
define('FACETAPI_REGEX_RANGE', '/^[\\[\\{](\\S+) TO (\\S+)[\\]\\}]$/');
/**
* Regex pattern for date queries.
*/
define('FACETAPI_REGEX_DATE', '/^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})Z$/');
/**
* Regex pattern for date ranges.
*/
define('FACETAPI_REGEX_DATE_RANGE', '/^\\[(' . trim(FACETAPI_REGEX_DATE, '/^$') . ') TO (' . trim(FACETAPI_REGEX_DATE, '/^$') . ')\\]$/');
// Calls block specific hooks and overrides.
module_load_include('inc', 'facetapi', 'facetapi.block');
/**
* Implements hook_facetapi_hook_info().
*/
function facetapi_hook_info() {
return array(
'facetapi_adapters' => array(
'group' => 'facetapi',
),
'facetapi_dependencies' => array(
'group' => 'facetapi',
),
'facetapi_empty_behaviors' => array(
'group' => 'facetapi',
),
'facetapi_facet_info' => array(
'group' => 'facetapi',
),
'facetapi_filters' => array(
'group' => 'facetapi',
),
'facetapi_query_types' => array(
'group' => 'facetapi',
),
'facetapi_realm_info' => array(
'group' => 'facetapi',
),
'facetapi_sort_info' => array(
'group' => 'facetapi',
),
'facetapi_url_processors' => array(
'group' => 'facetapi',
),
'facetapi_widgets' => array(
'group' => 'facetapi',
),
'current_search_items' => array(
'group' => 'facetapi',
),
);
}
/**
* Implements hook_menu().
*/
function facetapi_menu() {
$items = array();
// Builds the realm settings forms for each searcher.
foreach (facetapi_get_searcher_info() as $searcher => $searcher_info) {
// Only build router items automatically if a path is provided.
if (empty($searcher_info['path'])) {
continue;
}
// Builds realm settings.
$first = TRUE;
foreach (facetapi_get_realm_info() as $realm_name => $realm) {
if ($first) {
$first = FALSE;
// Add the first realm as a default local task.
$items[$searcher_info['path'] . '/facets'] = array(
'title' => 'Facets',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_realm_settings_form',
$searcher,
$realm_name,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_LOCAL_TASK,
'file' => 'facetapi.admin.inc',
);
$items[$searcher_info['path'] . '/facets/' . $realm_name] = array(
'title' => $realm['label'],
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => $realm['weight'],
);
}
else {
// Add all additional realms as local tasks.
$items[$searcher_info['path'] . '/facets/' . $realm_name] = array(
'title' => $realm['label'],
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_realm_settings_form',
$searcher,
$realm_name,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_LOCAL_TASK,
'file' => 'facetapi.admin.inc',
);
}
}
}
$items['admin/config/search/facetapi/%facetapi_adapter/%facetapi_realm/%facetapi_facet/edit'] = array(
'title' => 'Configure facet display',
'load arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_facet_display_form',
4,
5,
6,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_LOCAL_ACTION,
'context' => MENU_CONTEXT_INLINE,
'weight' => -15,
'file' => 'facetapi.admin.inc',
);
$items['admin/config/search/facetapi/%facetapi_adapter/%facetapi_realm/%facetapi_dependencies/dependencies'] = array(
'title' => 'Configure facet dependencies',
'load arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_facet_dependencies_form',
4,
5,
6,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_LOCAL_ACTION,
'context' => MENU_CONTEXT_INLINE,
'weight' => -10,
'file' => 'facetapi.admin.inc',
);
$items['admin/config/search/facetapi/%facetapi_adapter/%facetapi_realm/%facetapi_filters/filters'] = array(
'title' => 'Configure facet filters',
'load arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_facet_filters_form',
4,
5,
6,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_LOCAL_ACTION,
'context' => MENU_CONTEXT_INLINE,
'weight' => -5,
'file' => 'facetapi.admin.inc',
);
$items['admin/config/search/facetapi/%facetapi_adapter/%facetapi_realm/%facetapi_facet/export'] = array(
'title' => 'Export facet configuration',
'load arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_export_form',
4,
5,
6,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_NORMAL_ITEM,
'file' => 'facetapi.admin.inc',
);
$items['admin/config/search/facetapi/%facetapi_adapter/%facetapi_realm/%facetapi_facet/revert'] = array(
'title' => 'Revert facet configuration',
'load arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'facetapi_revert_form',
4,
5,
6,
),
'access callback' => 'facetapi_access_callback',
'type' => MENU_NORMAL_ITEM,
'file' => 'facetapi.admin.inc',
);
return $items;
}
/**
* Implements hook_ctools_plugin_type().
*/
function facetapi_ctools_plugin_type() {
return array(
'adapters' => array(
'use hooks' => TRUE,
),
'dependencies' => array(
'use hooks' => TRUE,
),
'empty_behaviors' => array(
'use hooks' => TRUE,
),
'filters' => array(
'use hooks' => TRUE,
),
'query_types' => array(
'use hooks' => TRUE,
),
'url_processors' => array(
'use hooks' => TRUE,
),
'widgets' => array(
'use hooks' => TRUE,
),
);
}
/**
* Implements hook_theme().
*/
function facetapi_theme() {
return array(
'facetapi_title' => array(
'variables' => array(
'title' => NULL,
'facet' => array(),
),
'file' => 'facetapi.theme.inc',
),
'facetapi_facet_missing' => array(
'variables' => array(
'field_name' => NULL,
),
'file' => 'facetapi.theme.inc',
),
'facetapi_count' => array(
'variables' => array(
'count' => NULL,
),
'file' => 'facetapi.theme.inc',
),
'facetapi_link_inactive' => array(
'variables' => array(
'text' => NULL,
'path' => NULL,
'options' => array(),
'count' => 0,
),
'file' => 'facetapi.theme.inc',
),
'facetapi_link_active' => array(
'variables' => array(
'text' => NULL,
'path' => NULL,
'options' => array(),
),
'file' => 'facetapi.theme.inc',
),
'facetapi_deactivate_widget' => array(
'variables' => array(
'text' => NULL,
),
'file' => 'facetapi.theme.inc',
),
'facetapi_accessible_markup' => array(
'variables' => array(
'text' => NULL,
'active' => NULL,
),
'file' => 'facetapi.theme.inc',
),
'facetapi_realm_settings_table' => array(
'render element' => 'element',
'file' => 'facetapi.admin.inc',
),
'facetapi_sort_settings_table' => array(
'render element' => 'element',
'file' => 'facetapi.admin.inc',
),
'facetapi_filter_settings_table' => array(
'render element' => 'element',
'file' => 'facetapi.admin.inc',
),
);
}
/**
* Returns the access callback.
*
* Custom access callback. Checks if the user has either the "administer search"
* OR "administer facets" permissions.
*
* @param stdObject|NULL $account
* (optional) The account to check, if not given use currently logged in user.
*
* @return bool
* TRUE if the user has access to the resource, FALSE otherwise.
*/
function facetapi_access_callback($account = NULL) {
global $user;
if (!isset($account)) {
$account = $user;
}
return user_access('administer search', $account) || user_access('administer facets', $account);
}
/**
* Implements hook_permission().
*/
function facetapi_permission() {
return array(
'administer facets' => array(
'title' => t('Administer Facets'),
),
);
}
/**
* Implements hook_i18n_string_info().
*/
function facetapi_i18n_string_info() {
$groups['facetapi'] = array(
'title' => t('Facet API'),
'description' => t('Translatable link text.'),
'format' => FALSE,
'list' => TRUE,
);
return $groups;
}
/**
* Implements hook_i18n_string_list().
*/
function facetapi_i18n_string_list($group) {
$strings = $texts = array();
if ($group == 'facetapi') {
// Get all enabled facets by looping over all searchers and realms.
foreach (facetapi_get_searcher_info() as $searcher => $searcher_info) {
$adapter = facetapi_adapter_load($searcher_info['name']);
foreach (facetapi_get_realm_info() as $realm) {
// Retrieve the "Show more/fewer" strings from the facet settings.
foreach ($adapter
->getEnabledFacets() as $facet) {
$settings = $adapter
->getFacetSettings($facet, $realm);
// Avoid adding duplicate strings by using the string itself as key.
$strings['facetapi']['link_text'][$settings->settings['facet_more_text']]['text'] = $settings->settings['facet_more_text'];
$strings['facetapi']['link_text'][$settings->settings['facet_fewer_text']]['text'] = $settings->settings['facet_fewer_text'];
// If title has been overridden, we should translate it.
if ($settings->settings['title_override']) {
$strings['facetapi']['title_text'][$settings->settings['title']]['text'] = $settings->settings['title'];
}
}
}
}
}
return $strings;
}
/**
* Instantiates the adapter plugin associated with the searcher.
*
* @param $searcher
* The machine readable name of searcher.
*
* @return FacetapiAdapter
* The adapter object, FALSE if the object can't be loaded.
*/
function facetapi_adapter_load($searcher) {
$adapters =& drupal_static(__FUNCTION__, array());
if (!isset($adapters[$searcher])) {
$searcher_info = facetapi_get_searcher_info();
if (isset($searcher_info[$searcher]['adapter'])) {
ctools_include('plugins');
$id = $searcher_info[$searcher]['adapter'];
$class = ctools_plugin_load_class('facetapi', 'adapters', $id, 'handler');
$adapters[$searcher] = $class ? new $class($searcher_info[$searcher]) : FALSE;
}
else {
$adapters[$searcher] = FALSE;
}
}
return $adapters[$searcher];
}
/**
* Loads the dependency plugins associated with the facet.
*
* @param string $facet_name
* The machine readable name of the facet.
* @param string $searcher
* The machine readable name of the searcher module.
*
* @return array
* An array of FacetapiDependency objects, FALSE if no plugins.
*/
function facetapi_dependencies_load($facet_name, $searcher) {
$dependencies = array();
$facet = facetapi_facet_load($facet_name, $searcher);
if ($facet && ($adapter = facetapi_adapter_load($searcher))) {
foreach ($facet['dependency plugins'] as $id) {
// NOTE: CTools plugin component is loaded by facetapi_adapter_load().
$class = ctools_plugin_load_class('facetapi', 'dependencies', $id, 'handler');
$settings = $adapter
->getFacet($facet)
->getSettings();
$dependencies[] = new $class($id, $adapter, $facet, $settings);
}
}
return $dependencies ? $dependencies : FALSE;
}
/**
* Returns array of filter options available to the facet.
*
* @param string $facet_name
* The machine readable name of the facet.
* @param string $searcher
* The machine readable name of the searcher.
*
* @return array
* An array of FacetapiFilter objects, FALSE if no plugins.
*/
function facetapi_filters_load($facet_name, $searcher) {
$filters = array(
'plugins' => array(),
);
if ($filters['facet'] = facetapi_facet_load($facet_name, $searcher)) {
$filters['plugins'] = facetapi_get_filters($filters['facet']);
}
return $filters['plugins'] ? $filters : FALSE;
}
/**
* Returns a realm definition.
*
* @param string $realm_name
* The machine readable name of the realm.
*
* @return array
* An array containing the realm definition, FALSE if the realm is invalid.
* - name: The machine name of the realm.
* - label: The human readable name of the realm displayed in the admin UI.
* - description: The description of the realm displayed in the admin UI.
* - element type: The type of element facets are rendered as, such as 'links'
* or 'form elements'.
* - default widget: The default widget plugin id for facets in the realm.
* - settings callback: A callback that alters the realm settings form.
* - sortable: Whether the facets can be sorted via the admin UI.
* - weight: The weight of the realm's menu item in comparison to the others.
*/
function facetapi_realm_load($realm_name) {
$realm_info = facetapi_get_realm_info();
return isset($realm_info[$realm_name]) ? $realm_info[$realm_name] : FALSE;
}
/**
* Returns a facet definition.
*
* @param string $facet_name
* The machine readable name of the facet.
* @param string $searcher
* The machine readable name of the searcher.
*
* @return array
* An array containing the facet definition, FALSE if the facet is invalid.
* - name: Machine readable name of the facet.
* - label: Human readable name of the facet displayed in settings forms.
* - description: Description of the facet displayed in settings forms.
* - field: The field name used by the backend to store and retrieve data from
* the search index it is associated with.
* - field alias: The query string variable inside of the filter key used to
* pass the filter information through the query string.
* - field api name: The machine readable name of the Field API field data the
* facet is associated with, FALSE if it is not associated with a field.
* - field api bundles: An array of entity names that this field contains
* bundle information for.
* - query types: The query type plugins that that this facet supports. For
* example, numeric fields support "term" and "range_filter" queries.
* - alter callbacks: Callbacks that alter the initialized render array
* returned by the query type plugin. Defaults to an empty array.
* - dependency plugins: An array of dependency plugin IDs that are supported
* by this facet.
* - default widget: The widget plugin ID used if no plugin has been selected
* or the one selected is not valid.
* - allowed operators: An array keyed by operator constant to boolean values
* specifying whether the operator is supported.
* - facet missing allowed: Whether or not missing facets are allowed.
* - facet mincount allowed: Whether or not the facet supports the "minimum
* facet count" setting.
* - weight: The weight of the facet
* - map callback: The callback used to map the raw values returned by the
* index to something human readable.
* - map options: An array of options passed to the map callback.
* - hierarchy callback: A callback that maps the parent / child relationships
* of the facet data, defaults to FALSE meaning the list is flat.
* - values callback: In instances where facet data is not returned by the
* backend, provide a list of values that can be used.
* - min callback: For facets containing ranges, a callback returning the
* minimum value in the index.
* - max callback: For facets containing ranges, a callback returning the
* maximum value in the index.
* - default sorts: An array of available sorts. Each item is an array
* containing two values, the first being the item being filtered on, the
* second being the SORT_* constant.
*/
function facetapi_facet_load($facet_name, $searcher) {
$facet_info = facetapi_get_facet_info($searcher);
return isset($facet_info[$facet_name]) ? $facet_info[$facet_name] : FALSE;
}
/**
* Returns all defined searcher definitions.
*
* @return array
* An array of searcher information. Each array is keyed by the machine
* readable searcher name and contains the following items:
* - name: The machine readable name of the searcher.
* - label: The human readable name of the searcher displayed in the admin UI.
* - adapter: The adapter plugin ID associated with the searcher.
* - url processor: The URL processor plugin ID associated with the searcher.
* - types: An array containing the types of content indexed by the searcher.
* A type is usually an entity such as 'node', but it can be a non-entity
* value as well.
* - path: The MENU_DEFAULT_LOCAL_TASK item which the admin UI page is added
* to as a MENU_LOCAL_TASK. An empty string if the backend manages the admin
* UI menu items internally.
* - supports facet missing: TRUE if the searcher supports "missing" facets.
* - supports facet mincount: TRUE if the searcher supports the minimum facet
* count setting.
* - include default facets: TRUE if the searcher should include the facets
* defined in facetapi_facetapi_facet_info() when indexing node content,
* FALSE if they should be skipped.
*/
function facetapi_get_searcher_info() {
$searcher_info = array();
foreach (module_implements('facetapi_searcher_info') as $module) {
// Iterates over the module's searcher definition.
$searchers = (array) module_invoke($module, 'facetapi_searcher_info');
foreach ($searchers as $searcher => $info) {
// @see http://drupal.org/node/1167974
// Converts "type" to an array and stores in "types".
// @todo Remove in later versions.
if (isset($info['type']) && !isset($info['types'])) {
$info['types'] = array(
$info['type'],
);
}
// @see http://drupal.org/node/1304010
// Converts "url_processor" to "url processor" for consistency.
// @todo Remove in later versions.
if (isset($info['url_processor']) && !isset($info['url processor'])) {
$info['url processor'] = $info['url_processor'];
}
$info += array(
'module' => $module,
'name' => $searcher,
'path' => '',
'types' => array(
'node',
),
'url processor' => 'standard',
'supports facet missing' => FALSE,
'supports facet mincount' => FALSE,
'include default facets' => TRUE,
);
// @see http://drupal.org/node/1167974
// Makes sure old style "type" is present.
if (!isset($info['type'])) {
$info['type'] = $info['types'][key($info['types'])];
}
// Maps "types" so we can do faster lookups via isset().
$info['types'] = drupal_map_assoc($info['types']);
$searcher_info[$searcher] = $info;
}
}
drupal_alter('facetapi_searcher_info', $searcher_info);
array_walk($searcher_info, 'facetapi_map_assoc', 'types');
return $searcher_info;
}
/**
* Returns a list of active searchers.
*
* An active searcher means that facet data is parsed and processed by the
* backend. Any searcher's adapter who's FacetapiAdapter::addActiveFilters() was
* called is automatically added to this list.
*
* @return array
* An associative array of active adapters
*/
function facetapi_get_active_searchers() {
$searchers =& drupal_static('facetapi_active_searchers', array());
return $searchers;
}
/**
* Returns all defined realm definitions.
*
* @return array
* An array of realm definitions. Each definition is an array keyed by the
* machine readable name of the realm. See the return value of the
* facetapi_realm_load() function for the structure of the definitions.
*/
function facetapi_get_realm_info() {
$realm_info =& drupal_static(__FUNCTION__);
if (NULL === $realm_info) {
$realm_info = module_invoke_all('facetapi_realm_info');
foreach ($realm_info as $realm_name => $realm) {
$realm_info[$realm_name] += array(
'name' => $realm_name,
'label' => $realm_name,
'description' => '',
'default widget' => '',
'settings callback' => FALSE,
'element type' => 'links',
'sortable' => TRUE,
'weight' => 0,
);
}
drupal_alter('facetapi_realm_info', $realm_info);
uasort($realm_info, 'drupal_sort_weight');
}
return $realm_info;
}
/**
* Returns all defined facet definitions available to the searcher.
*
* @param string $searcher
* A string containing the machine readable name of the searcher.
*
* @return array
* An array of facet definitions. Each definition is an array keyed by the
* machine readable name of the facet. See the return value of the
* facetapi_facet_load() function for the structure of the definitions.
*/
function facetapi_get_facet_info($searcher) {
$facet_info =& drupal_static(__FUNCTION__, array());
// Gets facet info if we haven't gotten it already.
if (!isset($facet_info[$searcher])) {
// Builds cache ID.
global $language;
$cid = 'facetapi:facet_info:' . $searcher . ':' . $language->language;
// Checks if our results are cached.
$cache = cache_get($cid);
if (!empty($cache->data)) {
$facet_info[$searcher] = $cache->data;
}
else {
$searcher_info = facetapi_get_searcher_info();
$facet_info[$searcher] = array();
// Invokes hook_facetapi_facet_info(), normalizes facets.
foreach (module_implements('facetapi_facet_info') as $module) {
$facets = call_user_func($module . '_facetapi_facet_info', $searcher_info[$searcher]);
if (!$facets || !is_array($facets)) {
$facets = array();
}
// Iterates over facet definitions, merges defaults.
foreach ($facets as $facet_name => $info) {
// @see http://drupal.org/node/1161434
// Converts "query type" to an array and stores in "query types".
// @todo Remove in later versions.
if (isset($info['query type']) && !isset($info['query types'])) {
$info['query types'] = array(
$info['query type'],
);
}
$facet_info[$searcher][$facet_name] = $info;
$facet_info[$searcher][$facet_name] += array(
'name' => $facet_name,
'label' => $facet_name,
'description' => '',
'field' => $facet_name,
'field alias' => isset($info['field']) ? $info['field'] : $facet_name,
'field api name' => FALSE,
'field api bundles' => array(),
'query types' => array(
'term',
),
'alter callbacks' => array(),
'dependency plugins' => array(),
'default widget' => FALSE,
'allowed operators' => array(
FACETAPI_OPERATOR_AND => TRUE,
FACETAPI_OPERATOR_OR => TRUE,
),
'facet missing allowed' => FALSE,
'facet mincount allowed' => FALSE,
'weight' => 0,
'map callback' => FALSE,
'map options' => array(),
'hierarchy callback' => FALSE,
'values callback' => FALSE,
'min callback' => FALSE,
'max callback' => FALSE,
'default sorts' => array(
array(
'active',
SORT_DESC,
),
array(
'count',
SORT_DESC,
),
array(
'display',
SORT_ASC,
),
),
);
// @see http://drupal.org/node/1161434
// Makes sure old style "query type" is present.
// @todo Remove in later versions.
if (!isset($facet_info[$searcher][$facet_name]['query type'])) {
$type = key($facet_info[$searcher][$facet_name]['query types']);
$facet_info[$searcher][$facet_name]['type'] = $type;
}
}
}
// Invokes alter hook, sorts and returns.
drupal_alter('facetapi_facet_info', $facet_info[$searcher], $searcher_info[$searcher]);
array_walk($facet_info[$searcher], 'facetapi_map_assoc', 'field api bundles');
uasort($facet_info[$searcher], 'drupal_sort_weight');
// Caches the result.
cache_set($cid, $facet_info[$searcher], 'cache', CACHE_TEMPORARY);
}
}
return $facet_info[$searcher];
}
/**
* Implements hook_field_create_instance().
*/
function facetapi_field_create_instance($instance) {
cache_clear_all('facetapi:facet_info:', 'cache', TRUE);
}
/**
* Implements hook_field_delete_instance().
*/
function facetapi_field_delete_instance($instance) {
cache_clear_all('facetapi:facet_info:', 'cache', TRUE);
}
/**
* Wrapper around drupal_map_assoc() for a key in all items of an array.
*
* Useful as an array_walk() callback.
*
* @param array &$array
* The array being modified.
* @param string $name
* The key of the array being modified, usually the name of a definition.
* @param array $key
* The key in the array being passed to drupal_map_assoc().
*/
function facetapi_map_assoc(&$array, $name, $key) {
if (array_key_exists($key, $array)) {
$array[$key] = drupal_map_assoc($array[$key]);
}
}
/**
* Returns all sort definitions.
*
* @return array
* An associative array of sort definitions keyed by sort name. Each sort
* definition contains:
* - name: The machine readable name of the sort.
* - title: The human readable name of the sort displayed in the admin UI.
* - callback: The uasort() callback the render array is passed to.
* - description: The description of the sort displayed in the admin UI.
* - weight: The default weight of the sort specifying its processing order.
*/
function facetapi_get_sort_info() {
$sort_info =& drupal_static(__FUNCTION__);
if (NULL === $sort_info) {
$sort_info = module_invoke_all('facetapi_sort_info');
foreach ($sort_info as $sort_name => $info) {
$sort_info[$sort_name] += array(
'name' => $sort_name,
'label' => $sort_name,
'callback' => '',
'requirements' => array(),
'description' => '',
'weight' => 0,
);
}
drupal_alter('facetapi_sort_info', $sort_info);
}
return $sort_info;
}
/**
* Returns all filter definitions available to the facet.
*
* Each filter plugin must pass all the requirements checks specified in its
* definition. Only plugins that pass all requirements are returned.
*
* @param array $facet
* The facet definition as returned by facetapi_facet_load().
*
* @return array
* An associative array of filter plugin definitions keyed by the plugin ID.
* Each filter plugin definition contains:
* - handler: An associative array containing:
* - label: The human readable name of the plugin displayed in the admin UI.
* - description: The description of the plugin displayed in the admin UI.
* - class: The class containing the plugin.
*/
function facetapi_get_filters(array $facet) {
$plugins = array();
// Iterates over all defined plugins.
foreach (ctools_get_plugins('facetapi', 'filters') as $id => $plugin) {
$plugin['handler'] += array(
'label' => $id,
'description' => '',
'requirements' => array(),
);
// Checks requirements.
if (facetapi_check_requirements($plugin['handler']['requirements'], array(), $facet)) {
$plugins[$id] = $plugin;
}
}
return $plugins;
}
/**
* Gets raw settings from the database, caches as a static variable.
*
* Avoid using this function directly as it will not load default settings. Use
* the FacetapiAdapter::getFacetSettings*() method instead.
*
* @param string $searcher
* A string containing the searcher.
*
* @return array
* An array of settings keyed by name.
*
* @see FacetapiAdapter::getFacetSettings()
* @see FacetapiAdapter::getFacetSettingsGlobal()
*/
function facetapi_get_searcher_settings($searcher) {
$settings =& drupal_static(__FUNCTION__, array());
if (!isset($settings[$searcher])) {
ctools_include('export');
$args = array(
'searcher' => $searcher,
);
$settings[$searcher] = ctools_export_load_object('facetapi', 'conditions', $args);
}
return $settings[$searcher];
}
/**
* Returns all enabled facet definitions available to the searcher.
*
* If a realm is passed, this function returns all facets enabled in the realm.
* If no realm is passed, this function returns all facets that are enabled in
* at least one realm.
*
* @param string $searcher
* The machine readable name of the searcher.
* @param string $realm_name
* The machine readable name of the realm, pass NULL to return all facets that
* are enabled in at least one realm.
*
* @return array
* An array of facet definitions. Each definition is an array keyed by the
* machine readable name of the facet. See the return value of the
* facetapi_facet_load() function for the structure of the definitions.
*/
function facetapi_get_enabled_facets($searcher, $realm_name = NULL) {
$enabled_facets =& drupal_static(__FUNCTION__, array());
$cid = $searcher . ':' . (string) $realm_name;
if (!isset($enabled_facets[$cid])) {
$facets = array();
// Gets cached settings, finds enabled facets.
$cached = facetapi_get_searcher_settings($searcher);
foreach ($cached as $name => $settings) {
$test_enabled = NULL === $realm_name || $realm_name == $settings->realm;
if ($test_enabled && $settings->enabled) {
$facets[$settings->facet] = $settings->facet;
}
}
// Gets facet definitions for all enabled facets.
$facet_info = facetapi_get_facet_info($searcher);
$enabled_facets[$cid] = array_intersect_key($facet_info, $facets);
// Alter enabled facets on the fly.
drupal_alter('facetapi_enabled_facets', $enabled_facets[$cid], $searcher, $realm_name);
}
return $enabled_facets[$cid];
}
/**
* Translates a string via the translator module.
*
* @param string $name
* The name of the string in "textgroup:object_type:object_key:property_name"
* format.
* @param string $string
* The string being translated.
* @param string $langcode
* The language code to translate to a language other than what is used to
* display the page. Defaults to NULL, which uses the current language.
*
* @return string
* The translated string.
*/
function facetapi_translate_string($name, $string, $langcode = NULL) {
if ($module = variable_get('facetapi:translator_module', NULL)) {
$function = $module . '_facetapi_translate_string';
if (function_exists($function)) {
$string = $function($name, $string, $langcode);
}
}
return $string;
}
/**
* Tests whether a searcher is active or not.
*
* @param string $searcher
* The machine readable name of the searcher.
*
* @return FacetapiAdapter
* The adapter object, FALSE if the object can't be loaded.
*/
function facetapi_is_active_searcher($searcher) {
$searchers = facetapi_get_active_searchers();
return isset($searchers[$searcher]);
}
/**
* Adds an active searcher to the list.
*
* @param string $searcher
* The machine readable name of the searcher.
*
* @see facetapi_get_active_searchers();
*/
function facetapi_add_active_searcher($searcher) {
$searchers =& drupal_static('facetapi_active_searchers', array());
$searchers[$searcher] = $searcher;
}
/**
* Tests whether a single facet is enabled in a given realm.
*
* @param string $searcher
* The machine readable name of the searcher.
* @param string $realm_name
* The machine readable name of the realm, pass NULL to test if the facet is
* enabled in at least one realm.
* @param string $facet_name
* The machine readable name of the facet.
*
* @return bool
* A boolean flagging whether the facet is enabled in the passed realm.
*/
function facetapi_facet_enabled($searcher, $realm_name, $facet_name) {
$enabled_facets = facetapi_get_enabled_facets($searcher, $realm_name, $facet_name);
return isset($enabled_facets[$facet_name]);
}
/**
* Builds a facet realm.
*
* Converts the facet data into a render array suitable for passing to the
* drupal_render() function.
*
* @param string $searcher
* The machine readable name of the searcher.
* @param string $realm_name
* The machine readable name of the realm.
*
* @return array
* The realm's render array.
*/
function facetapi_build_realm($searcher, $realm_name) {
$adapter = facetapi_adapter_load($searcher);
return $adapter ? $adapter
->buildRealm($realm_name) : array();
}
/**
* Checks requirements.
*
* Requirements fail if at least one requirements callback returns FALSE. Note
* that if no requirement callbacks are passed, this function will return TRUE.
*
* @param array $requirements
* The requirements keyed by callback to options.
* @param array $realm
* The realm definition.
* @param array $facet
* The facet definition.
*
* @return bool
* A boolean flagging whether all requirements were passed.
*/
function facetapi_check_requirements(array $requirements, array $realm, array $facet, $operator = 'AND') {
$return = TRUE;
module_load_include('inc', 'facetapi', 'facetapi.requirements');
foreach ($requirements as $callback => $options) {
if (!call_user_func($callback, $realm, $facet, $options, $operator)) {
$return = FALSE;
break;
}
}
return $return;
}
/**
* Enables or disables a facet for this page load only.
*
* @param string $searcher
* The machine readable name of the searcher.
* @param string $realm_name
* The machine readable name of the realm, pass NULL for all realms.
* @param string $facet_name
* The machine readable name of the facet.
* @param bool $status
* A boolean flagging whether the facet is enabled or disabled.
* @param bool $batch_process
* A boolean flagging whether batch processing is being performed. If set to
* TRUE, the list of enabled facets won't be rebuild and the active items
* won't be re-processed. Note that these tasks will have to be performed
* manually in order for the status to be properly set.
*/
function facetapi_set_facet_status($searcher, $realm_name, $facet_name, $status, $batch_process) {
// Rebuild static if not batch processing.
if (!$batch_process) {
drupal_static('facetapi_get_enabled_facets', array(), TRUE);
}
// Pulls the list of enabled facets so we can modify it here.
facetapi_get_enabled_facets($searcher, $realm_name);
$enabled_facets =& drupal_static('facetapi_get_enabled_facets', array());
// Performs the operation by setting or unsetting the facet.
$cid = $searcher . ':' . (string) $realm_name;
if ($status && !isset($enabled_facets[$cid][$facet_name])) {
if ($facet = facetapi_facet_load($facet_name, $searcher)) {
// Add facet to static, which enables it.
$enabled_facets[$cid][$facet_name] = $facet;
// If facet isn't already globally enabled, enable it.
if (!isset($enabled_facets[$searcher . ':'][$facet_name])) {
// Ensure sure static is set before modifying it.
facetapi_get_enabled_facets($searcher, NULL);
$enabled_facets[$searcher . ':'][$facet_name] = $facet;
}
}
}
elseif (!$status && isset($enabled_facets[$cid][$facet_name])) {
// Removes facet to static, which disables it.
unset($enabled_facets[$cid][$facet_name]);
// If acting globally, disable facet in all realms.
if (!$realm_name) {
foreach (facetapi_get_realm_info() as $realm) {
// Ensure sure static is set before unsetting the facet.
facetapi_get_enabled_facets($searcher, $realm['name']);
unset($enabled_facets[$searcher . ':' . $realm['name']][$facet_name]);
}
}
}
else {
return;
}
// Re-process the active items since the list of active facets has changed.
if (!$batch_process && ($adapter = facetapi_adapter_load($searcher))) {
$adapter
->processActiveItems();
}
}
/**
* Enables a facet for this page load only.
*
* If you are enabling facets in the block realm, you will have to force the
* delta mapping so that the block can be configured even if it is disabled via
* the Facet API interface. Otherwise you will not be able to assign the block
* to a region because it won't be available in admin/structure/block.
*
* @param $searcher
* The machine readable name of the searcher.
* @param $realm_name
* The machine readable name of the realm, pass NULL for all realms.
* @param $facet_name
* The machine readable name of the facet.
* @param $batch_process
* A boolean flagging whether batch processing is being performed.
*
* @see facetapi_set_facet_status()
* @see hook_facetapi_force_delta_mapping()
*/
function facetapi_set_facet_enabled($searcher, $realm_name, $facet_name, $batch_process = FALSE) {
return facetapi_set_facet_status($searcher, $realm_name, $facet_name, TRUE, $batch_process);
}
/**
* Disables a facet for this page load only.
*
* @param string $searcher
* The machine readable name of the searcher.
* @param string $realm_name
* The machine readable name of the realm, pass NULL for all realms.
* @param string $facet_name
* The machine readable name of the facet.
* @param bool $batch_process
* A boolean flagging whether batch processing is being performed.
*
* @see facetapi_set_facet_status()
*/
function facetapi_set_facet_disabled($searcher, $realm_name, $facet_name, $batch_process = FALSE) {
return facetapi_set_facet_status($searcher, $realm_name, $facet_name, FALSE, $batch_process);
}
/**
* Sets the facet status in a given realm, stores settings in the database.
*
* @param FacetapiAdapter $adapter
* The adapter object of the searcher the settings are being modified for.
* @param array $realm
* The realm definition as returned by facetapi_realm_load().
* @param array $facet
* The facet definition as returned by facetapi_facet_load().
* @param bool $status
* Flags whether or not the facet is being enabled or disabled.
* @param bool $weight
* If the realm is sortable, allows the assigning of a weight. Pass FALSE to
* maintain the previously stored value.
* @param bool $batch_process
* A boolean flagging whether batch processing is being performed. If set to
* TRUE, the caches and statics won't be reset.
*
* @reutrn
* TRUE if the operation succeeded, FALSE otherwise.
*/
function facetapi_save_facet_status(FacetapiAdapter $adapter, array $realm, array $facet, $status, $weight, $batch_process) {
// Loads the realm settings, sets enabled flag and weight.
$settings = $adapter
->getFacet($facet)
->getSettings($realm);
$settings->enabled = $status ? 1 : 0;
if (FALSE !== $weight) {
$settings->settings['weight'] = $realm['sortable'] ? $weight : 0;
}
// Saves the settings in the database, stores the result.
// NOTE: CTools export componenet loaded in the getSettings() method.
$success = FALSE !== ctools_export_crud_save('facetapi', $settings);
// Clears caches and statics if we are not batch processing.
if ($success && !$batch_process) {
drupal_static('facetapi_get_searcher_settings', array(), TRUE);
drupal_static('facetapi_get_enabled_facets', array(), TRUE);
if ('block' == $realm['name']) {
cache_clear_all(NULL, 'cache_block');
cache_clear_all('facetapi:delta_map', 'cache');
}
}
return $success;
}
/**
* Enables a facet in a given realm, stores settings in the database.
*
* @param FacetapiAdapter $adapter
* The adapter object of the searcher the settings are being modified for.
* @param array $realm
* The realm definition as returned by facetapi_realm_load().
* @param array $facet
* The facet definition as returned by facetapi_facet_load().
* @param string $weight
* If the realm is sortable, allows the assigning of a weight. Pass FALSE to
* maintain the previously stored value.
* @param bool $batch_process
* A boolean flagging whether batch processing is being performed.
*
* @reutrn
* TRUE if the operation succeeded, FALSE otherwise.
*/
function facetapi_save_facet_enabled(FacetapiAdapter $adapter, array $realm, array $facet, $weight = FALSE, $batch_process = FALSE) {
return facetapi_save_facet_status($adapter, $realm, $facet, TRUE, $weight, $batch_process);
}
/**
* Disables a facet in a given realm, stores settings in the database.
*
* @param FacetapiAdapter $adapter
* The adapter object of the searcher the settings are being modified for.
* @param array $realm
* The realm definition as returned by facetapi_realm_load().
* @param array $facet
* The facet definition as returned by facetapi_facet_load().
* @param bool $weight
* If the realm is sortable, allows the assigning of a weight. Pass FALSE to
* maintain the previously stored value.
* @param bool $batch_process
* A boolean flagging whether batch processing is being performed.
*
* @reutrn bool
* TRUE if the operation succeeded, FALSE otherwise.
*/
function facetapi_save_facet_disabled(FacetapiAdapter $adapter, array $realm, array $facet, $weight = FALSE, $batch_process = FALSE) {
return facetapi_save_facet_status($adapter, $realm, $facet, FALSE, $weight, $batch_process);
}
/**
* Translates string for FacetAPI.
*/
function facetapi_i18n_string_translate($name, $string) {
return i18n_string_translate($name, $string, array(
'format' => I18N_STRING_FILTER_XSS,
));
}
Functions
Name | Description |
---|---|
facetapi_access_callback | Returns the access callback. |
facetapi_adapter_load | Instantiates the adapter plugin associated with the searcher. |
facetapi_add_active_searcher | Adds an active searcher to the list. |
facetapi_build_realm | Builds a facet realm. |
facetapi_check_requirements | Checks requirements. |
facetapi_ctools_plugin_type | Implements hook_ctools_plugin_type(). |
facetapi_dependencies_load | Loads the dependency plugins associated with the facet. |
facetapi_facet_enabled | Tests whether a single facet is enabled in a given realm. |
facetapi_facet_load | Returns a facet definition. |
facetapi_field_create_instance | Implements hook_field_create_instance(). |
facetapi_field_delete_instance | Implements hook_field_delete_instance(). |
facetapi_filters_load | Returns array of filter options available to the facet. |
facetapi_get_active_searchers | Returns a list of active searchers. |
facetapi_get_enabled_facets | Returns all enabled facet definitions available to the searcher. |
facetapi_get_facet_info | Returns all defined facet definitions available to the searcher. |
facetapi_get_filters | Returns all filter definitions available to the facet. |
facetapi_get_realm_info | Returns all defined realm definitions. |
facetapi_get_searcher_info | Returns all defined searcher definitions. |
facetapi_get_searcher_settings | Gets raw settings from the database, caches as a static variable. |
facetapi_get_sort_info | Returns all sort definitions. |
facetapi_hook_info | Implements hook_facetapi_hook_info(). |
facetapi_i18n_string_info | Implements hook_i18n_string_info(). |
facetapi_i18n_string_list | Implements hook_i18n_string_list(). |
facetapi_i18n_string_translate | Translates string for FacetAPI. |
facetapi_is_active_searcher | Tests whether a searcher is active or not. |
facetapi_map_assoc | Wrapper around drupal_map_assoc() for a key in all items of an array. |
facetapi_menu | Implements hook_menu(). |
facetapi_permission | Implements hook_permission(). |
facetapi_realm_load | Returns a realm definition. |
facetapi_save_facet_disabled | Disables a facet in a given realm, stores settings in the database. |
facetapi_save_facet_enabled | Enables a facet in a given realm, stores settings in the database. |
facetapi_save_facet_status | Sets the facet status in a given realm, stores settings in the database. |
facetapi_set_facet_disabled | Disables a facet for this page load only. |
facetapi_set_facet_enabled | Enables a facet for this page load only. |
facetapi_set_facet_status | Enables or disables a facet for this page load only. |
facetapi_theme | Implements hook_theme(). |
facetapi_translate_string | Translates a string via the translator module. |
Constants
Name | Description |
---|---|
FACETAPI_DATE_DAY | String that represents a time gap of a day between two dates. |
FACETAPI_DATE_HOUR | String that represents a time gap of an hour between two dates. |
FACETAPI_DATE_ISO8601 | Date string for ISO 8601 date formats. |
FACETAPI_DATE_MINUTE | String that represents a time gap of a minute between two dates. |
FACETAPI_DATE_MONTH | String that represents a time gap of a month between two dates. |
FACETAPI_DATE_SECOND | String that represents a time gap of a second between two dates. |
FACETAPI_DATE_YEAR | String that represents a time gap of a year between two dates. |
FACETAPI_OPERATOR_AND | Constant for the "AND" operator. |
FACETAPI_OPERATOR_OR | Constant for the "OR" operator. |
FACETAPI_REGEX_DATE | Regex pattern for date queries. |
FACETAPI_REGEX_DATE_RANGE | Regex pattern for date ranges. |
FACETAPI_REGEX_RANGE | Regex pattern for range queries. |