You are here

protected function NodeSearch::findResults in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/node/src/Plugin/Search/NodeSearch.php \Drupal\node\Plugin\Search\NodeSearch::findResults()

Queries to find search results, and sets status messages.

This method can assume that $this->isSearchExecutable() has already been checked and returned TRUE.

Return value

\Drupal\Core\Database\StatementInterface|null Results from search query execute() method, or NULL if the search failed.

1 call to NodeSearch::findResults()
NodeSearch::execute in core/modules/node/src/Plugin/Search/NodeSearch.php
Executes the search.

File

core/modules/node/src/Plugin/Search/NodeSearch.php, line 259

Class

NodeSearch
Handles searching for node entities using the Search module index.

Namespace

Drupal\node\Plugin\Search

Code

protected function findResults() {
  $keys = $this->keywords;

  // Build matching conditions.
  $query = $this->databaseReplica
    ->select('search_index', 'i')
    ->extend(SearchQuery::class)
    ->extend(PagerSelectExtender::class);
  $query
    ->join('node_field_data', 'n', '[n].[nid] = [i].[sid] AND [n].[langcode] = [i].[langcode]');
  $query
    ->condition('n.status', 1)
    ->addTag('node_access')
    ->searchExpression($keys, $this
    ->getPluginId());

  // Handle advanced search filters in the f query string.
  // \Drupal::request()->query->get('f') is an array that looks like this in
  // the URL: ?f[]=type:page&f[]=term:27&f[]=term:13&f[]=langcode:en
  // So $parameters['f'] looks like:
  // array('type:page', 'term:27', 'term:13', 'langcode:en');
  // We need to parse this out into query conditions, some of which go into
  // the keywords string, and some of which are separate conditions.
  $parameters = $this
    ->getParameters();
  if (!empty($parameters['f']) && is_array($parameters['f'])) {
    $filters = [];

    // Match any query value that is an expected option and a value
    // separated by ':' like 'term:27'.
    $pattern = '/^(' . implode('|', array_keys($this->advanced)) . '):([^ ]*)/i';
    foreach ($parameters['f'] as $item) {
      if (preg_match($pattern, $item, $m)) {

        // Use the matched value as the array key to eliminate duplicates.
        $filters[$m[1]][$m[2]] = $m[2];
      }
    }

    // Now turn these into query conditions. This assumes that everything in
    // $filters is a known type of advanced search.
    foreach ($filters as $option => $matched) {
      $info = $this->advanced[$option];

      // Insert additional conditions. By default, all use the OR operator.
      $operator = empty($info['operator']) ? 'OR' : $info['operator'];
      $where = $this->databaseReplica
        ->condition($operator);
      foreach ($matched as $value) {
        $where
          ->condition($info['column'], $value);
      }
      $query
        ->condition($where);
      if (!empty($info['join'])) {
        $query
          ->join($info['join']['table'], $info['join']['alias'], $info['join']['condition']);
      }
    }
  }

  // Add the ranking expressions.
  $this
    ->addNodeRankings($query);

  // Run the query.
  $find = $query
    ->fields('i', [
    'langcode',
  ])
    ->groupBy('i.langcode')
    ->limit(10)
    ->execute();

  // Check query status and set messages if needed.
  $status = $query
    ->getStatus();
  if ($status & SearchQuery::EXPRESSIONS_IGNORED) {
    $this->messenger
      ->addWarning($this
      ->t('Your search used too many AND/OR expressions. Only the first @count terms were included in this search.', [
      '@count' => $this->searchSettings
        ->get('and_or_limit'),
    ]));
  }
  if ($status & SearchQuery::LOWER_CASE_OR) {
    $this->messenger
      ->addWarning($this
      ->t('Search for either of the two terms with uppercase <strong>OR</strong>. For example, <strong>cats OR dogs</strong>.'));
  }
  if ($status & SearchQuery::NO_POSITIVE_KEYWORDS) {
    $this->messenger
      ->addWarning($this
      ->formatPlural($this->searchSettings
      ->get('index.minimum_word_size'), 'You must include at least one keyword to match in the content, and punctuation is ignored.', 'You must include at least one keyword to match in the content. Keywords must be at least @count characters, and punctuation is ignored.'));
  }
  return $find;
}