search_api_meilisearch-1.0.x-dev/src/Parser/StringExpressionFilterParser.php

src/Parser/StringExpressionFilterParser.php
<?php

namespace Drupal\search_api_meilisearch\Parser;

use Drupal\search_api\IndexInterface;
use Drupal\search_api\Query\ConditionGroupInterface;
use Drupal\search_api\Query\ConditionInterface;

/**
 * Provides parsing of string expression filters from condition group.
 */
final class StringExpressionFilterParser implements FilterParserInterface {

  /**
   * The list of applicable condition parsers.
   *
   * @var \Drupal\search_api_meilisearch\Parser\ConditionParserInterface[]
   */
  private array $conditionParsers = [];

  /**
   * The list of sorted condition parsers.
   *
   * @var \Drupal\search_api_meilisearch\Parser\ConditionParserInterface[]
   */
  private ?array $sortedConditionParsers = NULL;

  /**
   * The current recursion level.
   *
   * @var int
   */
  private int $level = 0;

  /**
   * {@inheritdoc}
   */
  public function parseExpression(ConditionGroupInterface $conditionGroup, IndexInterface $index): string {
    $this->level = 0;

    return $this->parseConditionGroup($conditionGroup, $index);
  }

  /**
   * Appends a condition parser to the list.
   *
   * @param \Drupal\search_api_meilisearch\Parser\ConditionParserInterface $parser
   *   The condition parser to be appended to the list.
   * @param int $priority
   *   The priority of the condition parser being added.
   *
   * @return $this
   */
  public function addConditionParser(ConditionParserInterface $parser, int $priority = 0): self {
    $this->conditionParsers[$priority][] = $parser;
    $this->sortedConditionParsers = NULL;

    return $this;
  }

  /**
   * Recursively parses expression from a condition group.
   *
   * @param \Drupal\search_api\Query\ConditionGroupInterface $conditionGroup
   *   The condition group.
   * @param \Drupal\search_api\IndexInterface $index
   *   The index the condition group belongs to.
   *
   * @return string
   *   The string expression filter.
   */
  private function parseConditionGroup(ConditionGroupInterface $conditionGroup, IndexInterface $index): string {
    $this->level++;
    $conditions = $conditionGroup->getConditions();
    if (!count($conditions)) {
      return '';
    }

    $filter = '';
    $conjunction = " {$conditionGroup->getConjunction()} ";
    foreach ($conditions as $condition) {
      if ($condition instanceof ConditionInterface) {
        $filter .= $this->parseCondition($condition, $conjunction, $index);
        continue;
      }

      $parsedGroup = $this->parseConditionGroup($condition, $index);
      if ($parsedGroup === '') {
        $this->level--;
        continue;
      }

      if ($this->wrapConditionInParenthesis($condition, $conditionGroup)) {
        $parsedGroup = '(' . $parsedGroup . ')';
      }
      $filter .= $parsedGroup . $conjunction;
      $this->level--;
    }

    return rtrim($filter, $conjunction);
  }

  /**
   * Parses expression from a condition.
   *
   * @param \Drupal\search_api\Query\ConditionInterface $condition
   *   The condition group.
   * @param string $conjunction
   *   The conditions conjunction.
   * @param \Drupal\search_api\IndexInterface $index
   *   The index the condition group belongs to.
   *
   * @return string
   *   The string expression of a condition.
   */
  private function parseCondition(ConditionInterface $condition, string $conjunction, IndexInterface $index): string {
    if ($this->sortedConditionParsers === NULL) {
      $this->sortedConditionParsers = $this->sortConditionParsers();
    }

    foreach ($this->sortedConditionParsers as $conditionParser) {
      if ($conditionParser->supports($condition, $index)) {
        return $conditionParser->parse($condition, $index) . $conjunction;
      }
    }

    return '';
  }

  /**
   * Checks if a condition string should be wrapped in parenthesis.
   *
   * @param \Drupal\search_api\Query\ConditionGroupInterface $currentGroup
   *   The current group being processed.
   * @param \Drupal\search_api\Query\ConditionGroupInterface $parentGroup
   *   The parent group of the current group.
   *
   * @return bool
   *   TRUE if condition should be wrapped in parenthesis, FALSE otherwise.
   */
  private function wrapConditionInParenthesis(ConditionGroupInterface $currentGroup, ConditionGroupInterface $parentGroup): bool {
    // First level conditions do not need to be wrapped.
    if ($this->level < 2) {
      return FALSE;
    }

    // A single condition in a parent group does not need to be wrapped.
    if (count($parentGroup->getConditions()) < 2) {
      return FALSE;
    }

    // A single condition in the current group does not need to be wrapped.
    if (count($currentGroup->getConditions()) < 2) {
      return FALSE;
    }

    if ($parentGroup->getConjunction() === 'OR' && $currentGroup->getConjunction() === 'AND') {
      return FALSE;
    }

    return $currentGroup->getConjunction() != $parentGroup->getConjunction();
  }

  /**
   * Sorts condition parsers by priority.
   *
   * @return \Drupal\search_api_meilisearch\Parser\ConditionParserInterface[]
   *   A sorted array of condition parser objects.
   */
  private function sortConditionParsers(): array {
    krsort($this->conditionParsers);

    return array_merge([], ...$this->conditionParsers);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc