vendor/store.shopware.com/swagenterprisesearchplatform/src/Indexing/FieldProvider.php line 132

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