class FacetapiFacet in Facet API 6
Same name and namespace in other branches
- 6.3 plugins/facetapi/adapter.inc \FacetapiFacet
- 7.2 plugins/facetapi/adapter.inc \FacetapiFacet
- 7 plugins/facetapi/adapter.inc \FacetapiFacet
Stores facet data, provides methods that build the facet's render array.
Hierarchy
- class \FacetapiFacet
Expanded class hierarchy of FacetapiFacet
File
- ./
facetapi.adapter.inc, line 211 - Defines classes used by the FacetAPI module.
View source
class FacetapiFacet {
/**
* A FacetapiAdapter object.
*/
protected $_adapter;
/**
* An array containing the facet definition.
*/
protected $_facet;
/**
* An array of active facets items.
*/
protected $_active;
/**
* The build array for the facet items.
*/
protected $_build;
/**
* Constructor, sets adapter and facet definition.
*
* @param $adapter
* A FacetapiAdapter object.
* @param $facet
* An array containing the facet definition.
*/
public function __construct(FacetapiAdapter $adapter, array $facet) {
$this
->setAdapter($adapter)
->setFacet($facet);
}
/**
* Sets adapter class.
*
* @param $adapter
* A FacetapiAdapter object.
*
* @return
* An instance of this class.
*/
public function setAdapter(FacetapiAdapter $adapter) {
$this->_adapter = $adapter;
return $this;
}
/**
* Returns the adapter class.
*
* @return
* The FacetapiAdapter class.
*/
public function getAdapter() {
return $this->_adapter;
}
/**
* Sets facet definition.
*
* @return
* An instance of this class.
*/
public function setFacet(array $facet) {
$this->_facet = $facet;
return $this;
}
/**
* Sets facet definition.
*
* @return
* An array containing the facet definition.
*/
public function getFacet() {
return $this->_facet;
}
/**
* Returns the facet's active items.
*
* @return
* An array of active items.
*/
public function getActiveItems() {
if (!isset($this->_active)) {
$this
->processActiveItems();
}
return $this->_active;
}
/**
* Returns an array of the facet's active item values, most useful as a form
* element's default value.
*
* @return
* An array containing the facet values keyed by position.
*/
public function getActiveValues() {
if (!isset($this->_active)) {
$this
->processActiveItems();
}
$values = array();
foreach ($this->_active as $value => $item) {
$values[$item['pos']] = $value;
}
if (!empty($values)) {
$values = array_combine($values, $values);
}
return $values;
}
/**
* Tests whether a facet item is active by passing it's value.
*
* NOTE: This method returns an integer instead of a boolean because the value
* is used by the Facet API's custom sorting functions. It ends up being less
* code to compare integers than booleans.
*
* @param $value
* A string containing the facet item's value.
*
* @return
* An integer, 1 if the item is active, 0 if it is inactive.
*/
public function itemActive($value) {
return (int) isset($this->_active[$value]);
}
/**
* Helper function that returns the query string variables for a facet item.
*
* @param $values
* An array containing the item's values being added to or removed from the
* query string dependent on whether or not the item is active.
* @param $active
* An integer flagging whether the item is active or not.
*
* @reutrn
* An array containing the query string variables.
*/
public function getQueryString(array $values, $active) {
// Gets field alias for readability.
$field_alias = $this->_facet['field alias'];
// Builds array of query string variables.
$qstring = $_GET;
foreach ($values as $value) {
if ($active && isset($this->_active[$value])) {
unset($qstring[$field_alias][$this->_active[$value]['pos']]);
}
elseif (!$active) {
if (!isset($qstring[$field_alias])) {
$qstring[$field_alias] = array();
}
elseif (!is_array($qstring[$field_alias])) {
$qstring[$field_alias] = array(
(string) $qstring[$field_alias],
);
}
$qstring[$field_alias][] = $value;
}
}
return $qstring;
}
/**
* Returns the facet's render array.
*
* @param $realm
* An array containing the realm definition.
*
* @return
* The facet's build array.
*/
public function build(array $realm) {
// Builds render array for facet items if necessary.
if (!isset($this->_build)) {
$this->_build = $this
->buildItems();
$this
->processHierarchy($this->_build)
->processQueryStrings($this->_build);
}
// Gets searcher since we use it a lot, gets field alias for readability.
$searcher = $this->_adapter
->getSearcher();
$field_alias = $this->_facet['field alias'];
// Initializes render array.
$build = array(
'#title' => $this->_facet['title'],
'#description' => $this->_facet['description'],
'#weight' => $this->_facet['weight'],
'#adapter' => $this->_adapter,
'#realm_name' => $realm['name'],
'#facet' => $this->_facet,
$field_alias => $this->_build,
);
// Adds identifiers to facet.
$build['#attributes'] = array(
'class' => "facetapi-facet-{$this->_facet['name']}",
'id' => "facetapi-facet-{$searcher}-{$realm['name']}-{$this->_facet['name']}",
);
// Applies sorting algorithms.
$this->_sorts = facetapi_facet_sorts_get($this->_adapter, $realm, $this->_facet);
$this
->_sort($build[$field_alias]);
unset($this->_sorts);
// Gets available widgets.
$widgets = facetapi_widgets_get(array(
'realm' => $realm,
'facet' => $this->_facet,
));
// Gets widget from settings, finds default if necessary.
$widget_name = facetapi_facet_widget_get($widgets, $searcher, $realm, $this->_facet);
// Initializes JavaScript settings.
$facet_settings = array(
'searcher' => $searcher,
'type' => $this->_adapter
->getType(),
'realmName' => $realm['name'],
'facetName' => $this->_facet['name'],
'widget' => $widget_name,
'queryType' => $this->_facet['query type'],
);
// Passes render array, JavaScript settings to widget.
$key = $this->_facet['field alias'];
if (NULL !== $widget_name && isset($widgets[$widget_name])) {
$build['#widget'] = $widgets[$widget_name];
if (facetapi_file_include($build['#widget'])) {
$build['#widget']['callback']($build, $key, $facet_settings);
}
}
// Adds JavaScript settings.
$settings['facetapi']['facets'][] = $facet_settings;
drupal_add_js($settings, 'setting');
return array(
$key => $build,
);
}
/**
* Finds and stores the facet's active items.
*
* @return
* An instance of this class.
*/
public function processActiveItems() {
$this->_active = array();
// Bails if the facet isn't enabled in any realm.
if (!facetapi_facet_enabled($this->_adapter
->getSearcher(), NULL, $this->_facet['name'])) {
return $this;
}
// Gets active items from query string, normalizes to an array.
$field_alias = $this->_facet['field alias'];
if (isset($_GET[$field_alias])) {
if (is_array($_GET[$field_alias])) {
$data = $_GET[$field_alias];
}
else {
$data = array(
(string) $_GET[$field_alias],
);
}
}
else {
$data = array();
}
// Allows hooks to add additional information to the active item. For
// example, range queries extract the start and end values from the item.
$hook = 'facetapi_value_' . $this->_facet['query type'];
foreach ($data as $key => $value) {
$this->_active[$value] = array(
'pos' => $key,
'value' => $value,
);
drupal_alter($hook, $this->_active[$value], $this->_adapter);
}
return $this;
}
/**
* Builds the render array for the facet's items.
*
* @return
* A render array for the facet's items.
*/
public function buildItems() {
$build = array();
// Build array defaults.
// @todo Use #markup in D7.
$defaults = array(
'#type' => 'markup',
'#value' => '',
'#indexed_value' => '',
'#count' => 0,
'#active' => 0,
'#item_parents' => array(),
'#item_children' => array(),
);
// Builds render arrays for each item.
if (NULL !== $this->_facet['field']) {
$hook = 'facetapi_facet_' . $this->_facet['query type'] . '_build';
$items = (array) module_invoke($this->_adapter
->getModule(), $hook, $this->_adapter, $this->_facet);
}
else {
$items = array();
}
foreach (element_children($items) as $value) {
// @todo Use #markup in D7.
$item_defaults = array(
'#value' => $value,
'#indexed_value' => $value,
'#active' => $this
->itemActive($value),
);
// This seems silly, but it maintains the references to the child items
// stored in the #item_children property.
$items[$value] = array_merge($defaults, $item_defaults, $items[$value]);
$build[$value] =& $items[$value];
}
// Maps the IDs to human readable values via the mapping callback.
if (!empty($this->_facet['map callback']) && function_exists($this->_facet['map callback'])) {
$map = call_user_func($this->_facet['map callback'], array_keys($build));
array_walk($build, 'facetapi_ids_replace', $map);
}
return $build;
}
/**
* Processes hierarchical relationships between the facet items.
*
* @param &$build
* The facet's render array.
*
* @return
* An instance of this class.
*/
public function processHierarchy(&$build) {
// Builds the hierarchy information if the hierarchy callback is defined.
if (!empty($this->_facet['hierarchy callback']) && !empty($build)) {
$parents = $this->_facet['hierarchy callback'](array_keys($build));
foreach ($parents as $value => $parents) {
foreach ($parents as $parent) {
if (isset($build[$parent]) && isset($build[$value])) {
// Use a reference so we see the updated data.
$build[$parent]['#item_children'][$value] =& $build[$value];
$build[$value]['#item_parents'][$parent] = $parent;
}
}
}
}
// Tests whether parents have an active child.
// @todo: Can we make this more efficient?
do {
$active = 0;
foreach ($build as $value => $item) {
if ($item['#active'] && !empty($item['#item_parents'])) {
// @todo Can we build facets with multiple parents? Core taxonomy
// form cannot, so we will need a check here.
foreach ($item['#item_parents'] as $parent) {
if (!$build[$parent]['#active']) {
$active = $build[$parent]['#active'] = 1;
}
}
}
}
} while ($active);
// Strips children whose parents are inactive.
$build = array_filter($build, 'facetapi_inactive_parent_filter');
// Returns instance of this class.
return $this;
}
/**
* Initializes the render array's query string variables.
*
* @param &$build
* The facet's render array.
*
* @return
* An instance of this class.
*/
function processQueryStrings(array &$build) {
foreach ($build as $value => &$item) {
$values = array(
$value,
);
// If the item is active an has children, gets the paths for the children.
// Merges child values with this facet item's value so that unclicking the
// parent deactivated the children as well.
if (!empty($item['#active']) && !empty($item['#item_children'])) {
$this
->processQueryStrings($item['#item_children']);
$values = array_merge(facetapi_child_values_get($item['#item_children']), $values);
}
// Formats query string for facet item, sets theme function.
$item['#query'] = $this
->getQueryString($values, $item['#active']);
}
// Returns instance of this calss.
return $this;
}
/**
* Sorts the facet's build array.
*
* @param &$build
* An array containing the render array.
*/
protected function _sort(&$build) {
foreach (element_children($build) as $value) {
if (!empty($build[$value]['#item_children'])) {
$this
->_sort($build[$value]['#item_children']);
}
}
uasort($build, array(
$this,
'_sortCallback',
));
}
/**
* Callback for uasort() that applies each sort in the order specified in the
* admin interface.
*/
protected function _sortCallback(array $a, array $b) {
$return = 0;
foreach ($this->_sorts as $sort) {
if ($return = $sort['callback']($a, $b)) {
if (SORT_DESC == $sort['order']) {
$return *= -1;
}
break;
}
}
return $return;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
FacetapiFacet:: |
protected | property | An array of active facets items. | |
FacetapiFacet:: |
protected | property | A FacetapiAdapter object. | |
FacetapiFacet:: |
protected | property | The build array for the facet items. | |
FacetapiFacet:: |
protected | property | An array containing the facet definition. | |
FacetapiFacet:: |
public | function | Returns the facet's render array. | |
FacetapiFacet:: |
public | function | Builds the render array for the facet's items. | |
FacetapiFacet:: |
public | function | Returns the facet's active items. | |
FacetapiFacet:: |
public | function | Returns an array of the facet's active item values, most useful as a form element's default value. | |
FacetapiFacet:: |
public | function | Returns the adapter class. | |
FacetapiFacet:: |
public | function | Sets facet definition. | |
FacetapiFacet:: |
public | function | Helper function that returns the query string variables for a facet item. | |
FacetapiFacet:: |
public | function | Tests whether a facet item is active by passing it's value. | |
FacetapiFacet:: |
public | function | Finds and stores the facet's active items. | |
FacetapiFacet:: |
public | function | Processes hierarchical relationships between the facet items. | |
FacetapiFacet:: |
function | Initializes the render array's query string variables. | ||
FacetapiFacet:: |
public | function | Sets adapter class. | |
FacetapiFacet:: |
public | function | Sets facet definition. | |
FacetapiFacet:: |
protected | function | Sorts the facet's build array. | |
FacetapiFacet:: |
protected | function | Callback for uasort() that applies each sort in the order specified in the admin interface. | |
FacetapiFacet:: |
public | function | Constructor, sets adapter and facet definition. |