vendor/shopware/elasticsearch/Framework/ElasticsearchHelper.php line 135

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Elasticsearch\Framework;
  3. use Elasticsearch\Client;
  4. use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
  5. use ONGR\ElasticsearchDSL\Query\FullText\MatchQuery;
  6. use ONGR\ElasticsearchDSL\Search;
  7. use Psr\Log\LoggerInterface;
  8. use Shopware\Core\Framework\Context;
  9. use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  13. use Shopware\Elasticsearch\Exception\NoIndexedDocumentsException;
  14. use Shopware\Elasticsearch\Exception\ServerNotAvailableException;
  15. use Shopware\Elasticsearch\Exception\UnsupportedElasticsearchDefinitionException;
  16. use Shopware\Elasticsearch\Framework\DataAbstractionLayer\CriteriaParser;
  17. class ElasticsearchHelper
  18. {
  19.     // max for default configuration
  20.     public const MAX_SIZE_VALUE 10000;
  21.     /**
  22.      * @var Client
  23.      */
  24.     private $client;
  25.     /**
  26.      * @var ElasticsearchRegistry
  27.      */
  28.     private $registry;
  29.     /**
  30.      * @var CriteriaParser
  31.      */
  32.     private $parser;
  33.     /**
  34.      * @var bool
  35.      */
  36.     private $searchEnabled;
  37.     /**
  38.      * @var bool
  39.      */
  40.     private $indexingEnabled;
  41.     /**
  42.      * @var string
  43.      */
  44.     private $environment;
  45.     /**
  46.      * @var LoggerInterface
  47.      */
  48.     private $logger;
  49.     /**
  50.      * @var string
  51.      */
  52.     private $prefix;
  53.     /**
  54.      * @var bool
  55.      */
  56.     private $throwException;
  57.     public function __construct(
  58.         string $environment,
  59.         bool $searchEnabled,
  60.         bool $indexingEnabled,
  61.         string $prefix,
  62.         bool $throwException,
  63.         Client $client,
  64.         ElasticsearchRegistry $registry,
  65.         CriteriaParser $parser,
  66.         LoggerInterface $logger
  67.     ) {
  68.         $this->client $client;
  69.         $this->registry $registry;
  70.         $this->parser $parser;
  71.         $this->searchEnabled $searchEnabled;
  72.         $this->indexingEnabled $indexingEnabled;
  73.         $this->environment $environment;
  74.         $this->logger $logger;
  75.         $this->prefix $prefix;
  76.         $this->throwException $throwException;
  77.     }
  78.     public function logOrThrowException(\Throwable $exception): bool
  79.     {
  80.         if ($this->environment === 'test') {
  81.             throw $exception;
  82.         }
  83.         if ($this->environment !== 'dev') {
  84.             return false;
  85.         }
  86.         if ($this->throwException) {
  87.             throw $exception;
  88.         }
  89.         $this->logger->critical($exception->getMessage());
  90.         return false;
  91.     }
  92.     /**
  93.      * Created the index alias
  94.      */
  95.     public function getIndexName(EntityDefinition $definitionstring $languageId): string
  96.     {
  97.         return $this->prefix '_' $definition->getEntityName() . '_' $languageId;
  98.     }
  99.     public function allowIndexing(): bool
  100.     {
  101.         if (!$this->indexingEnabled) {
  102.             return false;
  103.         }
  104.         if (!$this->client->ping()) {
  105.             return $this->logOrThrowException(new ServerNotAvailableException());
  106.         }
  107.         return true;
  108.     }
  109.     /**
  110.      * Validates if it is allowed do execute the search request over elasticsearch
  111.      */
  112.     public function allowSearch(EntityDefinition $definitionContext $context): bool
  113.     {
  114.         if (!$this->searchEnabled) {
  115.             return false;
  116.         }
  117.         if (!$this->isSupported($definition)) {
  118.             return false;
  119.         }
  120.         // while indexing or not cacheable call?
  121.         if (!$context->getUseCache()) {
  122.             return false;
  123.         }
  124.         if (!$this->client->ping()) {
  125.             return $this->logOrThrowException(new ServerNotAvailableException());
  126.         }
  127.         if ($this->hasIndexDocuments($definition$context)) {
  128.             return true;
  129.         }
  130.         return $this->logOrThrowException(new NoIndexedDocumentsException($definition->getEntityName()));
  131.     }
  132.     public function handleIds(EntityDefinition $definitionCriteria $criteriaSearch $searchContext $context): void
  133.     {
  134.         $ids $criteria->getIds();
  135.         if (empty($ids)) {
  136.             return;
  137.         }
  138.         $query $this->parser->parseFilter(
  139.             new EqualsAnyFilter('id'array_values($ids)),
  140.             $definition,
  141.             $definition->getEntityName(),
  142.             $context
  143.         );
  144.         $search->addQuery($queryBoolQuery::FILTER);
  145.     }
  146.     public function addFilters(EntityDefinition $definitionCriteria $criteriaSearch $searchContext $context): void
  147.     {
  148.         $filters $criteria->getFilters();
  149.         if (empty($filters)) {
  150.             return;
  151.         }
  152.         $query $this->parser->parseFilter(
  153.             new MultiFilter(MultiFilter::CONNECTION_AND$filters),
  154.             $definition,
  155.             $definition->getEntityName(),
  156.             $context
  157.         );
  158.         $search->addQuery($queryBoolQuery::FILTER);
  159.     }
  160.     public function addPostFilters(EntityDefinition $definitionCriteria $criteriaSearch $searchContext $context): void
  161.     {
  162.         $postFilters $criteria->getPostFilters();
  163.         if (empty($postFilters)) {
  164.             return;
  165.         }
  166.         $query $this->parser->parseFilter(
  167.             new MultiFilter(MultiFilter::CONNECTION_AND$postFilters),
  168.             $definition,
  169.             $definition->getEntityName(),
  170.             $context
  171.         );
  172.         $search->addPostFilter($queryBoolQuery::FILTER);
  173.     }
  174.     public function addTerm(Criteria $criteriaSearch $searchContext $contextEntityDefinition $definition): void
  175.     {
  176.         if (!$criteria->getTerm()) {
  177.             return;
  178.         }
  179.         $esDefinition $this->registry->get($definition->getEntityName());
  180.         if (!$esDefinition) {
  181.             throw new UnsupportedElasticsearchDefinitionException($definition->getEntityName());
  182.         }
  183.         $query $esDefinition->buildTermQuery($context$criteria);
  184.         $search->addQuery($query);
  185.     }
  186.     public function addQueries(EntityDefinition $definitionCriteria $criteriaSearch $searchContext $context): void
  187.     {
  188.         $queries $criteria->getQueries();
  189.         if (empty($queries)) {
  190.             return;
  191.         }
  192.         $bool = new BoolQuery();
  193.         foreach ($queries as $query) {
  194.             $parsed $this->parser->parseFilter($query->getQuery(), $definition$definition->getEntityName(), $context);
  195.             if ($parsed instanceof MatchQuery) {
  196.                 $score = (string) $query->getScore();
  197.                 /* @var MatchQuery $parsed */
  198.                 $parsed->addParameter('boost'$score);
  199.                 $parsed->addParameter('fuzziness''2');
  200.             }
  201.             $bool->add($parsedBoolQuery::SHOULD);
  202.         }
  203.         $bool->addParameter('minimum_should_match''1');
  204.         $search->addQuery($bool);
  205.     }
  206.     public function addSortings(EntityDefinition $definitionCriteria $criteriaSearch $searchContext $context): void
  207.     {
  208.         foreach ($criteria->getSorting() as $sorting) {
  209.             $search->addSort(
  210.                 $this->parser->parseSorting($sorting$definition$context)
  211.             );
  212.         }
  213.     }
  214.     public function addAggregations(EntityDefinition $definitionCriteria $criteriaSearch $searchContext $context): void
  215.     {
  216.         $aggregations $criteria->getAggregations();
  217.         if (empty($aggregations)) {
  218.             return;
  219.         }
  220.         foreach ($aggregations as $aggregation) {
  221.             $agg $this->parser->parseAggregation($aggregation$definition$context);
  222.             if (!$agg) {
  223.                 continue;
  224.             }
  225.             $search->addAggregation($agg);
  226.         }
  227.     }
  228.     /**
  229.      * Only used for unit tests because the container parameter bag is frozen and can not be changed at runtime.
  230.      * Therefore this function can be used to test different behaviours
  231.      *
  232.      * @internal
  233.      */
  234.     public function setEnabled(bool $enabled): self
  235.     {
  236.         $this->searchEnabled $enabled;
  237.         $this->indexingEnabled $enabled;
  238.         return $this;
  239.     }
  240.     public function isSupported(EntityDefinition $definition): bool
  241.     {
  242.         $entityName $definition->getEntityName();
  243.         return $this->registry->has($entityName);
  244.     }
  245.     private function hasIndexDocuments(EntityDefinition $definitionContext $context): bool
  246.     {
  247.         $index $this->getIndexName($definition$context->getLanguageId());
  248.         $exists $this->client->indices()->exists(['index' => $index]);
  249.         if (!$exists) {
  250.             return false;
  251.         }
  252.         $count $this->client->count(['index' => $index]);
  253.         if (!\array_key_exists('count'$count)) {
  254.             return false;
  255.         }
  256.         return $count['count'] > 0;
  257.     }
  258. }