You are here

public function IndexResource::process in JSON:API Search API 8

Process the resource request.

Parameters

\Symfony\Component\HttpFoundation\Request $request: The request.

\Drupal\search_api\IndexInterface $index: The index.

Return value

\Drupal\jsonapi\ResourceResponse The response.

Throws

\Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException

\Drupal\Component\Plugin\Exception\PluginNotFoundException

\Drupal\search_api\SearchApiException

\Drupal\Component\Plugin\Exception\PluginException

File

src/Resource/IndexResource.php, line 79

Class

IndexResource
JSON:API Resource to return Search API index results.

Namespace

Drupal\jsonapi_search_api\Resource

Code

public function process(Request $request, IndexInterface $index) : ResourceResponse {
  $cacheability = new CacheableMetadata();

  // Ensure that different pages will be cached separately.
  $cacheability
    ->addCacheContexts([
    'url.query_args:page',
  ]);
  $cacheability
    ->addCacheContexts([
    'url.query_args:filter',
  ]);
  $cacheability
    ->addCacheContexts([
    'url.query_args:sort',
  ]);

  // Ensure changes to the index invalidate cache.
  $cacheability
    ->addCacheableDependency($index);

  // Make sure the index list cache tag is present.
  $cacheability
    ->addCacheTags([
    'search_api_list:' . $index
      ->id(),
  ]);
  $query = $index
    ->query();

  // Set the search ID so we can identify that these queries are coming from
  // JSON:API.
  $query
    ->setSearchId(strtr('jsonapi_search_api:!index', [
    '!index' => $index
      ->id(),
  ]));

  // Derive any pagination options from the query params or use defaults.
  $pagination = $this
    ->getPagination($request);
  if ($pagination
    ->getSize() <= 0) {
    throw new CacheableBadRequestHttpException($cacheability, sprintf('The page size needs to be a positive integer.'));
  }
  $query
    ->range($pagination
    ->getOffset(), $pagination
    ->getSize());
  if ($request->query
    ->has(Filter::KEY_NAME)) {
    $this
      ->applyFiltersToQuery($request, $query, $cacheability);
  }
  if ($request->query
    ->has('sort')) {
    $this
      ->applySortingToQuery($request, $query, $cacheability);
  }

  // Get the results and convert to JSON:API resource object data.
  try {
    $results = $query
      ->execute();
  } catch (SearchApiException $exception) {
    throw new CacheableBadRequestHttpException($cacheability, $exception
      ->getMessage());
  }

  // Load all entities at once, for better performance.
  $results
    ->preLoadResultItems();
  $result_entities = array_map(static function (ItemInterface $item) {
    return $item
      ->getOriginalObject()
      ->getValue();
  }, $results
    ->getResultItems());
  $primary_data = $this
    ->createCollectionDataFromEntities(array_values($result_entities));
  $primary_data
    ->setTotalCount((int) $results
    ->getResultCount());
  $pager_links = $this
    ->getPagerLinks($request, $pagination, $primary_data
    ->getTotalCount(), count($result_entities));

  // @todo remove after https://www.drupal.org/project/jsonapi_resources/issues/3120437
  $meta = [
    'count' => $primary_data
      ->getTotalCount(),
  ];

  // Dispatch an event to allow other modules to modify the meta.
  $event = new AddSearchMetaEvent($query, $results, $meta);
  $meta = $this->eventDispatcher
    ->dispatch(Events::ADD_SEARCH_META, $event)
    ->getMeta();
  $response = $this
    ->createJsonapiResponse($primary_data, $request, 200, [], $pager_links, $meta);
  $response
    ->addCacheableDependency($cacheability);
  return $response;
}