You are here

public function FieldsHelper::extractItemValues in Search API 8

Extracts property values from items.

Values are taken from existing fields on the item, where present, and are otherwise extracted from the item's underlying object.

Parameters

\Drupal\search_api\Item\ItemInterface[] $items: The items from which properties should be extracted.

string[][] $required_properties: The properties that should be extracted, keyed by datasource ID and property path, with the values being the IDs that the values should be put under in the return value.

bool $load: (optional) If FALSE, only field values already present will be returned. Otherwise, fields will be extracted (and underlying objects loaded) if necessary.

Return value

mixed[][][] Arrays of field values, keyed by items' indexes in $items and the given field IDs from $required_properties.

Overrides FieldsHelperInterface::extractItemValues

File

src/Utility/FieldsHelper.php, line 220

Class

FieldsHelper
Provides helper methods for dealing with Search API fields and properties.

Namespace

Drupal\search_api\Utility

Code

public function extractItemValues(array $items, array $required_properties, $load = TRUE) {
  $extracted_values = [];

  /** @var \Drupal\search_api\Item\ItemInterface $item */
  foreach ($items as $i => $item) {
    $index = $item
      ->getIndex();
    $item_values = [];

    /** @var \Drupal\search_api\Item\FieldInterface[][] $missing_fields */
    $missing_fields = [];
    $processor_fields = [];
    $needed_processors = [];
    foreach ([
      NULL,
      $item
        ->getDatasourceId(),
    ] as $datasource_id) {
      if (empty($required_properties[$datasource_id])) {
        continue;
      }
      $properties = $index
        ->getPropertyDefinitions($datasource_id);
      foreach ($required_properties[$datasource_id] as $property_path => $combined_id) {
        $item_values[$combined_id] = [];

        // If a field with the right property path is already set on the item,
        // use it. This might actually make problems in case the values have
        // already been processed in some way, or use a data type that
        // transformed their original value. But that will hopefully not be a
        // problem in most situations.
        foreach ($this
          ->filterForPropertyPath($item
          ->getFields(FALSE), $datasource_id, $property_path) as $field) {
          $item_values[$combined_id] = $field
            ->getValues();
          continue 2;
        }

        // There are no values present on the item for this property. If we
        // don't want to extract any fields, skip it.
        if (!$load) {
          continue;
        }

        // If the field is not already on the item, we need to extract it. We
        // set our own combined ID as the field identifier as kind of a hack,
        // to easily be able to add the field values to $property_values
        // afterwards.
        // In case the first part of the property path refers to a
        // processor-defined property, we need to use the processor to
        // retrieve the value. Otherwise, we extract it normally from the
        // data object.
        $property_name = Utility::splitPropertyPath($property_path, FALSE)[0];
        $property = $properties[$property_name] ?? NULL;
        if ($property instanceof ProcessorPropertyInterface) {
          $field_info = [
            'datasource_id' => $datasource_id,
            'property_path' => $property_path,
          ];
          if ($property instanceof ConfigurablePropertyInterface) {
            $field_info['configuration'] = $property
              ->defaultConfiguration();

            // If the index contains a field with that property, just use the
            // configuration from there instead of the default configuration.
            // This will probably be what users expect in most situations.
            foreach ($this
              ->filterForPropertyPath($index
              ->getFields(), $datasource_id, $property_path) as $field) {
              $field_info['configuration'] = $field
                ->getConfiguration();
              break;
            }
          }
          $processor_fields[] = $this
            ->createField($index, $combined_id, $field_info);
          $needed_processors[$property
            ->getProcessorId()] = TRUE;
        }
        elseif ($datasource_id) {
          $missing_fields[$property_path][] = $this
            ->createField($index, $combined_id);
        }
      }
    }
    if ($missing_fields) {
      $this
        ->extractFields($item
        ->getOriginalObject(), $missing_fields);
      foreach ($missing_fields as $property_fields) {
        foreach ($property_fields as $field) {
          $item_values[$field
            ->getFieldIdentifier()] = $field
            ->getValues();
        }
      }
    }
    if ($processor_fields) {
      $dummy_item = clone $item;
      $dummy_item
        ->setFields($processor_fields);
      $dummy_item
        ->setFieldsExtracted(TRUE);
      $processors = $index
        ->getProcessorsByStage(ProcessorInterface::STAGE_ADD_PROPERTIES);
      foreach ($processors as $processor_id => $processor) {
        if (isset($needed_processors[$processor_id])) {
          $processor
            ->addFieldValues($dummy_item);
        }
      }
      foreach ($processor_fields as $field) {
        $item_values[$field
          ->getFieldIdentifier()] = $field
          ->getValues();
      }
    }
    $extracted_values[$i] = $item_values;
  }
  return $extracted_values;
}