vendor/ibexa/elasticsearch/src/lib/Query/EventSubscriber/LanguageQueryFilter.php line 35

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. declare(strict_types=1);
  7. namespace Ibexa\Elasticsearch\Query\EventSubscriber;
  8. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
  9. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\CustomField;
  10. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalAnd;
  11. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalNot;
  12. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LogicalOr;
  13. use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Operator;
  14. use Ibexa\Contracts\Elasticsearch\Query\Event\QueryFilterEvent;
  15. use Ibexa\Contracts\Elasticsearch\Query\LanguageFilter;
  16. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  17. final class LanguageQueryFilter implements EventSubscriberInterface
  18. {
  19.     private const FIELD_LANGUAGES 'content_language_codes_ms';
  20.     private const FIELD_LANGUAGE 'meta_indexed_language_code_s';
  21.     private const FIELD_IS_MAIN_LANGUAGE 'meta_indexed_is_main_translation_b';
  22.     private const FIELD_IS_ALWAYS_AVAILABLE 'meta_indexed_is_main_translation_and_always_available_b';
  23.     public static function getSubscribedEvents(): array
  24.     {
  25.         return [
  26.             QueryFilterEvent::class => 'onQueryFilterEvent',
  27.         ];
  28.     }
  29.     public function onQueryFilterEvent(QueryFilterEvent $event): void
  30.     {
  31.         $languageCriteria $this->createLanguageFilter($event->getLanguageFilter());
  32.         // Append language criteria to filter
  33.         $query $event->getQuery();
  34.         if ($query->filter === null) {
  35.             $query->filter $languageCriteria;
  36.         } else {
  37.             $query->filter = new LogicalAnd([
  38.                 $languageCriteria,
  39.                 $query->filter,
  40.             ]);
  41.         }
  42.     }
  43.     private function createLanguageFilter(LanguageFilter $filter): ?Criterion
  44.     {
  45.         if (!empty($filter->getLanguages())) {
  46.             // Get condition for prioritized languages fallback
  47.             $criteria $this->getLanguagesCriteria($filter->getLanguages());
  48.             // Handle always available fallback if used
  49.             if ($filter->getUseAlwaysAvailable()) {
  50.                 $criteria = new LogicalOr([
  51.                     $criteria,
  52.                     $this->getAlwaysAvailableCriteria(
  53.                         $filter->getLanguages(),
  54.                         $filter->getExcludeTranslationsFromAlwaysAvailable()
  55.                     ),
  56.                 ]);
  57.             }
  58.             return $criteria;
  59.         }
  60.         // Otherwise search only main languages
  61.         return new CustomField(self::FIELD_IS_MAIN_LANGUAGEOperator::EQtrue);
  62.     }
  63.     /**
  64.      * Returns criteria for prioritized languages fallback.
  65.      *
  66.      * @param string[] $languageCodes
  67.      *
  68.      * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion
  69.      */
  70.     private function getLanguagesCriteria(array $languageCodes): Criterion
  71.     {
  72.         $criteria = [];
  73.         foreach ($languageCodes as $languageCode) {
  74.             $criterion = new CustomField(self::FIELD_LANGUAGEOperator::EQ$languageCode);
  75.             $excluded $this->getExcludedLanguageCodes($languageCodes$languageCode);
  76.             if (!empty($excluded)) {
  77.                 $criterion = new LogicalAnd([
  78.                     $criterion,
  79.                     new LogicalNot(
  80.                         new CustomField(self::FIELD_LANGUAGESOperator::IN$excluded)
  81.                     ),
  82.                 ]);
  83.             }
  84.             $criteria[] = $criterion;
  85.         }
  86.         if (count($criteria) > 1) {
  87.             return new LogicalOr($criteria);
  88.         }
  89.         return $criteria[0];
  90.     }
  91.     /**
  92.      * Returns criteria for always available translation fallback.
  93.      *
  94.      * @param string[] $languageCodes
  95.      * @param bool $excludeTranslationsFromAlwaysAvailable
  96.      *
  97.      * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion
  98.      */
  99.     private function getAlwaysAvailableCriteria(
  100.         array $languageCodes,
  101.         bool $excludeTranslationsFromAlwaysAvailable
  102.     ): Criterion {
  103.         $excludeOnField $excludeTranslationsFromAlwaysAvailable
  104.             // Exclude all translations by given languages
  105.             self::FIELD_LANGUAGES
  106.             // Exclude only main translation by given languages
  107.             self::FIELD_LANGUAGE
  108.         ;
  109.         return new LogicalAnd([
  110.             // Include always available main language translations
  111.             new CustomField(self::FIELD_IS_ALWAYS_AVAILABLEOperator::EQtrue),
  112.             new LogicalNot(
  113.                 new CustomField($excludeOnFieldOperator::IN$languageCodes)
  114.             ),
  115.         ]);
  116.     }
  117.     /**
  118.      * Returns a list of language codes to be excluded when matching translation in given
  119.      * $selectedLanguageCode.
  120.      *
  121.      * If $selectedLanguageCode is omitted, all languages will be returned.
  122.      *
  123.      * @param string[] $languageCodes
  124.      * @param string|null $selectedLanguageCode
  125.      *
  126.      * @return string[]
  127.      */
  128.     private function getExcludedLanguageCodes(array $languageCodes, ?string $selectedLanguageCode): array
  129.     {
  130.         $excludedLanguageCodes = [];
  131.         foreach ($languageCodes as $languageCode) {
  132.             if ($selectedLanguageCode !== null && $languageCode === $selectedLanguageCode) {
  133.                 break;
  134.             }
  135.             $excludedLanguageCodes[] = $languageCode;
  136.         }
  137.         return $excludedLanguageCodes;
  138.     }
  139. }
  140. class_alias(LanguageQueryFilter::class, 'Ibexa\Platform\ElasticSearchEngine\Query\EventSubscriber\LanguageQueryFilter');