protected function SearchApiFieldTrait::getValuesToExtract in Search API 8
Determines and prepares the property values that need to be extracted.
Parameters
\Drupal\views\ResultRow[] $values: The Views result rows from which property values should be extracted.
string|null $datasource_id: The datasource ID of the property to extract (or NULL for datasource- independent properties).
string $property_path: The property path of the property to extract.
string $combined_property_path: The combined property path of the property to extract.
string[] $dependents: The actually required properties (as combined property paths) that depend on this property.
Return value
\Drupal\Core\TypedData\TypedDataInterface[][] The values of the property for each result row, keyed by result row index.
1 call to SearchApiFieldTrait::getValuesToExtract()
- SearchApiFieldTrait::preRender in src/
Plugin/ views/ field/ SearchApiFieldTrait.php - Runs before any fields are rendered.
File
- src/
Plugin/ views/ field/ SearchApiFieldTrait.php, line 612
Class
- SearchApiFieldTrait
- Provides a trait to use for Search API Views field handlers.
Namespace
Drupal\search_api\Plugin\views\fieldCode
protected function getValuesToExtract(array $values, $datasource_id, $property_path, $combined_property_path, array $dependents) {
// Determine the path of the parent property, and the property key to
// take from it for this property.
list($parent_path, $name) = Utility::splitPropertyPath($property_path);
$combined_parent_path = $this
->createCombinedPropertyPath($datasource_id, $parent_path);
// For top-level properties, we need the definition to check whether its
// a processor-generated property later.
$property = NULL;
if (!$parent_path) {
$datasource_properties = $this
->getIndex()
->getPropertyDefinitions($datasource_id);
if (isset($datasource_properties[$name])) {
$property = $datasource_properties[$name];
}
}
// Now go through all rows and add the property to them, if necessary.
// We then extract the actual values in a second pass in order to be
// able to use multi-loading for any encountered entities.
/** @var \Drupal\Core\TypedData\TypedDataInterface[][] $property_values */
$property_values = [];
$entities_to_load = [];
foreach ($values as $i => $row) {
// Bail for rows with the wrong datasource for this property, or for
// which this field doesn't even apply (which will usually be the
// same, though).
if ($datasource_id && $datasource_id !== $row->search_api_datasource || !$this
->isActiveForRow($row)) {
continue;
}
// Then, make sure we even need this property for the current row. (Will
// not be the case if all required properties that depend on this property
// were already set on the row previously.)
$required = FALSE;
foreach ($dependents as $dependent) {
if (!isset($row->{$dependent})) {
$required = TRUE;
break;
}
}
if (!$required) {
continue;
}
// Check whether there are parent objects present. Otherwise, nothing we
// can do here.
if (empty($row->_relationship_objects[$combined_parent_path])) {
continue;
}
// If the property key is "_object", we only needed to load the parent
// object(s), so we just copy those to the result row object and we're
// done.
if ($name === '_object') {
// The $row->_object is special, since we also set it in
// \Drupal\search_api\Plugin\views\query\SearchApiQuery::addResults()
// (conditionally). To keep it consistent, we make it single-valued
// here, too.
if ($combined_property_path !== '_object') {
$row->{$combined_property_path} = $row->_relationship_objects[$combined_parent_path];
}
continue;
}
if (empty($row->_relationship_objects[$combined_property_path])) {
// Check whether this is a processor-generated property and use
// special code to retrieve it in that case.
if ($property instanceof ProcessorPropertyInterface) {
// Determine whether this property is required.
$is_required = in_array($combined_property_path, $dependents);
$this
->extractProcessorProperty($property, $row, $datasource_id, $property_path, $combined_property_path, $is_required);
continue;
}
foreach ($row->_relationship_objects[$combined_parent_path] as $j => $parent) {
// Follow references.
while ($parent instanceof DataReferenceInterface) {
$parent = $parent
->getTarget();
}
// At this point we need the parent to be a complex item,
// otherwise it can't have any children (and thus, our property
// can't be present).
if (!$parent instanceof ComplexDataInterface) {
continue;
}
try {
// Retrieve the actual typed data for the property and add it to
// our property values.
$typed_data = $parent
->get($name);
$property_values[$i][$j] = $typed_data;
// Remember any encountered entity references so we can
// multi-load them.
if ($typed_data instanceof DataReferenceInterface) {
/** @var \Drupal\Core\TypedData\DataReferenceDefinitionInterface $definition */
$definition = $typed_data
->getDataDefinition();
$definition = $definition
->getTargetDefinition();
if ($definition instanceof EntityDataDefinitionInterface) {
$entity_type_id = $definition
->getEntityTypeId();
$entity_type = $this
->getEntityTypeManager()
->getDefinition($entity_type_id);
if ($entity_type
->isStaticallyCacheable()) {
$entity_id = $typed_data
->getTargetIdentifier();
if ($entity_id) {
$entities_to_load[$entity_type_id][$entity_id] = $entity_id;
}
}
}
}
} catch (\InvalidArgumentException $e) {
// This can easily happen, for example, when requesting a field
// that only exists on a different bundle. Unfortunately, there
// is no ComplexDataInterface::hasProperty() method, so we can
// only catch and ignore the exception.
}
}
}
}
// Multi-load all entities we encountered before (to get them into the
// static cache).
foreach ($entities_to_load as $entity_type_id => $ids) {
$this
->getEntityTypeManager()
->getStorage($entity_type_id)
->loadMultiple($ids);
}
return $property_values;
}