You are here

NodeSearch.php in Multiversion 8

File

src/Entity/Search/NodeSearch.php
View source
<?php

namespace Drupal\multiversion\Entity\Search;

use Drupal\Core\Database\Query\Condition;
use Drupal\Search\SearchQuery;
use Drupal\node\Plugin\Search\NodeSearch as CoreNodeSearch;

/**
 * Handles searching for node entities using the Search module index.
 *
 * Overriding search result to accommodate '_delete' flag. Only line needs
 * change here is the query condition "AND _deleted = 0". But there is no
 * easy way to override it.
 *
 * @see https://www.drupal.org/project/drupal/issues/3039265
 */
class NodeSearch extends CoreNodeSearch {

  /**
   * {@inheritdoc}
   */
  protected function findResults() {
    $keys = $this->keywords;

    // Build matching conditions.
    $query = $this->database
      ->select('search_index', 'i', [
      'target' => 'replica',
    ])
      ->extend('Drupal\\search\\SearchQuery')
      ->extend('Drupal\\Core\\Database\\Query\\PagerSelectExtender');
    $query
      ->join('node_field_data', 'n', 'n.nid = i.sid AND n.langcode = i.langcode AND _deleted = 0');
    $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 = new 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;
  }

}

Classes

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