vendor/shopware/core/Framework/DataAbstractionLayer/EntityRepository.php line 111

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\DataAbstractionLayer;
  3. use Shopware\Core\Framework\Adapter\Database\ReplicaConnection;
  4. use Shopware\Core\Framework\Context;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityAggregationResultLoadedEvent;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityIdSearchResultLoadedEvent;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEventFactory;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchedEvent;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Read\EntityReaderInterface;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntityAggregatorInterface;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearcherInterface;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Write\CloneBehavior;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Write\WriteContext;
  20. use Shopware\Core\Framework\Feature;
  21. use Shopware\Core\Framework\Log\Package;
  22. use Shopware\Core\Framework\Struct\ArrayEntity;
  23. use Shopware\Core\Framework\Uuid\Exception\InvalidUuidException;
  24. use Shopware\Core\Framework\Uuid\Uuid;
  25. use Shopware\Core\Profiling\Profiler;
  26. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  27. /**
  28.  * @final tag:v6.5.0
  29.  */
  30. #[Package('core')]
  31. class EntityRepository implements EntityRepositoryInterface
  32. {
  33.     private EntityReaderInterface $reader;
  34.     private EntitySearcherInterface $searcher;
  35.     private EntityAggregatorInterface $aggregator;
  36.     private EventDispatcherInterface $eventDispatcher;
  37.     private VersionManager $versionManager;
  38.     private EntityDefinition $definition;
  39.     private ?EntityLoadedEventFactory $eventFactory null;
  40.     /**
  41.      * @internal
  42.      *
  43.      * @deprecated tag:v6.5.0 - parameter $eventFactory will be required
  44.      */
  45.     public function __construct(
  46.         EntityDefinition $definition,
  47.         EntityReaderInterface $reader,
  48.         VersionManager $versionManager,
  49.         EntitySearcherInterface $searcher,
  50.         EntityAggregatorInterface $aggregator,
  51.         EventDispatcherInterface $eventDispatcher,
  52.         ?EntityLoadedEventFactory $eventFactory null
  53.     ) {
  54.         $this->reader $reader;
  55.         $this->searcher $searcher;
  56.         $this->aggregator $aggregator;
  57.         $this->eventDispatcher $eventDispatcher;
  58.         $this->versionManager $versionManager;
  59.         $this->definition $definition;
  60.         if ($eventFactory !== null) {
  61.             $this->eventFactory $eventFactory;
  62.         } else {
  63.             Feature::triggerDeprecationOrThrow(
  64.                 'v6.5.0.0',
  65.                 sprintf('EntityRepository constructor for definition %s requires the event factory as required 7th parameter in v6.5.0.0'$definition->getEntityName())
  66.             );
  67.         }
  68.     }
  69.     /**
  70.      * @deprecated tag:v6.5.0 - Will be removed, inject entity loaded event factory in __construct
  71.      */
  72.     public function setEntityLoadedEventFactory(EntityLoadedEventFactory $eventFactory): void
  73.     {
  74.         if (isset($this->eventFactory)) {
  75.             return;
  76.         }
  77.         Feature::triggerDeprecationOrThrow(
  78.             'v6.5.0.0',
  79.             sprintf('Repository for definition %s requires the event factory as __construct parameter'$this->definition->getEntityName())
  80.         );
  81.         $this->eventFactory $eventFactory;
  82.     }
  83.     public function getDefinition(): EntityDefinition
  84.     {
  85.         return $this->definition;
  86.     }
  87.     public function search(Criteria $criteriaContext $context): EntitySearchResult
  88.     {
  89.         if (!$criteria->getTitle()) {
  90.             return $this->_search($criteria$context);
  91.         }
  92.         return Profiler::trace($criteria->getTitle(), function () use ($criteria$context) {
  93.             return $this->_search($criteria$context);
  94.         }, 'repository');
  95.     }
  96.     public function aggregate(Criteria $criteriaContext $context): AggregationResultCollection
  97.     {
  98.         $criteria = clone $criteria;
  99.         $result $this->aggregator->aggregate($this->definition$criteria$context);
  100.         $event = new EntityAggregationResultLoadedEvent($this->definition$result$context);
  101.         $this->eventDispatcher->dispatch($event$event->getName());
  102.         return $result;
  103.     }
  104.     public function searchIds(Criteria $criteriaContext $context): IdSearchResult
  105.     {
  106.         $criteria = clone $criteria;
  107.         $this->eventDispatcher->dispatch(new EntitySearchedEvent($criteria$this->definition$context));
  108.         $result $this->searcher->search($this->definition$criteria$context);
  109.         $event = new EntityIdSearchResultLoadedEvent($this->definition$result);
  110.         $this->eventDispatcher->dispatch($event$event->getName());
  111.         return $result;
  112.     }
  113.     /**
  114.      * @param array<array<string, mixed|null>> $data
  115.      */
  116.     public function update(array $dataContext $context): EntityWrittenContainerEvent
  117.     {
  118.         ReplicaConnection::ensurePrimary();
  119.         $affected $this->versionManager->update($this->definition$dataWriteContext::createFromContext($context));
  120.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, []);
  121.         $this->eventDispatcher->dispatch($event);
  122.         return $event;
  123.     }
  124.     /**
  125.      * @param array<array<string, mixed|null>> $data
  126.      */
  127.     public function upsert(array $dataContext $context): EntityWrittenContainerEvent
  128.     {
  129.         ReplicaConnection::ensurePrimary();
  130.         $affected $this->versionManager->upsert($this->definition$dataWriteContext::createFromContext($context));
  131.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, []);
  132.         $this->eventDispatcher->dispatch($event);
  133.         return $event;
  134.     }
  135.     /**
  136.      * @param array<array<string, mixed|null>> $data
  137.      */
  138.     public function create(array $dataContext $context): EntityWrittenContainerEvent
  139.     {
  140.         ReplicaConnection::ensurePrimary();
  141.         $affected $this->versionManager->insert($this->definition$dataWriteContext::createFromContext($context));
  142.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, []);
  143.         $this->eventDispatcher->dispatch($event);
  144.         return $event;
  145.     }
  146.     /**
  147.      * @param array<array<string, mixed|null>> $ids
  148.      */
  149.     public function delete(array $idsContext $context): EntityWrittenContainerEvent
  150.     {
  151.         ReplicaConnection::ensurePrimary();
  152.         $affected $this->versionManager->delete($this->definition$idsWriteContext::createFromContext($context));
  153.         $event EntityWrittenContainerEvent::createWithDeletedEvents($affected->getDeleted(), $context$affected->getNotFound());
  154.         if ($affected->getWritten()) {
  155.             $updates EntityWrittenContainerEvent::createWithWrittenEvents($affected->getWritten(), $context, []);
  156.             if ($updates->getEvents() !== null) {
  157.                 $event->addEvent(...$updates->getEvents());
  158.             }
  159.         }
  160.         $this->eventDispatcher->dispatch($event);
  161.         return $event;
  162.     }
  163.     public function createVersion(string $idContext $context, ?string $name null, ?string $versionId null): string
  164.     {
  165.         ReplicaConnection::ensurePrimary();
  166.         if (!$this->definition->isVersionAware()) {
  167.             throw new \RuntimeException(sprintf('Entity %s is not version aware'$this->definition->getEntityName()));
  168.         }
  169.         return $this->versionManager->createVersion($this->definition$idWriteContext::createFromContext($context), $name$versionId);
  170.     }
  171.     public function merge(string $versionIdContext $context): void
  172.     {
  173.         ReplicaConnection::ensurePrimary();
  174.         if (!$this->definition->isVersionAware()) {
  175.             throw new \RuntimeException(sprintf('Entity %s is not version aware'$this->definition->getEntityName()));
  176.         }
  177.         $this->versionManager->merge($versionIdWriteContext::createFromContext($context));
  178.     }
  179.     public function clone(string $idContext $context, ?string $newId null, ?CloneBehavior $behavior null): EntityWrittenContainerEvent
  180.     {
  181.         ReplicaConnection::ensurePrimary();
  182.         $newId $newId ?? Uuid::randomHex();
  183.         if (!Uuid::isValid($newId)) {
  184.             throw new InvalidUuidException($newId);
  185.         }
  186.         $affected $this->versionManager->clone(
  187.             $this->definition,
  188.             $id,
  189.             $newId,
  190.             $context->getVersionId(),
  191.             WriteContext::createFromContext($context),
  192.             $behavior ?? new CloneBehavior()
  193.         );
  194.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, [], true);
  195.         $this->eventDispatcher->dispatch($event);
  196.         return $event;
  197.     }
  198.     /**
  199.      * @return EntityCollection<Entity>
  200.      */
  201.     private function read(Criteria $criteriaContext $context): EntityCollection
  202.     {
  203.         $criteria = clone $criteria;
  204.         $entities $this->reader->read($this->definition$criteria$context);
  205.         if ($this->eventFactory === null) {
  206.             throw new \RuntimeException('Event loaded factory was not injected');
  207.         }
  208.         if ($criteria->getFields() === []) {
  209.             $event $this->eventFactory->create($entities->getElements(), $context);
  210.         } else {
  211.             $event $this->eventFactory->createPartial($entities->getElements(), $context);
  212.         }
  213.         $this->eventDispatcher->dispatch($event);
  214.         return $entities;
  215.     }
  216.     private function _search(Criteria $criteriaContext $context): EntitySearchResult
  217.     {
  218.         $criteria = clone $criteria;
  219.         $aggregations null;
  220.         if ($criteria->getAggregations()) {
  221.             $aggregations $this->aggregate($criteria$context);
  222.         }
  223.         if (!RepositorySearchDetector::isSearchRequired($this->definition$criteria)) {
  224.             $this->eventDispatcher->dispatch(
  225.                 new EntitySearchedEvent($criteria$this->definition$context)
  226.             );
  227.             $entities $this->read($criteria$context);
  228.             return new EntitySearchResult($this->definition->getEntityName(), $entities->count(), $entities$aggregations$criteria$context);
  229.         }
  230.         $ids $this->searchIds($criteria$context);
  231.         if (empty($ids->getIds())) {
  232.             /** @var EntityCollection<Entity> $collection */
  233.             $collection $this->definition->getCollectionClass();
  234.             return new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), new $collection(), $aggregations$criteria$context);
  235.         }
  236.         $readCriteria $criteria->cloneForRead($ids->getIds());
  237.         $entities $this->read($readCriteria$context);
  238.         $search $ids->getData();
  239.         /** @var Entity $element */
  240.         foreach ($entities as $element) {
  241.             if (!\array_key_exists($element->getUniqueIdentifier(), $search)) {
  242.                 continue;
  243.             }
  244.             $data $search[$element->getUniqueIdentifier()];
  245.             unset($data['id']);
  246.             if (empty($data)) {
  247.                 continue;
  248.             }
  249.             $element->addExtension('search', new ArrayEntity($data));
  250.         }
  251.         $result = new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), $entities$aggregations$criteria$context);
  252.         $result->addState(...$ids->getStates());
  253.         $event = new EntitySearchResultLoadedEvent($this->definition$result);
  254.         $this->eventDispatcher->dispatch($event$event->getName());
  255.         return $result;
  256.     }
  257. }