custom/plugins/SwagEnterpriseSearchPlatform/src/Indexing/FieldProvider.php line 130

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Swag\EnterpriseSearch\Indexing;
  3. use Shopware\Core\Framework\Context;
  4. use Shopware\Core\Framework\DataAbstractionLayer\Dbal\EntityDefinitionQueryHelper;
  5. use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
  6. use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
  7. use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
  8. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Field\AssociationField;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Field\Field;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Field\ManyToManyAssociationField;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Field\StringField;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Field\TranslatedField;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  16. use Shopware\Core\System\NumberRange\DataAbstractionLayer\NumberRangeField;
  17. use Swag\EnterpriseSearch\Boosting\BoostingDefinition;
  18. use Swag\EnterpriseSearch\Boosting\BoostingEntity;
  19. use Swag\EnterpriseSearch\Boosting\BoostingProvider;
  20. use Swag\EnterpriseSearch\Boosting\BoostingQueryBuilder;
  21. use Swag\EnterpriseSearch\Relevance\RelevanceBluePrintCollection;
  22. use Swag\EnterpriseSearch\Relevance\RelevanceDefinition;
  23. use Swag\EnterpriseSearch\Relevance\RelevanceRepository;
  24. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  25. class FieldProvider implements EventSubscriberInterface
  26. {
  27.     /**
  28.      * @var array<string, DefinitionFieldCollection>
  29.      */
  30.     public $cache = [];
  31.     /**
  32.      * @var EntityRepositoryInterface
  33.      */
  34.     private $salesChannelRepository;
  35.     /**
  36.      * @var RelevanceRepository
  37.      */
  38.     private $relevanceRepository;
  39.     /**
  40.      * @var BoostingProvider
  41.      */
  42.     private $boostingProvider;
  43.     /**
  44.      * @var DefinitionInstanceRegistry
  45.      */
  46.     private $definitionInstanceRegistry;
  47.     public function __construct(
  48.         RelevanceRepository $relevanceRepository,
  49.         BoostingProvider $boostingProvider,
  50.         EntityRepositoryInterface $salesChannelRepository,
  51.         DefinitionInstanceRegistry $definitionInstanceRegistry
  52.     ) {
  53.         $this->salesChannelRepository $salesChannelRepository;
  54.         $this->relevanceRepository $relevanceRepository;
  55.         $this->boostingProvider $boostingProvider;
  56.         $this->definitionInstanceRegistry $definitionInstanceRegistry;
  57.     }
  58.     public function getFieldsForEntityDefinition(EntityDefinition $entityDefinition): DefinitionFieldCollection
  59.     {
  60.         if (isset($this->cache[$entityDefinition->getEntityName()])) {
  61.             return $this->cache[$entityDefinition->getEntityName()];
  62.         }
  63.         return $this->cache[$entityDefinition->getEntityName()] = $this->getFieldsSettings($entityDefinition);
  64.     }
  65.     public static function getDefinitionFieldsOfAccessor(EntityDefinition $definitionstring $accessor): array
  66.     {
  67.         $parts explode('.'$accessor);
  68.         if ($definition->getEntityName() === $parts[0]) {
  69.             array_shift($parts);
  70.         }
  71.         $accessorFields = [];
  72.         $source $definition;
  73.         foreach ($parts as $part) {
  74.             $fields $source->getFields();
  75.             if ($part === 'extensions') {
  76.                 continue;
  77.             }
  78.             $field $fields->get($part);
  79.             if ($field instanceof TranslatedField) {
  80.                 $oldSource $source;
  81.                 $source $source->getTranslationDefinition();
  82.                 $accessorFields[] = new DefinitionField($oldSource$field);
  83.                 $accessorFields[] = new DefinitionField($source$source->getFields()->get($field->getPropertyName()));
  84.                 continue;
  85.             }
  86.             if ($field) {
  87.                 $accessorFields[] = new DefinitionField($source$field);
  88.             }
  89.             if (!$field instanceof AssociationField) {
  90.                 break;
  91.             }
  92.             $source $field->getReferenceDefinition();
  93.             if ($field instanceof ManyToManyAssociationField) {
  94.                 $source $field->getToManyReferenceDefinition();
  95.             }
  96.         }
  97.         return $accessorFields;
  98.     }
  99.     public static function getSubscribedEvents(): array
  100.     {
  101.         return [
  102.             RelevanceDefinition::ENTITY_NAME '.written' => 'clear',
  103.             BoostingDefinition::ENTITY_NAME '.written' => 'clear',
  104.         ];
  105.     }
  106.     public function clear(): void
  107.     {
  108.         $this->cache = [];
  109.     }
  110.     private function getFieldsSettings(EntityDefinition $definition): DefinitionFieldCollection
  111.     {
  112.         $salesChannels $this->getSalesChannels();
  113.         $context Context::createDefaultContext();
  114.         $salesChannelIds array_map(function ($salesChannel) {
  115.             return $salesChannel->getId();
  116.         }, $salesChannels->getElements());
  117.         $relefances $this->relevanceRepository->getRelevancesBySalesChannelIds($definition$context$salesChannelIds);
  118.         $boostings $this->boostingProvider->getActiveBoostingsBySalesChannelIds($definition$context$salesChannelIds);
  119.         $settingsFields $this->getFields($definition$boostings$relefances);
  120.         $fullTextFields $this->getDefinitionFields($definition);
  121.         return new DefinitionFieldCollection(array_merge($settingsFields->getElements(), $fullTextFields->getElements()));
  122.     }
  123.     private function getDefinitionFields(EntityDefinition $definition): DefinitionFieldCollection
  124.     {
  125.         $fieldCollection = new DefinitionFieldCollection();
  126.         foreach ($definition->getFields() as $field) {
  127.             $real $field;
  128.             $isTranslated $field instanceof TranslatedField;
  129.             if ($isTranslated && $definition->getTranslationDefinition()) {
  130.                 $translationField EntityDefinitionQueryHelper::getTranslatedField($definition$real);
  131.                 $field $this->handleField($translationField);
  132.             } else {
  133.                 $field $this->handleField($real);
  134.             }
  135.             if (!$field) {
  136.                 continue;
  137.             }
  138.             $fieldCollection->add(new DefinitionField($definition$real));
  139.             if ($isTranslated && $definition->getTranslationDefinition()) {
  140.                 $translationDefinition $definition->getTranslationDefinition();
  141.                 $fieldCollection->add(new DefinitionField($translationDefinition$translationDefinition->getFields()->get($real->getPropertyName())));
  142.             }
  143.         }
  144.         return $fieldCollection;
  145.     }
  146.     private function handleField(Field $field): bool
  147.     {
  148.         switch (true) {
  149.             case $field instanceof StringField:
  150.             case $field instanceof NumberRangeField:
  151.             case $field instanceof TranslatedField:
  152.             case $field->is(PrimaryKey::class):
  153.                 return true;
  154.             default:
  155.                 return false;
  156.         }
  157.     }
  158.     private function getFields(
  159.         EntityDefinition $definition,
  160.         array $boostings,
  161.         RelevanceBluePrintCollection $relevanceBluePrintCollection
  162.     ): DefinitionFieldCollection {
  163.         $definitionFieldCollection = new DefinitionFieldCollection();
  164.         foreach ($relevanceBluePrintCollection as $relevanceEntity) {
  165.             $definition $this->definitionInstanceRegistry->getByEntityName($relevanceEntity->getEntityName());
  166.             /** @var Field $field */
  167.             foreach (self::getDefinitionFieldsOfAccessor($definition$relevanceEntity->getFieldName()) as $field) {
  168.                 $definitionFieldCollection->add($field);
  169.             }
  170.         }
  171.         foreach ($boostings as $boosting) {
  172.             $filters $boosting[BoostingQueryBuilder::FILTER];
  173.             /** @var BoostingEntity $boostingEntity */
  174.             $boostingEntity $boosting[BoostingQueryBuilder::BOOSTING];
  175.             if (empty($filters)) {
  176.                 continue;
  177.             }
  178.             if (!$boostingEntity->isActive() || !$boostingEntity->isValid()) {
  179.                 continue;
  180.             }
  181.             $this->addFieldsFilterToCollection($definition$definitionFieldCollection$filters);
  182.         }
  183.         return $definitionFieldCollection;
  184.     }
  185.     private function addFieldsFilterToCollection(EntityDefinition $definitionDefinitionFieldCollection $collection, array $filters): void
  186.     {
  187.         foreach ($filters as $key => $value) {
  188.             if (is_array($value)) {
  189.                 $this->addFieldsFilterToCollection($definition$collection$value);
  190.             }
  191.             if ($key === 'field') {
  192.                 foreach (self::getDefinitionFieldsOfAccessor($definition$key) as $field) {
  193.                     $collection->add($field);
  194.                 }
  195.             }
  196.         }
  197.     }
  198.     private function getSalesChannels(): EntityCollection
  199.     {
  200.         return $this->salesChannelRepository->search(new Criteria(), Context::createDefaultContext())->getEntities();
  201.     }
  202. }