/** * {@inheritdoc} */ public function preRender($result) { // Load all result objects at once, before rendering. $items_to_load = array(); foreach ($result as $i => $row) { if (empty($row->_object)) { $items_to_load[$i] = $row->search_api_id; } } $items = $this->index->loadItemsMultiple($items_to_load); foreach ($items_to_load as $i => $item_id) { if (isset($items[$item_id])) { $result[$i]->_object = $items[$item_id]; $result[$i]->_item->setOriginalObject($items[$item_id]); } } }
/** * Adds Search API result items to a view's result set. * * @param \Drupal\search_api\Item\ItemInterface[] $results * The search results. * @param \Drupal\views\ViewExecutable $view * The executed view. */ protected function addResults(array $results, ViewExecutable $view) { /** @var \Drupal\views\ResultRow[] $rows */ $rows = array(); $missing = array(); if (!empty($this->configuration['entity_access'])) { $items = $this->index->loadItemsMultiple(array_keys($results)); $results = array_intersect_key($results, $items); /** @var \Drupal\Core\Entity\Plugin\DataType\EntityAdapter $item */ foreach ($items as $item_id => $item) { if (!$item->getValue()->access('view')) { unset($results[$item_id]); } } } // First off, we try to gather as much field values as possible without // loading any items. foreach ($results as $item_id => $result) { $datasource_id = $result->getDatasourceId(); // @todo Find a more elegant way of passing metadata here. $values['search_api_id'] = $item_id; $values['search_api_datasource'] = $datasource_id; // Include the loaded item for this result row, if present, or the item // ID. $values['_item'] = $result->getOriginalObject(FALSE); if (!$values['_item']) { $values['_item'] = $item_id; } $values['search_api_relevance'] = $result->getScore(); $values['search_api_excerpt'] = $result->getExcerpt() ?: ''; // Gather any fields from the search results. foreach ($result->getFields(FALSE) as $field_id => $field) { if ($field->getValues()) { $values[$field_id] = $field->getValues(); } } // Check whether we need to extract any properties from the result item. $missing_fields = array_diff_key($this->fields, $values); if ($missing_fields) { $missing[$item_id] = $missing_fields; if (!is_object($values['_item'])) { $item_ids[] = $item_id; } } // Save the row values for adding them to the Views result afterwards. // @todo Use a custom sub-class here to also pass the result item object, // or other information? $rows[$item_id] = new ResultRow($values); } // Load items of those rows which haven't got all field values, yet. if (!empty($item_ids)) { foreach ($this->index->loadItemsMultiple($item_ids) as $item_id => $object) { $results[$item_id]->setOriginalObject($object); $rows[$item_id]->_item = $object; } } foreach ($missing as $item_id => $missing_fields) { foreach ($missing_fields as $field_id) { // @todo This will only extract the indexed fields, but all of them. We // should instead use Utility::extractFields() directly. $field = $results[$item_id]->getField($field_id); if ($field) { $rows[$item_id]->$field_id = $field->getValues(); } } } // Finally, add all rows to the Views result set. $view->result = array_values($rows); array_walk($view->result, function (ResultRow $row, $index) { $row->index = $index; }); }
/** * {@inheritdoc} */ public function loadItemsMultiple(array $item_ids, $group_by_datasource = FALSE) { return $this->entity->loadItemsMultiple($item_ids, $group_by_datasource); }