Bachir Soussi Chiadmi 1bc61b12ad first import
2015-04-08 11:40:19 +02:00

937 lines
32 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Class representing a search index.
*/
class SearchApiIndex extends Entity {
// Cache values, set when the corresponding methods are called for the first
// time.
/**
* Cached return value of datasource().
*
* @var SearchApiDataSourceControllerInterface
*/
protected $datasource = NULL;
/**
* Cached return value of server().
*
* @var SearchApiServer
*/
protected $server_object = NULL;
/**
* All enabled data alterations for this index.
*
* @var array
*/
protected $callbacks = NULL;
/**
* All enabled processors for this index.
*
* @var array
*/
protected $processors = NULL;
/**
* The properties added by data alterations on this index.
*
* @var array
*/
protected $added_properties = NULL;
/**
* An array containing two arrays.
*
* At index 0, all fulltext fields of this index. At index 1, all indexed
* fulltext fields of this index.
*
* @var array
*/
protected $fulltext_fields = array();
// Database values that will be set when object is loaded.
/**
* An integer identifying the index.
* Immutable.
*
* @var integer
*/
public $id;
/**
* A name to be displayed for the index.
*
* @var string
*/
public $name;
/**
* The machine name of the index.
* Immutable.
*
* @var string
*/
public $machine_name;
/**
* A string describing the index' use to users.
*
* @var string
*/
public $description;
/**
* The machine_name of the server with which data should be indexed.
*
* @var string
*/
public $server;
/**
* The type of items stored in this index.
* Immutable.
*
* @var string
*/
public $item_type;
/**
* An array of options for configuring this index. The layout is as follows:
* - cron_limit: The maximum number of items to be indexed per cron batch.
* - index_directly: Boolean setting whether entities are indexed immediately
* after they are created or updated.
* - fields: An array of all indexed fields for this index. Keys are the field
* identifiers, the values are arrays for specifying the field settings. The
* structure of those arrays looks like this:
* - type: The type set for this field. One of the types returned by
* search_api_default_field_types().
* - real_type: (optional) If a custom data type was selected for this
* field, this type will be stored here, and "type" contain the fallback
* default data type.
* - boost: (optional) A boost value for terms found in this field during
* searches. Usually only relevant for fulltext fields. Defaults to 1.0.
* - entity_type (optional): If set, the type of this field is really an
* entity. The "type" key will then just contain the primitive data type
* of the ID field, meaning that servers will ignore this and merely index
* the entity's ID. Components displaying this field, though, are advised
* to use the entity label instead of the ID.
* - additional fields: An associative array with keys and values being the
* field identifiers of related entities whose fields should be displayed.
* - data_alter_callbacks: An array of all data alterations available. Keys
* are the alteration identifiers, the values are arrays containing the
* settings for that data alteration. The inner structure looks like this:
* - status: Boolean indicating whether the data alteration is enabled.
* - weight: Used for sorting the data alterations.
* - settings: Alteration-specific settings, configured via the alteration's
* configuration form.
* - processors: An array of all processors available for the index. The keys
* are the processor identifiers, the values are arrays containing the
* settings for that processor. The inner structure looks like this:
* - status: Boolean indicating whether the processor is enabled.
* - weight: Used for sorting the processors.
* - settings: Processor-specific settings, configured via the processor's
* configuration form.
*
* @var array
*/
public $options = array();
/**
* A flag indicating whether this index is enabled.
*
* @var integer
*/
public $enabled = 1;
/**
* A flag indicating whether to write to this index.
*
* @var integer
*/
public $read_only = 0;
/**
* Constructor as a helper to the parent constructor.
*/
public function __construct(array $values = array()) {
parent::__construct($values, 'search_api_index');
}
/**
* Execute necessary tasks for a newly created index.
*/
public function postCreate() {
if ($this->enabled) {
$this->queueItems();
}
$server = $this->server();
if ($server) {
// Tell the server about the new index.
if ($server->enabled) {
$server->addIndex($this);
}
else {
$tasks = variable_get('search_api_tasks', array());
// When we add or remove an index, we can ignore all other tasks.
$tasks[$server->machine_name][$this->machine_name] = array('add');
variable_set('search_api_tasks', $tasks);
}
}
}
/**
* Execute necessary tasks when the index is removed from the database.
*/
public function postDelete() {
if ($server = $this->server()) {
if ($server->enabled) {
$server->removeIndex($this);
}
else {
$tasks = variable_get('search_api_tasks', array());
$tasks[$server->machine_name][$this->machine_name] = array('remove');
variable_set('search_api_tasks', $tasks);
}
}
// Stop tracking entities for indexing.
$this->dequeueItems();
}
/**
* Record entities to index.
*/
public function queueItems() {
if (!$this->read_only) {
$this->datasource()->startTracking(array($this));
}
}
/**
* Remove all records of entities to index.
*/
public function dequeueItems() {
$this->datasource()->stopTracking(array($this));
_search_api_empty_cron_queue($this);
}
/**
* Saves this index to the database, either creating a new record or updating
* an existing one.
*
* @return
* Failure to save the index will return FALSE. Otherwise, SAVED_NEW or
* SAVED_UPDATED is returned depending on the operation performed. $this->id
* will be set if a new index was inserted.
*/
public function save() {
if (empty($this->description)) {
$this->description = NULL;
}
if (empty($this->server)) {
$this->server = NULL;
$this->enabled = FALSE;
}
// This will also throw an exception if the server doesn't exist which is good.
elseif (!$this->server(TRUE)->enabled) {
$this->enabled = FALSE;
}
return parent::save();
}
/**
* Helper method for updating entity properties.
*
* NOTE: You shouldn't change any properties of this object before calling
* this method, as this might lead to the fields not being saved correctly.
*
* @param array $fields
* The new field values.
*
* @return
* SAVE_UPDATED on success, FALSE on failure, 0 if the fields already had
* the specified values.
*/
public function update(array $fields) {
$changeable = array('name' => 1, 'enabled' => 1, 'description' => 1, 'server' => 1, 'options' => 1, 'read_only' => 1);
$changed = FALSE;
foreach ($fields as $field => $value) {
if (isset($changeable[$field]) && $value !== $this->$field) {
$this->$field = $value;
$changed = TRUE;
}
}
// If there are no new values, just return 0.
if (!$changed) {
return 0;
}
// Reset the index's internal property cache to correctly incorporate new
// settings.
$this->resetCaches();
return $this->save();
}
/**
* Schedules this search index for re-indexing.
*
* @return
* TRUE on success, FALSE on failure.
*/
public function reindex() {
if (!$this->server || $this->read_only) {
return TRUE;
}
_search_api_index_reindex($this);
module_invoke_all('search_api_index_reindex', $this, FALSE);
return TRUE;
}
/**
* Clears this search index and schedules all of its items for re-indexing.
*
* @return
* TRUE on success, FALSE on failure.
*/
public function clear() {
if (!$this->server || $this->read_only) {
return TRUE;
}
$server = $this->server();
if ($server->enabled) {
$server->deleteItems('all', $this);
}
else {
$tasks = variable_get('search_api_tasks', array());
// If the index was cleared or newly added since the server was last enabled, we don't need to do anything.
if (!isset($tasks[$server->machine_name][$this->machine_name])
|| (array_search('add', $tasks[$server->machine_name][$this->machine_name]) === FALSE
&& array_search('clear', $tasks[$server->machine_name][$this->machine_name]) === FALSE)) {
$tasks[$server->machine_name][$this->machine_name][] = 'clear';
variable_set('search_api_tasks', $tasks);
}
}
_search_api_index_reindex($this);
module_invoke_all('search_api_index_reindex', $this, TRUE);
return TRUE;
}
/**
* Magic method for determining which fields should be serialized.
*
* Don't serialize properties that are basically only caches.
*
* @return array
* An array of properties to be serialized.
*/
public function __sleep() {
$ret = get_object_vars($this);
unset($ret['server_object'], $ret['datasource'], $ret['processors'], $ret['added_properties'], $ret['fulltext_fields']);
return array_keys($ret);
}
/**
* Get the controller object of the data source used by this index.
*
* @throws SearchApiException
* If the specified item type or data source doesn't exist or is invalid.
*
* @return SearchApiDataSourceControllerInterface
* The data source controller for this index.
*/
public function datasource() {
if (!isset($this->datasource)) {
$this->datasource = search_api_get_datasource_controller($this->item_type);
}
return $this->datasource;
}
/**
* Get the server this index lies on.
*
* @param $reset
* Whether to reset the internal cache. Set to TRUE when the index' $server
* property has just changed.
*
* @throws SearchApiException
* If $this->server is set, but no server with that machine name exists.
*
* @return SearchApiServer
* The server associated with this index, or NULL if this index currently
* doesn't lie on a server.
*/
public function server($reset = FALSE) {
if (!isset($this->server_object) || $reset) {
$this->server_object = $this->server ? search_api_server_load($this->server) : FALSE;
if ($this->server && !$this->server_object) {
throw new SearchApiException(t('Unknown server @server specified for index @name.', array('@server' => $this->server, '@name' => $this->machine_name)));
}
}
return $this->server_object ? $this->server_object : NULL;
}
/**
* Create a query object for this index.
*
* @param $options
* Associative array of options configuring this query. See
* SearchApiQueryInterface::__construct().
*
* @throws SearchApiException
* If the index is currently disabled.
*
* @return SearchApiQueryInterface
* A query object for searching this index.
*/
public function query($options = array()) {
if (!$this->enabled) {
throw new SearchApiException(t('Cannot search on a disabled index.'));
}
return $this->server()->query($this, $options);
}
/**
* Indexes items on this index. Will return an array of IDs of items that
* should be marked as indexed i.e., items that were either rejected by a
* data-alter callback or were successfully indexed.
*
* @param array $items
* An array of items to index.
*
* @return array
* An array of the IDs of all items that should be marked as indexed.
*/
public function index(array $items) {
if ($this->read_only) {
return array();
}
if (!$this->enabled) {
throw new SearchApiException(t("Couldn't index values on '@name' index (index is disabled)", array('@name' => $this->name)));
}
if (empty($this->options['fields'])) {
throw new SearchApiException(t("Couldn't index values on '@name' index (no fields selected)", array('@name' => $this->name)));
}
$fields = $this->options['fields'];
$custom_type_fields = array();
foreach ($fields as $field => $info) {
if (isset($info['real_type'])) {
$custom_type = search_api_extract_inner_type($info['real_type']);
if ($this->server()->supportsFeature('search_api_data_type_' . $custom_type)) {
$fields[$field]['type'] = $info['real_type'];
$custom_type_fields[$custom_type][$field] = search_api_list_nesting_level($info['real_type']);
}
}
}
if (empty($fields)) {
throw new SearchApiException(t("Couldn't index values on '@name' index (no fields selected)", array('@name' => $this->name)));
}
// Mark all items that are rejected as indexed.
$ret = array_keys($items);
drupal_alter('search_api_index_items', $items, $this);
if ($items) {
$this->dataAlter($items);
}
$ret = array_diff($ret, array_keys($items));
// Items that are rejected should also be deleted from the server.
if ($ret) {
$this->server()->deleteItems($ret, $this);
}
if (!$items) {
return $ret;
}
$data = array();
foreach ($items as $id => $item) {
$data[$id] = search_api_extract_fields($this->entityWrapper($item), $fields);
unset($items[$id]);
foreach ($custom_type_fields as $type => $type_fields) {
$info = search_api_get_data_type_info($type);
if (isset($info['conversion callback']) && is_callable($info['conversion callback'])) {
$callback = $info['conversion callback'];
foreach ($type_fields as $field => $nesting_level) {
if (isset($data[$id][$field]['value'])) {
$value = $data[$id][$field]['value'];
$original_type = $data[$id][$field]['original_type'];
$data[$id][$field]['value'] = _search_api_convert_custom_type($callback, $value, $original_type, $type, $nesting_level);
}
}
}
}
}
$this->preprocessIndexItems($data);
return array_merge($ret, $this->server()->indexItems($this, $data));
}
/**
* Calls data alteration hooks for a set of items, according to the index
* options.
*
* @param array $items
* An array of items to be altered.
*
* @return SearchApiIndex
* The called object.
*/
public function dataAlter(array &$items) {
// First, execute our own search_api_language data alteration.
foreach ($items as &$item) {
$item->search_api_language = isset($item->language) ? $item->language : LANGUAGE_NONE;
}
foreach ($this->getAlterCallbacks() as $callback) {
$callback->alterItems($items);
}
return $this;
}
/**
* Property info alter callback that adds the infos of the properties added by
* data alter callbacks.
*
* @param EntityMetadataWrapper $wrapper
* The wrapped data.
* @param $property_info
* The original property info.
*
* @return array
* The altered property info.
*/
public function propertyInfoAlter(EntityMetadataWrapper $wrapper, array $property_info) {
if (entity_get_property_info($wrapper->type())) {
// Overwrite the existing properties with the list of properties including
// all fields regardless of the used bundle.
$property_info['properties'] = entity_get_all_property_info($wrapper->type());
}
if (!isset($this->added_properties)) {
$this->added_properties = array(
'search_api_language' => array(
'label' => t('Item language'),
'description' => t("A field added by the search framework to let components determine an item's language. Is always indexed."),
'type' => 'token',
'options list' => 'entity_metadata_language_list',
),
);
// We use the reverse order here so the hierarchy for overwriting property infos is the same
// as for actually overwriting the properties.
foreach (array_reverse($this->getAlterCallbacks()) as $callback) {
$props = $callback->propertyInfo();
if ($props) {
$this->added_properties += $props;
}
}
}
// Let fields added by data-alter callbacks override default fields.
$property_info['properties'] = array_merge($property_info['properties'], $this->added_properties);
return $property_info;
}
/**
* Fills the $processors array for use by the pre-/postprocessing functions.
*
* @return SearchApiIndex
* The called object.
* @return array
* All enabled callbacks for this index, as SearchApiAlterCallbackInterface
* objects.
*/
protected function getAlterCallbacks() {
if (isset($this->callbacks)) {
return $this->callbacks;
}
$this->callbacks = array();
if (empty($this->options['data_alter_callbacks'])) {
return $this->callbacks;
}
$callback_settings = $this->options['data_alter_callbacks'];
$infos = search_api_get_alter_callbacks();
foreach ($callback_settings as $id => $settings) {
if (empty($settings['status'])) {
continue;
}
if (empty($infos[$id]) || !class_exists($infos[$id]['class'])) {
watchdog('search_api', t('Undefined data alteration @class specified in index @name', array('@class' => $id, '@name' => $this->name)), NULL, WATCHDOG_WARNING);
continue;
}
$class = $infos[$id]['class'];
$callback = new $class($this, empty($settings['settings']) ? array() : $settings['settings']);
if (!($callback instanceof SearchApiAlterCallbackInterface)) {
watchdog('search_api', t('Unknown callback class @class specified for data alteration @name', array('@class' => $class, '@name' => $id)), NULL, WATCHDOG_WARNING);
continue;
}
$this->callbacks[$id] = $callback;
}
return $this->callbacks;
}
/**
* @return array
* All enabled processors for this index, as SearchApiProcessorInterface
* objects.
*/
protected function getProcessors() {
if (isset($this->processors)) {
return $this->processors;
}
$this->processors = array();
if (empty($this->options['processors'])) {
return $this->processors;
}
$processor_settings = $this->options['processors'];
$infos = search_api_get_processors();
foreach ($processor_settings as $id => $settings) {
if (empty($settings['status'])) {
continue;
}
if (empty($infos[$id]) || !class_exists($infos[$id]['class'])) {
watchdog('search_api', t('Undefined processor @class specified in index @name', array('@class' => $id, '@name' => $this->name)), NULL, WATCHDOG_WARNING);
continue;
}
$class = $infos[$id]['class'];
$processor = new $class($this, isset($settings['settings']) ? $settings['settings'] : array());
if (!($processor instanceof SearchApiProcessorInterface)) {
watchdog('search_api', t('Unknown processor class @class specified for processor @name', array('@class' => $class, '@name' => $id)), NULL, WATCHDOG_WARNING);
continue;
}
$this->processors[$id] = $processor;
}
return $this->processors;
}
/**
* Preprocess data items for indexing. Data added by data alter callbacks will
* be available on the items.
*
* Typically, a preprocessor will execute its preprocessing (e.g. stemming,
* n-grams, word splitting, stripping stop words, etc.) only on the items'
* fulltext fields. Other fields should usually be left untouched.
*
* @param array $items
* An array of items to be preprocessed for indexing.
*
* @return SearchApiIndex
* The called object.
*/
public function preprocessIndexItems(array &$items) {
foreach ($this->getProcessors() as $processor) {
$processor->preprocessIndexItems($items);
}
return $this;
}
/**
* Preprocess a search query.
*
* The same applies as when preprocessing indexed items: typically, only the
* fulltext search keys should be processed, queries on specific fields should
* usually not be altered.
*
* @param SearchApiQuery $query
* The object representing the query to be executed.
*
* @return SearchApiIndex
* The called object.
*/
public function preprocessSearchQuery(SearchApiQuery $query) {
foreach ($this->getProcessors() as $processor) {
$processor->preprocessSearchQuery($query);
}
return $this;
}
/**
* Postprocess search results before display.
*
* If a class is used for both pre- and post-processing a search query, the
* same object will be used for both calls (so preserving some data or state
* locally is possible).
*
* @param array $response
* An array containing the search results. See
* SearchApiServiceInterface->search() for the detailed format.
* @param SearchApiQuery $query
* The object representing the executed query.
*
* @return SearchApiIndex
* The called object.
*/
public function postprocessSearchResults(array &$response, SearchApiQuery $query) {
// Postprocessing is done in exactly the opposite direction than preprocessing.
foreach (array_reverse($this->getProcessors()) as $processor) {
$processor->postprocessSearchResults($response, $query);
}
return $this;
}
/**
* Returns a list of all known fields for this index.
*
* @param $only_indexed (optional)
* Return only indexed fields, not all known fields. Defaults to TRUE.
* @param $get_additional (optional)
* Return not only known/indexed fields, but also related entities whose
* fields could additionally be added to the index.
*
* @return array
* An array of all known fields for this index. Keys are the field
* identifiers, the values are arrays for specifying the field settings. The
* structure of those arrays looks like this:
* - name: The human-readable name for the field.
* - description: A description of the field, if available.
* - indexed: Boolean indicating whether the field is indexed or not.
* - type: The type set for this field. One of the types returned by
* search_api_default_field_types().
* - real_type: (optional) If a custom data type was selected for this
* field, this type will be stored here, and "type" contain the fallback
* default data type.
* - boost: A boost value for terms found in this field during searches.
* Usually only relevant for fulltext fields.
* - entity_type (optional): If set, the type of this field is really an
* entity. The "type" key will then contain "integer", meaning that
* servers will ignore this and merely index the entity's ID. Components
* displaying this field, though, are advised to use the entity label
* instead of the ID.
* If $get_additional is TRUE, this array is encapsulated in another
* associative array, which contains the above array under the "fields" key,
* and a list of related entities (field keys mapped to names) under the
* "additional fields" key.
*/
public function getFields($only_indexed = TRUE, $get_additional = FALSE) {
$fields = empty($this->options['fields']) ? array() : $this->options['fields'];
$wrapper = $this->entityWrapper();
$additional = array();
$entity_types = entity_get_info();
// First we need all already added prefixes.
$added = ($only_indexed || empty($this->options['additional fields'])) ? array() : $this->options['additional fields'];
foreach (array_keys($fields) as $key) {
$len = strlen($key) + 1;
$pos = $len;
// The third parameter ($offset) to strrpos has rather weird behaviour,
// necessitating this rather awkward code. It will iterate over all
// prefixes of each field, beginning with the longest, adding all of them
// to $added until one is encountered that was already added (which means
// all shorter ones will have already been added, too).
while ($pos = strrpos($key, ':', $pos - $len)) {
$prefix = substr($key, 0, $pos);
if (isset($added[$prefix])) {
break;
}
$added[$prefix] = $prefix;
}
}
// Then we walk through all properties and look if they are already
// contained in one of the arrays.
// Since this uses an iterative instead of a recursive approach, it is a bit
// complicated, with three arrays tracking the current depth.
// A wrapper for a specific field name prefix, e.g. 'user:' mapped to the user wrapper
$wrappers = array('' => $wrapper);
// Display names for the prefixes
$prefix_names = array('' => '');
// The list nesting level for entities with a certain prefix
$nesting_levels = array('' => 0);
$types = search_api_default_field_types();
$flat = array();
while ($wrappers) {
foreach ($wrappers as $prefix => $wrapper) {
$prefix_name = $prefix_names[$prefix];
// Deal with lists of entities.
$nesting_level = $nesting_levels[$prefix];
$type_prefix = str_repeat('list<', $nesting_level);
$type_suffix = str_repeat('>', $nesting_level);
if ($nesting_level) {
$info = $wrapper->info();
// The real nesting level of the wrapper, not the accumulated one.
$level = search_api_list_nesting_level($info['type']);
for ($i = 0; $i < $level; ++$i) {
$wrapper = $wrapper[0];
}
}
// Now look at all properties.
foreach ($wrapper as $property => $value) {
$info = $value->info();
// We hide the complexity of multi-valued types from the user here.
$type = search_api_extract_inner_type($info['type']);
// Treat Entity API type "token" as our "string" type.
// Also let text fields with limited options be of type "string" by default.
if ($type == 'token' || ($type == 'text' && !empty($info['options list']))) {
// Inner type is changed to "string".
$type = 'string';
// Set the field type accordingly.
$info['type'] = search_api_nest_type('string', $info['type']);
}
$info['type'] = $type_prefix . $info['type'] . $type_suffix;
$key = $prefix . $property;
if ((isset($types[$type]) || isset($entity_types[$type])) && (!$only_indexed || !empty($fields[$key]))) {
if (!empty($fields[$key])) {
// This field is already known in the index configuration.
$flat[$key] = $fields[$key] + array(
'name' => $prefix_name . $info['label'],
'description' => empty($info['description']) ? NULL : $info['description'],
'boost' => '1.0',
'indexed' => TRUE,
);
// Update the type and its nesting level for non-entity properties.
if (!isset($entity_types[$type])) {
$flat[$key]['type'] = search_api_nest_type(search_api_extract_inner_type($flat[$key]['type']), $info['type']);
if (isset($flat[$key]['real_type'])) {
$real_type = search_api_extract_inner_type($flat[$key]['real_type']);
$flat[$key]['real_type'] = search_api_nest_type($real_type, $info['type']);
}
}
}
else {
$flat[$key] = array(
'name' => $prefix_name . $info['label'],
'description' => empty($info['description']) ? NULL : $info['description'],
'type' => $info['type'],
'boost' => '1.0',
'indexed' => FALSE,
);
}
if (isset($entity_types[$type])) {
$base_type = isset($entity_types[$type]['entity keys']['name']) ? 'string' : 'integer';
$flat[$key]['type'] = search_api_nest_type($base_type, $info['type']);
$flat[$key]['entity_type'] = $type;
}
}
if (empty($types[$type])) {
if (isset($added[$key])) {
// Visit this entity/struct in a later iteration.
$wrappers[$key . ':'] = $value;
$prefix_names[$key . ':'] = $prefix_name . $info['label'] . ' » ';
$nesting_levels[$key . ':'] = search_api_list_nesting_level($info['type']);
}
else {
$name = $prefix_name . $info['label'];
// Add machine names to discern fields with identical labels.
if (isset($used_names[$name])) {
if ($used_names[$name] !== FALSE) {
$additional[$used_names[$name]] .= ' [' . $used_names[$name] . ']';
$used_names[$name] = FALSE;
}
$name .= ' [' . $key . ']';
}
$additional[$key] = $name;
$used_names[$name] = $key;
}
}
}
unset($wrappers[$prefix]);
}
}
if (!$get_additional) {
return $flat;
}
$options = array();
$options['fields'] = $flat;
$options['additional fields'] = $additional;
return $options;
}
/**
* Convenience method for getting all of this index's fulltext fields.
*
* @param boolean $only_indexed
* If set to TRUE, only the indexed fulltext fields will be returned.
*
* @return array
* An array containing all (or all indexed) fulltext fields defined for this
* index.
*/
public function getFulltextFields($only_indexed = TRUE) {
$i = $only_indexed ? 1 : 0;
if (!isset($this->fulltext_fields[$i])) {
$this->fulltext_fields[$i] = array();
$fields = $only_indexed ? $this->options['fields'] : $this->getFields(FALSE);
foreach ($fields as $key => $field) {
if (search_api_is_text_type($field['type'])) {
$this->fulltext_fields[$i][] = $key;
}
}
}
return $this->fulltext_fields[$i];
}
/**
* Helper function for creating an entity metadata wrapper appropriate for
* this index.
*
* @param $item
* Unless NULL, an item of this index's item type which should be wrapped.
* @param $alter
* Whether to apply the index's active data alterations on the property
* information used. To also apply the data alteration to the wrapped item,
* execute SearchApiIndex::dataAlter() on it before calling this method.
*
* @return EntityMetadataWrapper
* A wrapper for the item type of this index, optionally loaded with the
* given data and having additional fields according to the data alterations
* of this index.
*/
public function entityWrapper($item = NULL, $alter = TRUE) {
$info['property info alter'] = $alter ? array($this, 'propertyInfoAlter') : '_search_api_wrapper_add_all_properties';
$info['property defaults']['property info alter'] = '_search_api_wrapper_add_all_properties';
return $this->datasource()->getMetadataWrapper($item, $info);
}
/**
* Helper method to load items from the type lying on this index.
*
* @param array $ids
* The IDs of the items to load.
*
* @return array
* The requested items, as loaded by the data source.
*
* @see SearchApiDataSourceControllerInterface::loadItems()
*/
public function loadItems(array $ids) {
return $this->datasource()->loadItems($ids);
}
/**
* Reset internal static caches.
*
* Should be used when things like fields or data alterations change to avoid
* using stale data.
*/
public function resetCaches() {
$this->datasource = NULL;
$this->server_object = NULL;
$this->callbacks = NULL;
$this->processors = NULL;
$this->added_properties = NULL;
$this->fulltext_fields = array();
}
}