class Item in Search API 8
Provides a default implementation for a search item.
Hierarchy
- class \Drupal\search_api\Item\Item implements \Drupal\search_api\Item\IteratorAggregate, ItemInterface uses LoggerTrait
Expanded class hierarchy of Item
4 files declare their use of Item
- FieldsHelper.php in src/
Utility/ FieldsHelper.php - SerializationTest.php in tests/
src/ Kernel/ System/ SerializationTest.php - TestItemsTrait.php in tests/
src/ Unit/ Processor/ TestItemsTrait.php - ViewsFieldTraitTest.php in tests/
src/ Kernel/ Views/ ViewsFieldTraitTest.php
1 string reference to 'Item'
- DatasourceTaskTest::setUp in tests/
src/ Kernel/ Datasource/ DatasourceTaskTest.php
File
- src/
Item/ Item.php, line 19
Namespace
Drupal\search_api\ItemView source
class Item implements \IteratorAggregate, ItemInterface {
use LoggerTrait;
/**
* The search index with which this item is associated.
*
* @var \Drupal\search_api\IndexInterface
*/
protected $index;
/**
* The ID of the index with which this item is associated.
*
* This is only used to avoid serialization of the index in __sleep() and
* __wakeup().
*
* @var string
*/
protected $indexId;
/**
* The ID of this item.
*
* @var string
*/
protected $itemId;
/**
* The complex data item this Search API item is based on.
*
* @var \Drupal\Core\TypedData\ComplexDataInterface
*/
protected $originalObject;
/**
* The ID of this item's datasource.
*
* @var string
*/
protected $datasourceId;
/**
* The datasource of this item.
*
* @var \Drupal\search_api\Datasource\DatasourceInterface
*/
protected $datasource;
/**
* The language code of this item.
*
* @var string
*/
protected $language;
/**
* The extracted fields of this item.
*
* @var \Drupal\search_api\Item\FieldInterface[]
*/
protected $fields = [];
/**
* Whether the fields were already extracted for this item.
*
* @var bool
*/
protected $fieldsExtracted = FALSE;
/**
* The HTML text with highlighted text-parts that match the query.
*
* @var string
*/
protected $excerpt;
/**
* The score this item had as a result in a corresponding search query.
*
* @var float
*/
protected $score = 1.0;
/**
* The boost of this item at indexing time.
*
* @var float
*/
protected $boost = 1.0;
/**
* Extra data set on this item.
*
* @var array
*/
protected $extraData = [];
/**
* Cached access results for the item, keyed by user ID.
*
* @var \Drupal\Core\Access\AccessResultInterface[]
*
* @see getAccessResult()
*/
protected $accessResults = [];
/**
* Constructs an Item object.
*
* @param \Drupal\search_api\IndexInterface $index
* The item's search index.
* @param string $id
* The ID of this item.
* @param \Drupal\search_api\Datasource\DatasourceInterface|null $datasource
* (optional) The datasource of this item. If not set, it will be determined
* from the ID and loaded from the index.
*/
public function __construct(IndexInterface $index, $id, DatasourceInterface $datasource = NULL) {
$this->index = $index;
$this->itemId = $id;
if ($datasource) {
$this->datasource = $datasource;
$this->datasourceId = $datasource
->getPluginId();
}
}
/**
* {@inheritdoc}
*/
public function getDatasourceId() {
if (!isset($this->datasourceId)) {
list($this->datasourceId) = Utility::splitCombinedId($this->itemId);
}
return $this->datasourceId;
}
/**
* {@inheritdoc}
*/
public function getDatasource() {
if (!isset($this->datasource)) {
$this->datasource = $this->index
->getDatasource($this
->getDatasourceId());
}
return $this->datasource;
}
/**
* {@inheritdoc}
*/
public function getIndex() {
return $this->index;
}
/**
* {@inheritdoc}
*/
public function getLanguage() {
if (!isset($this->language)) {
$this->language = $this
->getDatasource()
->getItemLanguage($this
->getOriginalObject());
}
return $this->language;
}
/**
* {@inheritdoc}
*/
public function setLanguage($language) {
$this->language = $language;
return $this;
}
/**
* {@inheritdoc}
*/
public function getId() {
return $this->itemId;
}
/**
* {@inheritdoc}
*/
public function getOriginalObject($load = TRUE) {
if (!isset($this->originalObject) && $load) {
$this->originalObject = $this->index
->loadItem($this->itemId);
if (!$this->originalObject) {
throw new SearchApiException('Failed to load original object ' . $this->itemId);
}
}
return $this->originalObject;
}
/**
* {@inheritdoc}
*/
public function setOriginalObject(ComplexDataInterface $original_object) {
$this->originalObject = $original_object;
return $this;
}
/**
* {@inheritdoc}
*/
public function getField($field_id, $extract = TRUE) {
if (isset($this->fields[$field_id])) {
return $this->fields[$field_id];
}
$fields = $this
->getFields($extract);
return isset($fields[$field_id]) ? $fields[$field_id] : NULL;
}
/**
* {@inheritdoc}
*/
public function getFields($extract = TRUE) {
if ($extract && !$this->fieldsExtracted) {
$data_type_fallback_mapping = \Drupal::getContainer()
->get('search_api.data_type_helper')
->getDataTypeFallbackMapping($this->index);
foreach ([
NULL,
$this
->getDatasourceId(),
] as $datasource_id) {
$fields_by_property_path = [];
$processors_with_fields = [];
$properties = $this->index
->getPropertyDefinitions($datasource_id);
foreach ($this->index
->getFieldsByDatasource($datasource_id) as $field_id => $field) {
// Don't overwrite fields that were previously set.
if (empty($this->fields[$field_id])) {
$this->fields[$field_id] = clone $field;
$field_data_type = $this->fields[$field_id]
->getType();
// If the field data type is in the fallback mapping list, then use
// the fallback type as field type.
if (isset($data_type_fallback_mapping[$field_data_type])) {
$this->fields[$field_id]
->setType($data_type_fallback_mapping[$field_data_type]);
}
// For determining whether the field is provided via a processor, we
// need to check using the first part of its property path (in other
// words, the property that's directly on the result item, not
// nested), since only direct properties of the item can be added by
// the processor.
$property = NULL;
$property_name = Utility::splitPropertyPath($field
->getPropertyPath(), FALSE)[0];
if (isset($properties[$property_name])) {
$property = $properties[$property_name];
}
if ($property instanceof ProcessorPropertyInterface) {
$processors_with_fields[$property
->getProcessorId()] = TRUE;
}
elseif ($datasource_id) {
$fields_by_property_path[$field
->getPropertyPath()][] = $this->fields[$field_id];
}
}
}
try {
if ($fields_by_property_path) {
\Drupal::getContainer()
->get('search_api.fields_helper')
->extractFields($this
->getOriginalObject(), $fields_by_property_path, $this
->getLanguage());
}
if ($processors_with_fields) {
$processors = $this->index
->getProcessorsByStage(ProcessorInterface::STAGE_ADD_PROPERTIES);
foreach ($processors as $processor_id => $processor) {
if (isset($processors_with_fields[$processor_id])) {
$processor
->addFieldValues($this);
}
}
}
} catch (SearchApiException $e) {
// If we couldn't load the object, just log an error and fail
// silently to set the values.
$this
->logException($e);
}
}
$this->fieldsExtracted = TRUE;
}
return $this->fields;
}
/**
* {@inheritdoc}
*/
public function setField($field_id, FieldInterface $field = NULL) {
if ($field) {
if ($field
->getFieldIdentifier() !== $field_id) {
throw new \InvalidArgumentException('The field identifier passed must be consistent with the identifier set on the field object.');
}
// Make sure that the field has the same index object set as we. This
// might otherwise cause impossibly hard-to-detect bugs.
$field
->setIndex($this->index);
$this->fields[$field_id] = $field;
}
else {
unset($this->fields[$field_id]);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function setFields(array $fields) {
// Make sure that all fields have the same index object set as we. This
// might otherwise cause impossibly hard-to-detect bugs.
/** @var \Drupal\search_api\Item\FieldInterface $field */
foreach ($fields as $field) {
$field
->setIndex($this->index);
}
$this->fields = $fields;
return $this;
}
/**
* {@inheritdoc}
*/
public function isFieldsExtracted() {
return $this->fieldsExtracted;
}
/**
* {@inheritdoc}
*/
public function setFieldsExtracted($fields_extracted) {
$this->fieldsExtracted = $fields_extracted;
return $this;
}
/**
* {@inheritdoc}
*/
public function getScore() {
return $this->score;
}
/**
* {@inheritdoc}
*/
public function setScore($score) {
$this->score = $score;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBoost() {
return $this->boost;
}
/**
* {@inheritdoc}
*/
public function setBoost($boost) {
$this->boost = $boost;
return $this;
}
/**
* {@inheritdoc}
*/
public function getExcerpt() {
return $this->excerpt;
}
/**
* {@inheritdoc}
*/
public function setExcerpt($excerpt) {
$this->excerpt = $excerpt;
return $this;
}
/**
* {@inheritdoc}
*/
public function hasExtraData($key) {
return array_key_exists($key, $this->extraData);
}
/**
* {@inheritdoc}
*/
public function getExtraData($key, $default = NULL) {
return array_key_exists($key, $this->extraData) ? $this->extraData[$key] : $default;
}
/**
* {@inheritdoc}
*/
public function getAllExtraData() {
return $this->extraData;
}
/**
* {@inheritdoc}
*/
public function setExtraData($key, $data = NULL) {
if (isset($data)) {
$this->extraData[$key] = $data;
}
else {
unset($this->extraData[$key]);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function checkAccess(AccountInterface $account = NULL) {
@trigger_error('\\Drupal\\search_api\\Item\\ItemInterface::checkAccess() is deprecated in search_api:8.x-1.14 and is removed from search_api:2.0.0. Use getAccessResult() instead. See https://www.drupal.org/node/3051902', E_USER_DEPRECATED);
return $this
->getAccessResult($account)
->isAllowed();
}
/**
* {@inheritdoc}
*/
public function getAccessResult(AccountInterface $account = NULL) {
if (!$account) {
$account = \Drupal::currentUser();
}
$uid = $account
->id();
if (empty($this->accessResults[$uid])) {
try {
$this->accessResults[$uid] = $this
->getDatasource()
->getItemAccessResult($this
->getOriginalObject(), $account);
} catch (SearchApiException $e) {
$this->accessResults[$uid] = AccessResult::neutral('Item could not be loaded, so cannot check access');
}
}
return $this->accessResults[$uid];
}
/**
* {@inheritdoc}
*/
public function getIterator() {
return new \ArrayIterator($this
->getFields());
}
/**
* Implements the magic __clone() method to implement a deep clone.
*/
public function __clone() {
// The fields definitely need to be cloned. For the extra data its hard (or,
// rather, impossible) to tell, but we opt for cloning objects there, too,
// to be on the (hopefully) safer side. (Ideas for later: introduce an
// interface that tells us to not clone the data object; or check whether
// its an entity; or introduce some other system to override this default.)
foreach ($this->fields as $field_id => $field) {
$this->fields[$field_id] = clone $field;
}
foreach ($this->extraData as $key => $data) {
if (is_object($data)) {
$this->extraData[$key] = clone $data;
}
}
}
/**
* Implements the magic __sleep() method to avoid serializing the index.
*/
public function __sleep() {
$this->indexId = $this->index
->id();
$properties = get_object_vars($this);
// Don't serialize objects that can easily be loaded again. (We cannot be
// sure about the "original object", so we do serialize that.
unset($properties['index']);
unset($properties['datasource']);
unset($properties['accessResults']);
return array_keys($properties);
}
/**
* Implements the magic __wakeup() method to control object unserialization.
*/
public function __wakeup() {
// Make sure we have a container to do this. Otherwise, there could be
// errors when displaying failed tests.
if ($this->indexId && \Drupal::hasContainer()) {
$this->index = \Drupal::entityTypeManager()
->getStorage('search_api_index')
->load($this->indexId);
$this->indexId = NULL;
if ($this->index && $this->fields) {
foreach ($this->fields as $field) {
$field
->setIndex($this->index);
}
}
}
}
/**
* Implements the magic __toString() method to simplify debugging.
*/
public function __toString() {
$out = 'Item ' . $this
->getId();
if ($this
->getScore() != 1) {
$out .= "\nScore: " . $this
->getScore();
}
if ($this
->getBoost() != 1) {
$out .= "\nBoost: " . $this
->getBoost();
}
if ($this
->getExcerpt()) {
$excerpt = str_replace("\n", "\n ", $this
->getExcerpt());
$out .= "\nExcerpt: {$excerpt}";
}
if ($this
->getFields(FALSE)) {
$out .= "\nFields:";
foreach ($this
->getFields(FALSE) as $field) {
$field = str_replace("\n", "\n ", "{$field}");
$out .= "\n- " . $field;
}
}
if ($this
->getAllExtraData()) {
$data = str_replace("\n", "\n ", print_r($this
->getAllExtraData(), TRUE));
$out .= "\nExtra data: " . $data;
}
return $out;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
Item:: |
protected | property | Cached access results for the item, keyed by user ID. | |
Item:: |
protected | property | The boost of this item at indexing time. | |
Item:: |
protected | property | The datasource of this item. | |
Item:: |
protected | property | The ID of this item's datasource. | |
Item:: |
protected | property | The HTML text with highlighted text-parts that match the query. | |
Item:: |
protected | property | Extra data set on this item. | |
Item:: |
protected | property | The extracted fields of this item. | |
Item:: |
protected | property | Whether the fields were already extracted for this item. | |
Item:: |
protected | property | The search index with which this item is associated. | |
Item:: |
protected | property | The ID of the index with which this item is associated. | |
Item:: |
protected | property | The ID of this item. | |
Item:: |
protected | property | The language code of this item. | |
Item:: |
protected | property | The complex data item this Search API item is based on. | |
Item:: |
protected | property | The score this item had as a result in a corresponding search query. | |
Item:: |
public | function |
Checks whether a user has permission to view this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Checks whether a user has permission to view this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Retrieves all extra data set for this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Gets the boost value of this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the datasource of this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the ID of this item's datasource. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns an HTML text with highlighted text-parts that match the query. Overrides ItemInterface:: |
|
Item:: |
public | function |
Retrieves extra data for this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Retrieves a single field of this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the item's fields. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the item's ID. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the index of this item. Overrides ItemInterface:: |
|
Item:: |
public | function | ||
Item:: |
public | function |
Retrieves the item language. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the original complex data object this Search API item is based on. Overrides ItemInterface:: |
|
Item:: |
public | function |
Returns the score of the item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Determines whether extra data with a specific key is set on this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Determines whether fields have been extracted already for this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets the boost value of this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets an HTML text with highlighted text-parts that match the query. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets some extra data for this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets one of the item's fields. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets the item's fields. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets the field extraction state of this item. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets the item language. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets the original complex data object this item should be based on. Overrides ItemInterface:: |
|
Item:: |
public | function |
Sets the score of the item. Overrides ItemInterface:: |
|
Item:: |
public | function | Implements the magic __clone() method to implement a deep clone. | |
Item:: |
public | function | Constructs an Item object. | |
Item:: |
public | function | Implements the magic __sleep() method to avoid serializing the index. | |
Item:: |
public | function | Implements the magic __toString() method to simplify debugging. | |
Item:: |
public | function | Implements the magic __wakeup() method to control object unserialization. | |
LoggerTrait:: |
protected | property | The logging channel to use. | |
LoggerTrait:: |
public | function | Retrieves the logger. | |
LoggerTrait:: |
protected | function | Logs an exception. | |
LoggerTrait:: |
public | function | Sets the logger. |