search_api-8.x-1.15/src/Item/Field.php
src/Item/Field.php
<?php namespace Drupal\search_api\Item; use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\search_api\DataType\DataTypePluginManager; use Drupal\search_api\IndexInterface; use Drupal\search_api\LoggerTrait; use Drupal\search_api\Processor\ConfigurablePropertyInterface; use Drupal\search_api\SearchApiException; use Drupal\search_api\Utility\Utility; /** * Represents a field on a search item that can be indexed. */ class Field implements \IteratorAggregate, FieldInterface { use LoggerTrait; /** * The index this field is attached to. * * @var \Drupal\search_api\IndexInterface */ protected $index; /** * The ID of the index this field is attached to. * * This is only used to avoid serialization of the index in __sleep() and * __wakeup(). * * @var string */ protected $indexId; /** * The field's identifier. * * @var string */ protected $fieldIdentifier; /** * The field's original identifier. * * @var string */ protected $originalFieldIdentifier; /** * The field's datasource's ID. * * @var string|null */ protected $datasourceId; /** * The field's datasource. * * @var \Drupal\search_api\Datasource\DatasourceInterface|null */ protected $datasource; /** * The property path on the search object. * * @var string */ protected $propertyPath; /** * This field's data definition. * * @var \Drupal\Core\TypedData\DataDefinitionInterface */ protected $dataDefinition; /** * The human-readable label for this field. * * @var string */ protected $label; /** * The human-readable description for this field. * * FALSE if the field has no description. * * @var string|false */ protected $description; /** * The human-readable label for this field's datasource. * * @var string */ protected $labelPrefix; /** * The Search API data type of this field. * * @var string */ protected $type; /** * The boost assigned to this field, if any. * * @var float */ protected $boost; /** * Whether this field should be hidden from the user. * * @var bool */ protected $hidden; /** * Whether this field should always be enabled/indexed. * * @var bool */ protected $indexedLocked; /** * Whether this field type should be locked. * * @var bool */ protected $typeLocked; /** * The field's configuration. * * @var array */ protected $configuration = []; /** * This field's dependencies, if any. * * @var string[][] */ protected $dependencies = []; /** * The field's values. * * @var array */ protected $values = []; /** * The original data type of this field. * * @var string */ protected $originalType; /** * The data type manager. * * @var \Drupal\search_api\DataType\DataTypePluginManager|null */ protected $dataTypeManager; /** * Constructs a Field object. * * @param \Drupal\search_api\IndexInterface $index * The field's index. * @param string $field_identifier * The field's identifier. */ public function __construct(IndexInterface $index, $field_identifier) { $this->index = $index; $this->fieldIdentifier = $this->originalFieldIdentifier = $field_identifier; } /** * Retrieves the data type manager. * * @return \Drupal\search_api\DataType\DataTypePluginManager * The data type manager. */ public function getDataTypeManager() { return $this->dataTypeManager ?: \Drupal::service('plugin.manager.search_api.data_type'); } /** * Sets the data type manager. * * @param \Drupal\search_api\DataType\DataTypePluginManager $data_type_manager * The new data type manager. * * @return $this */ public function setDataTypeManager(DataTypePluginManager $data_type_manager) { $this->dataTypeManager = $data_type_manager; return $this; } /** * {@inheritdoc} */ public function getIndex() { return $this->index; } /** * {@inheritdoc} */ public function setIndex(IndexInterface $index) { if ($this->index->id() != $index->id()) { throw new \InvalidArgumentException('Attempted to change the index of a field object.'); } $this->index = $index; $this->datasource = NULL; return $this; } /** * {@inheritdoc} */ public function getFieldIdentifier() { return $this->fieldIdentifier; } /** * {@inheritdoc} */ public function getOriginalFieldIdentifier() { return $this->originalFieldIdentifier; } /** * {@inheritdoc} */ public function setFieldIdentifier($field_id) { $this->fieldIdentifier = $field_id; return $this; } /** * {@inheritdoc} */ public function wasRenamed() { return $this->fieldIdentifier != $this->originalFieldIdentifier; } /** * {@inheritdoc} */ public function getSettings() { $settings = [ 'label' => $this->getLabel(), 'datasource_id' => $this->getDatasourceId(), 'property_path' => $this->getPropertyPath(), 'type' => $this->getType(), ]; if ($this->getDatasourceId() === NULL) { unset($settings['datasource_id']); } if ($this->getBoost() != 1.0) { $settings['boost'] = $this->getBoost(); } if ($this->isIndexedLocked()) { $settings['indexed_locked'] = TRUE; } if ($this->isTypeLocked()) { $settings['type_locked'] = TRUE; } if ($this->isHidden()) { $settings['hidden'] = TRUE; } if ($this->getConfiguration()) { $settings['configuration'] = $this->getConfiguration(); } if ($this->getDependencies()) { $settings['dependencies'] = $this->getDependencies(); } return $settings; } /** * {@inheritdoc} */ public function getDatasourceId() { return $this->datasourceId; } /** * {@inheritdoc} */ public function getDatasource() { if (!isset($this->datasource) && isset($this->datasourceId)) { $this->datasource = $this->index->getDatasource($this->datasourceId); } return $this->datasource; } /** * {@inheritdoc} */ public function setDatasourceId($datasource_id) { if ($this->datasourceId != $datasource_id) { $this->datasource = NULL; } $this->datasourceId = $datasource_id; return $this; } /** * {@inheritdoc} */ public function getPropertyPath() { return $this->propertyPath; } /** * {@inheritdoc} */ public function setPropertyPath($property_path) { $this->propertyPath = $property_path; return $this; } /** * {@inheritdoc} */ public function getCombinedPropertyPath() { return Utility::createCombinedId($this->getDatasourceId(), $this->getPropertyPath()); } /** * {@inheritdoc} */ public function getLabel() { return $this->label; } /** * {@inheritdoc} */ public function setLabel($label) { $this->label = $label; return $this; } /** * {@inheritdoc} */ public function getDescription() { if (!isset($this->description)) { try { $property = $this->getDataDefinition(); if ($property instanceof ConfigurablePropertyInterface) { $this->description = $property->getFieldDescription($this); } else { $this->description = $property->getDescription(); } $this->description = $this->description ?: FALSE; } catch (SearchApiException $e) { $this->logException($e); } } return $this->description ?: NULL; } /** * {@inheritdoc} */ public function setDescription($description) { // Set FALSE instead of NULL so caching will work properly. $this->description = $description ?: FALSE; return $this; } /** * {@inheritdoc} */ public function getPrefixedLabel() { if (!isset($this->labelPrefix)) { $this->labelPrefix = ''; if (isset($this->datasourceId)) { $this->labelPrefix = $this->datasourceId; try { $this->labelPrefix = $this->getDatasource()->label(); } catch (SearchApiException $e) { $this->logException($e); } $this->labelPrefix .= ' » '; } } return $this->labelPrefix . $this->getLabel(); } /** * {@inheritdoc} */ public function setLabelPrefix($label_prefix) { $this->labelPrefix = $label_prefix; return $this; } /** * {@inheritdoc} */ public function isHidden() { return (bool) $this->hidden; } /** * {@inheritdoc} */ public function setHidden($hidden = TRUE) { $this->hidden = $hidden; return $this; } /** * {@inheritdoc} */ public function getDataDefinition() { if (!isset($this->dataDefinition)) { $definitions = $this->index->getPropertyDefinitions($this->getDatasourceId()); $definition = \Drupal::getContainer() ->get('search_api.fields_helper') ->retrieveNestedProperty($definitions, $this->getPropertyPath()); if (!$definition) { $field_label = $this->getLabel(); $index_label = $this->getIndex()->label(); throw new SearchApiException("Could not retrieve data definition for field '$field_label' on index '$index_label'."); } $this->dataDefinition = $definition; } return $this->dataDefinition; } /** * Sets the field's data definition. * * This should mainly be used only when creating a new field object. Calling * this on an existing field object might not work as expected. * * @param \Drupal\Core\TypedData\DataDefinitionInterface $data_definition * The field's new data definition. * * @return $this */ public function setDataDefinition(DataDefinitionInterface $data_definition) { $this->dataDefinition = $data_definition; return $this; } /** * {@inheritdoc} */ public function getType() { return $this->type; } /** * {@inheritdoc} */ public function getDataTypePlugin() { $data_type_manager = $this->getDataTypeManager(); if ($data_type_manager->hasDefinition($this->getType())) { return $data_type_manager->createInstance($this->getType()); } return NULL; } /** * {@inheritdoc} */ public function setType($type) { if ($type != $this->type && $this->isTypeLocked()) { $field_label = $this->getLabel(); $index_label = $this->getIndex()->label(); throw new SearchApiException("Trying to change the type of field '$field_label' on index '$index_label', which is locked."); } $this->type = $type; return $this; } /** * {@inheritdoc} */ public function getValues() { return $this->values; } /** * {@inheritdoc} */ public function setValues(array $values) { $this->values = array_values($values); return $this; } /** * {@inheritdoc} */ public function addValue($value) { // The data type has to be able to alter the given value before it is // included. $data_type_plugin = $this->getDataTypePlugin(); if ($data_type_plugin) { $value = $data_type_plugin->getValue($value); } $this->values[] = $value; return $this; } /** * {@inheritdoc} */ public function getOriginalType() { if (!isset($this->originalType)) { $this->originalType = 'string'; try { $this->originalType = $this->getDataDefinition()->getDataType(); } catch (SearchApiException $e) { $this->logException($e); } } return $this->originalType; } /** * {@inheritdoc} */ public function setOriginalType($original_type) { $this->originalType = $original_type; return $this; } /** * {@inheritdoc} */ public function getBoost() { return isset($this->boost) ? $this->boost : 1.0; } /** * {@inheritdoc} */ public function setBoost($boost) { $this->boost = (float) $boost; return $this; } /** * {@inheritdoc} */ public function isIndexedLocked() { return (bool) $this->indexedLocked; } /** * {@inheritdoc} */ public function setIndexedLocked($indexed_locked = TRUE) { $this->indexedLocked = $indexed_locked; return $this; } /** * {@inheritdoc} */ public function isTypeLocked() { return (bool) $this->typeLocked; } /** * {@inheritdoc} */ public function setTypeLocked($type_locked = TRUE) { $this->typeLocked = $type_locked; return $this; } /** * {@inheritdoc} */ public function getConfiguration() { return $this->configuration; } /** * {@inheritdoc} */ public function setConfiguration(array $configuration) { $this->configuration = $configuration; return $this; } /** * {@inheritdoc} */ public function getDependencies() { return $this->dependencies; } /** * {@inheritdoc} */ public function setDependencies(array $dependencies) { $this->dependencies = $dependencies; return $this; } /** * {@inheritdoc} */ public function getIterator() { return new \ArrayIterator($this->values); } /** * Implements the magic __toString() method to simplify debugging. */ public function __toString() { $label = $this->getLabel(); $field_id = $this->getFieldIdentifier(); $type = $this->getType(); $out = "$label [$field_id]: indexed as type $type"; $is_text_type = \Drupal::getContainer() ->get('search_api.data_type_helper') ->isTextType($type); if ($is_text_type) { $out .= ' (boost ' . $this->getBoost() . ')'; } if ($this->getValues()) { $out .= "\nValues:"; foreach ($this->getValues() as $value) { $value = str_replace("\n", "\n ", "$value"); $out .= "\n- " . $value; } } return $out; } /** * {@inheritdoc} */ public function __sleep() { $this->indexId = $this->index->id(); $properties = get_object_vars($this); // Don't serialize objects in properties or the field values. unset($properties['index']); unset($properties['datasource']); unset($properties['dataDefinition']); unset($properties['dataTypeManager']); 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. This is important to correctly // display test failures. if ($this->indexId && \Drupal::hasContainer()) { $this->index = \Drupal::entityTypeManager() ->getStorage('search_api_index') ->load($this->indexId); $this->indexId = NULL; } } }