vendor/shopware/core/System/SalesChannel/Entity/SalesChannelRepository.php line 130

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\System\SalesChannel\Entity;
  3. use Shopware\Core\Framework\DataAbstractionLayer\Entity;
  4. use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
  5. use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityAggregationResultLoadedEvent;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEventFactory;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Field\AssociationField;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Read\EntityReaderInterface;
  12. use Shopware\Core\Framework\DataAbstractionLayer\RepositorySearchDetector;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntityAggregatorInterface;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearcherInterface;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult;
  19. use Shopware\Core\Framework\Feature;
  20. use Shopware\Core\Framework\Struct\ArrayEntity;
  21. use Shopware\Core\System\SalesChannel\Event\SalesChannelProcessCriteriaEvent;
  22. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  23. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  24. /**
  25.  * @final tag:v6.5.0
  26.  */
  27. class SalesChannelRepository implements SalesChannelRepositoryInterface
  28. {
  29.     /**
  30.      * @var EntityDefinition
  31.      */
  32.     protected $definition;
  33.     /**
  34.      * @var EntityReaderInterface
  35.      */
  36.     protected $reader;
  37.     /**
  38.      * @var EntitySearcherInterface
  39.      */
  40.     protected $searcher;
  41.     /**
  42.      * @var EntityAggregatorInterface
  43.      */
  44.     protected $aggregator;
  45.     /**
  46.      * @var EventDispatcherInterface
  47.      */
  48.     protected $eventDispatcher;
  49.     private ?EntityLoadedEventFactory $eventFactory;
  50.     /**
  51.      * @internal
  52.      *
  53.      * @deprecated tag:v6.5.0 - $eventFactory parameter will be required
  54.      */
  55.     public function __construct(
  56.         EntityDefinition $definition,
  57.         EntityReaderInterface $reader,
  58.         EntitySearcherInterface $searcher,
  59.         EntityAggregatorInterface $aggregator,
  60.         EventDispatcherInterface $eventDispatcher,
  61.         ?EntityLoadedEventFactory $eventFactory
  62.     ) {
  63.         $this->definition $definition;
  64.         $this->reader $reader;
  65.         $this->searcher $searcher;
  66.         $this->aggregator $aggregator;
  67.         $this->eventDispatcher $eventDispatcher;
  68.         if ($eventFactory !== null) {
  69.             $this->eventFactory $eventFactory;
  70.         } else {
  71.             Feature::triggerDeprecationOrThrow(
  72.                 'v6.5.0.0',
  73.                 sprintf('SalesChannelRepository constructor for definition %s requires the event factory as required 6th parameter in v6.5.0.0'$definition->getEntityName())
  74.             );
  75.         }
  76.     }
  77.     /**
  78.      * @deprecated tag:v6.5.0 - Will be removed
  79.      */
  80.     public function setEntityLoadedEventFactory(EntityLoadedEventFactory $eventFactory): void
  81.     {
  82.         Feature::triggerDeprecationOrThrow(
  83.             'v6.5.0.0',
  84.             Feature::deprecatedMethodMessage(__CLASS____METHOD__'v6.5.0.0')
  85.         );
  86.         $this->eventFactory $eventFactory;
  87.     }
  88.     /**
  89.      * @throws InconsistentCriteriaIdsException
  90.      */
  91.     public function search(Criteria $criteriaSalesChannelContext $salesChannelContext): EntitySearchResult
  92.     {
  93.         $criteria = clone $criteria;
  94.         $this->processCriteria($criteria$salesChannelContext);
  95.         $aggregations null;
  96.         if ($criteria->getAggregations()) {
  97.             $aggregations $this->aggregate($criteria$salesChannelContext);
  98.         }
  99.         if (!RepositorySearchDetector::isSearchRequired($this->definition$criteria)) {
  100.             $entities $this->read($criteria$salesChannelContext);
  101.             return new EntitySearchResult($this->definition->getEntityName(), $entities->count(), $entities$aggregations$criteria$salesChannelContext->getContext());
  102.         }
  103.         $ids $this->doSearch($criteria$salesChannelContext);
  104.         if (empty($ids->getIds())) {
  105.             $collection $this->definition->getCollectionClass();
  106.             return new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), new $collection(), $aggregations$criteria$salesChannelContext->getContext());
  107.         }
  108.         $readCriteria $criteria->cloneForRead($ids->getIds());
  109.         $entities $this->read($readCriteria$salesChannelContext);
  110.         $search $ids->getData();
  111.         /** @var Entity $element */
  112.         foreach ($entities as $element) {
  113.             if (!\array_key_exists($element->getUniqueIdentifier(), $search)) {
  114.                 continue;
  115.             }
  116.             $data $search[$element->getUniqueIdentifier()];
  117.             unset($data['id']);
  118.             if (empty($data)) {
  119.                 continue;
  120.             }
  121.             $element->addExtension('search', new ArrayEntity($data));
  122.         }
  123.         $result = new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), $entities$aggregations$criteria$salesChannelContext->getContext());
  124.         $result->addState(...$ids->getStates());
  125.         $event = new EntitySearchResultLoadedEvent($this->definition$result);
  126.         $this->eventDispatcher->dispatch($event$event->getName());
  127.         $event = new SalesChannelEntitySearchResultLoadedEvent($this->definition$result$salesChannelContext);
  128.         $this->eventDispatcher->dispatch($event$event->getName());
  129.         return $result;
  130.     }
  131.     public function aggregate(Criteria $criteriaSalesChannelContext $salesChannelContext): AggregationResultCollection
  132.     {
  133.         $criteria = clone $criteria;
  134.         $this->processCriteria($criteria$salesChannelContext);
  135.         $result $this->aggregator->aggregate($this->definition$criteria$salesChannelContext->getContext());
  136.         $event = new EntityAggregationResultLoadedEvent($this->definition$result$salesChannelContext->getContext());
  137.         $this->eventDispatcher->dispatch($event$event->getName());
  138.         return $result;
  139.     }
  140.     public function searchIds(Criteria $criteriaSalesChannelContext $salesChannelContext): IdSearchResult
  141.     {
  142.         $criteria = clone $criteria;
  143.         $this->processCriteria($criteria$salesChannelContext);
  144.         return $this->doSearch($criteria$salesChannelContext);
  145.     }
  146.     private function read(Criteria $criteriaSalesChannelContext $salesChannelContext): EntityCollection
  147.     {
  148.         $criteria = clone $criteria;
  149.         $entities $this->reader->read($this->definition$criteria$salesChannelContext->getContext());
  150.         if ($this->eventFactory === null) {
  151.             throw new \RuntimeException('Event loaded factory was not injected');
  152.         }
  153.         if ($criteria->getFields() === []) {
  154.             $events $this->eventFactory->createForSalesChannel($entities->getElements(), $salesChannelContext);
  155.         } else {
  156.             $events $this->eventFactory->createPartialForSalesChannel($entities->getElements(), $salesChannelContext);
  157.         }
  158.         foreach ($events as $event) {
  159.             $this->eventDispatcher->dispatch($event);
  160.         }
  161.         return $entities;
  162.     }
  163.     private function doSearch(Criteria $criteriaSalesChannelContext $salesChannelContext): IdSearchResult
  164.     {
  165.         $result $this->searcher->search($this->definition$criteria$salesChannelContext->getContext());
  166.         $event = new SalesChannelEntityIdSearchResultLoadedEvent($this->definition$result$salesChannelContext);
  167.         $this->eventDispatcher->dispatch($event$event->getName());
  168.         return $result;
  169.     }
  170.     private function processCriteria(Criteria $topCriteriaSalesChannelContext $salesChannelContext): void
  171.     {
  172.         if (!$this->definition instanceof SalesChannelDefinitionInterface) {
  173.             return;
  174.         }
  175.         $queue = [
  176.             ['definition' => $this->definition'criteria' => $topCriteria],
  177.         ];
  178.         $maxCount 100;
  179.         $processed = [];
  180.         // process all associations breadth-first
  181.         while (!empty($queue) && --$maxCount 0) {
  182.             $cur array_shift($queue);
  183.             /** @var EntityDefinition $definition */
  184.             $definition $cur['definition'];
  185.             $criteria $cur['criteria'];
  186.             if (isset($processed[\get_class($definition)])) {
  187.                 continue;
  188.             }
  189.             if ($definition instanceof SalesChannelDefinitionInterface) {
  190.                 $definition->processCriteria($criteria$salesChannelContext);
  191.                 $eventName \sprintf('sales_channel.%s.process.criteria'$definition->getEntityName());
  192.                 $event = new SalesChannelProcessCriteriaEvent($criteria$salesChannelContext);
  193.                 $this->eventDispatcher->dispatch($event$eventName);
  194.             }
  195.             $processed[\get_class($definition)] = true;
  196.             foreach ($criteria->getAssociations() as $associationName => $associationCriteria) {
  197.                 // find definition
  198.                 $field $definition->getField($associationName);
  199.                 if (!$field instanceof AssociationField) {
  200.                     continue;
  201.                 }
  202.                 $referenceDefinition $field->getReferenceDefinition();
  203.                 $queue[] = ['definition' => $referenceDefinition'criteria' => $associationCriteria];
  204.             }
  205.         }
  206.     }
  207. }