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

  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\Log\Package;
  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
  26.  */
  27. #[Package('sales-channel')]
  28. class SalesChannelRepository
  29. {
  30.     /**
  31.      * @internal
  32.      */
  33.     public function __construct(
  34.         private readonly EntityDefinition $definition,
  35.         private readonly EntityReaderInterface $reader,
  36.         private readonly EntitySearcherInterface $searcher,
  37.         private readonly EntityAggregatorInterface $aggregator,
  38.         private readonly EventDispatcherInterface $eventDispatcher,
  39.         private readonly EntityLoadedEventFactory $eventFactory
  40.     ) {
  41.     }
  42.     /**
  43.      * @throws InconsistentCriteriaIdsException
  44.      */
  45.     public function search(Criteria $criteriaSalesChannelContext $salesChannelContext): EntitySearchResult
  46.     {
  47.         $criteria = clone $criteria;
  48.         $this->processCriteria($criteria$salesChannelContext);
  49.         $aggregations null;
  50.         if ($criteria->getAggregations()) {
  51.             $aggregations $this->aggregate($criteria$salesChannelContext);
  52.         }
  53.         if (!RepositorySearchDetector::isSearchRequired($this->definition$criteria)) {
  54.             $entities $this->read($criteria$salesChannelContext);
  55.             return new EntitySearchResult($this->definition->getEntityName(), $entities->count(), $entities$aggregations$criteria$salesChannelContext->getContext());
  56.         }
  57.         $ids $this->doSearch($criteria$salesChannelContext);
  58.         if (empty($ids->getIds())) {
  59.             /** @var EntityCollection<Entity> $collection */
  60.             $collection $this->definition->getCollectionClass();
  61.             return new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), new $collection(), $aggregations$criteria$salesChannelContext->getContext());
  62.         }
  63.         $readCriteria $criteria->cloneForRead($ids->getIds());
  64.         $entities $this->read($readCriteria$salesChannelContext);
  65.         $search $ids->getData();
  66.         /** @var Entity $element */
  67.         foreach ($entities as $element) {
  68.             if (!\array_key_exists($element->getUniqueIdentifier(), $search)) {
  69.                 continue;
  70.             }
  71.             $data $search[$element->getUniqueIdentifier()];
  72.             unset($data['id']);
  73.             if (empty($data)) {
  74.                 continue;
  75.             }
  76.             $element->addExtension('search', new ArrayEntity($data));
  77.         }
  78.         $result = new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), $entities$aggregations$criteria$salesChannelContext->getContext());
  79.         $result->addState(...$ids->getStates());
  80.         $event = new EntitySearchResultLoadedEvent($this->definition$result);
  81.         $this->eventDispatcher->dispatch($event$event->getName());
  82.         $event = new SalesChannelEntitySearchResultLoadedEvent($this->definition$result$salesChannelContext);
  83.         $this->eventDispatcher->dispatch($event$event->getName());
  84.         return $result;
  85.     }
  86.     public function aggregate(Criteria $criteriaSalesChannelContext $salesChannelContext): AggregationResultCollection
  87.     {
  88.         $criteria = clone $criteria;
  89.         $this->processCriteria($criteria$salesChannelContext);
  90.         $result $this->aggregator->aggregate($this->definition$criteria$salesChannelContext->getContext());
  91.         $event = new EntityAggregationResultLoadedEvent($this->definition$result$salesChannelContext->getContext());
  92.         $this->eventDispatcher->dispatch($event$event->getName());
  93.         return $result;
  94.     }
  95.     public function searchIds(Criteria $criteriaSalesChannelContext $salesChannelContext): IdSearchResult
  96.     {
  97.         $criteria = clone $criteria;
  98.         $this->processCriteria($criteria$salesChannelContext);
  99.         return $this->doSearch($criteria$salesChannelContext);
  100.     }
  101.     /**
  102.      * @return EntityCollection<Entity>
  103.      */
  104.     private function read(Criteria $criteriaSalesChannelContext $salesChannelContext): EntityCollection
  105.     {
  106.         $criteria = clone $criteria;
  107.         $entities $this->reader->read($this->definition$criteria$salesChannelContext->getContext());
  108.         if ($criteria->getFields() === []) {
  109.             $events $this->eventFactory->createForSalesChannel($entities->getElements(), $salesChannelContext);
  110.         } else {
  111.             $events $this->eventFactory->createPartialForSalesChannel($entities->getElements(), $salesChannelContext);
  112.         }
  113.         foreach ($events as $event) {
  114.             $this->eventDispatcher->dispatch($event);
  115.         }
  116.         return $entities;
  117.     }
  118.     private function doSearch(Criteria $criteriaSalesChannelContext $salesChannelContext): IdSearchResult
  119.     {
  120.         $result $this->searcher->search($this->definition$criteria$salesChannelContext->getContext());
  121.         $event = new SalesChannelEntityIdSearchResultLoadedEvent($this->definition$result$salesChannelContext);
  122.         $this->eventDispatcher->dispatch($event$event->getName());
  123.         return $result;
  124.     }
  125.     private function processCriteria(Criteria $topCriteriaSalesChannelContext $salesChannelContext): void
  126.     {
  127.         if (!$this->definition instanceof SalesChannelDefinitionInterface) {
  128.             return;
  129.         }
  130.         $queue = [
  131.             ['definition' => $this->definition'criteria' => $topCriteria],
  132.         ];
  133.         $maxCount 100;
  134.         $processed = [];
  135.         // process all associations breadth-first
  136.         while (!empty($queue) && --$maxCount 0) {
  137.             $cur array_shift($queue);
  138.             /** @var EntityDefinition $definition */
  139.             $definition $cur['definition'];
  140.             $criteria $cur['criteria'];
  141.             if (isset($processed[$definition::class])) {
  142.                 continue;
  143.             }
  144.             if ($definition instanceof SalesChannelDefinitionInterface) {
  145.                 $definition->processCriteria($criteria$salesChannelContext);
  146.                 $eventName \sprintf('sales_channel.%s.process.criteria'$definition->getEntityName());
  147.                 $event = new SalesChannelProcessCriteriaEvent($criteria$salesChannelContext);
  148.                 $this->eventDispatcher->dispatch($event$eventName);
  149.             }
  150.             $processed[$definition::class] = true;
  151.             foreach ($criteria->getAssociations() as $associationName => $associationCriteria) {
  152.                 // find definition
  153.                 $field $definition->getField($associationName);
  154.                 if (!$field instanceof AssociationField) {
  155.                     continue;
  156.                 }
  157.                 $referenceDefinition $field->getReferenceDefinition();
  158.                 $queue[] = ['definition' => $referenceDefinition'criteria' => $associationCriteria];
  159.             }
  160.         }
  161.     }
  162. }