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

  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\Log\Package;
  21. use Shopware\Core\Framework\Struct\ArrayEntity;
  22. use Shopware\Core\Framework\Uuid\Exception\InvalidUuidException;
  23. use Shopware\Core\Framework\Uuid\Uuid;
  24. use Shopware\Core\Profiling\Profiler;
  25. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  26. /**
  27.  * @final
  28.  */
  29. #[Package('core')]
  30. class EntityRepository
  31. {
  32.     /**
  33.      * @internal
  34.      */
  35.     public function __construct(
  36.         private readonly EntityDefinition $definition,
  37.         private readonly EntityReaderInterface $reader,
  38.         private readonly VersionManager $versionManager,
  39.         private readonly EntitySearcherInterface $searcher,
  40.         private readonly EntityAggregatorInterface $aggregator,
  41.         private readonly EventDispatcherInterface $eventDispatcher,
  42.         private readonly EntityLoadedEventFactory $eventFactory
  43.     ) {
  44.     }
  45.     public function getDefinition(): EntityDefinition
  46.     {
  47.         return $this->definition;
  48.     }
  49.     public function search(Criteria $criteriaContext $context): EntitySearchResult
  50.     {
  51.         if (!$criteria->getTitle()) {
  52.             return $this->_search($criteria$context);
  53.         }
  54.         return Profiler::trace($criteria->getTitle(), fn () => $this->_search($criteria$context), 'repository');
  55.     }
  56.     public function aggregate(Criteria $criteriaContext $context): AggregationResultCollection
  57.     {
  58.         $criteria = clone $criteria;
  59.         $result $this->aggregator->aggregate($this->definition$criteria$context);
  60.         $event = new EntityAggregationResultLoadedEvent($this->definition$result$context);
  61.         $this->eventDispatcher->dispatch($event$event->getName());
  62.         return $result;
  63.     }
  64.     public function searchIds(Criteria $criteriaContext $context): IdSearchResult
  65.     {
  66.         $criteria = clone $criteria;
  67.         $this->eventDispatcher->dispatch(new EntitySearchedEvent($criteria$this->definition$context));
  68.         $result $this->searcher->search($this->definition$criteria$context);
  69.         $event = new EntityIdSearchResultLoadedEvent($this->definition$result);
  70.         $this->eventDispatcher->dispatch($event$event->getName());
  71.         return $result;
  72.     }
  73.     /**
  74.      * @param array<array<string, mixed|null>> $data
  75.      */
  76.     public function update(array $dataContext $context): EntityWrittenContainerEvent
  77.     {
  78.         ReplicaConnection::ensurePrimary();
  79.         $affected $this->versionManager->update($this->definition$dataWriteContext::createFromContext($context));
  80.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, []);
  81.         $this->eventDispatcher->dispatch($event);
  82.         return $event;
  83.     }
  84.     /**
  85.      * @param array<array<string, mixed|null>> $data
  86.      */
  87.     public function upsert(array $dataContext $context): EntityWrittenContainerEvent
  88.     {
  89.         ReplicaConnection::ensurePrimary();
  90.         $affected $this->versionManager->upsert($this->definition$dataWriteContext::createFromContext($context));
  91.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, []);
  92.         $this->eventDispatcher->dispatch($event);
  93.         return $event;
  94.     }
  95.     /**
  96.      * @param array<array<string, mixed|null>> $data
  97.      */
  98.     public function create(array $dataContext $context): EntityWrittenContainerEvent
  99.     {
  100.         ReplicaConnection::ensurePrimary();
  101.         $affected $this->versionManager->insert($this->definition$dataWriteContext::createFromContext($context));
  102.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, []);
  103.         $this->eventDispatcher->dispatch($event);
  104.         return $event;
  105.     }
  106.     /**
  107.      * @param array<array<string, mixed|null>> $ids
  108.      */
  109.     public function delete(array $idsContext $context): EntityWrittenContainerEvent
  110.     {
  111.         ReplicaConnection::ensurePrimary();
  112.         $affected $this->versionManager->delete($this->definition$idsWriteContext::createFromContext($context));
  113.         $event EntityWrittenContainerEvent::createWithDeletedEvents($affected->getDeleted(), $context$affected->getNotFound());
  114.         if ($affected->getWritten()) {
  115.             $updates EntityWrittenContainerEvent::createWithWrittenEvents($affected->getWritten(), $context, []);
  116.             if ($updates->getEvents() !== null) {
  117.                 $event->addEvent(...$updates->getEvents());
  118.             }
  119.         }
  120.         $this->eventDispatcher->dispatch($event);
  121.         return $event;
  122.     }
  123.     public function createVersion(string $idContext $context, ?string $name null, ?string $versionId null): string
  124.     {
  125.         ReplicaConnection::ensurePrimary();
  126.         if (!$this->definition->isVersionAware()) {
  127.             throw new \RuntimeException(sprintf('Entity %s is not version aware'$this->definition->getEntityName()));
  128.         }
  129.         return $this->versionManager->createVersion($this->definition$idWriteContext::createFromContext($context), $name$versionId);
  130.     }
  131.     public function merge(string $versionIdContext $context): void
  132.     {
  133.         ReplicaConnection::ensurePrimary();
  134.         if (!$this->definition->isVersionAware()) {
  135.             throw new \RuntimeException(sprintf('Entity %s is not version aware'$this->definition->getEntityName()));
  136.         }
  137.         $this->versionManager->merge($versionIdWriteContext::createFromContext($context));
  138.     }
  139.     public function clone(string $idContext $context, ?string $newId null, ?CloneBehavior $behavior null): EntityWrittenContainerEvent
  140.     {
  141.         ReplicaConnection::ensurePrimary();
  142.         $newId ??= Uuid::randomHex();
  143.         if (!Uuid::isValid($newId)) {
  144.             throw new InvalidUuidException($newId);
  145.         }
  146.         $affected $this->versionManager->clone(
  147.             $this->definition,
  148.             $id,
  149.             $newId,
  150.             $context->getVersionId(),
  151.             WriteContext::createFromContext($context),
  152.             $behavior ?? new CloneBehavior()
  153.         );
  154.         $event EntityWrittenContainerEvent::createWithWrittenEvents($affected$context, [], true);
  155.         $this->eventDispatcher->dispatch($event);
  156.         return $event;
  157.     }
  158.     /**
  159.      * @return EntityCollection<Entity>
  160.      */
  161.     private function read(Criteria $criteriaContext $context): EntityCollection
  162.     {
  163.         $criteria = clone $criteria;
  164.         $entities $this->reader->read($this->definition$criteria$context);
  165.         if ($criteria->getFields() === []) {
  166.             $event $this->eventFactory->create($entities->getElements(), $context);
  167.         } else {
  168.             $event $this->eventFactory->createPartial($entities->getElements(), $context);
  169.         }
  170.         $this->eventDispatcher->dispatch($event);
  171.         return $entities;
  172.     }
  173.     private function _search(Criteria $criteriaContext $context): EntitySearchResult
  174.     {
  175.         $criteria = clone $criteria;
  176.         $aggregations null;
  177.         if ($criteria->getAggregations()) {
  178.             $aggregations $this->aggregate($criteria$context);
  179.         }
  180.         if (!RepositorySearchDetector::isSearchRequired($this->definition$criteria)) {
  181.             $this->eventDispatcher->dispatch(
  182.                 new EntitySearchedEvent($criteria$this->definition$context)
  183.             );
  184.             $entities $this->read($criteria$context);
  185.             return new EntitySearchResult($this->definition->getEntityName(), $entities->count(), $entities$aggregations$criteria$context);
  186.         }
  187.         $ids $this->searchIds($criteria$context);
  188.         if (empty($ids->getIds())) {
  189.             /** @var EntityCollection<Entity> $collection */
  190.             $collection $this->definition->getCollectionClass();
  191.             return new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), new $collection(), $aggregations$criteria$context);
  192.         }
  193.         $readCriteria $criteria->cloneForRead($ids->getIds());
  194.         $entities $this->read($readCriteria$context);
  195.         $search $ids->getData();
  196.         /** @var Entity $element */
  197.         foreach ($entities as $element) {
  198.             if (!\array_key_exists($element->getUniqueIdentifier(), $search)) {
  199.                 continue;
  200.             }
  201.             $data $search[$element->getUniqueIdentifier()];
  202.             unset($data['id']);
  203.             if (empty($data)) {
  204.                 continue;
  205.             }
  206.             $element->addExtension('search', new ArrayEntity($data));
  207.         }
  208.         $result = new EntitySearchResult($this->definition->getEntityName(), $ids->getTotal(), $entities$aggregations$criteria$context);
  209.         $result->addState(...$ids->getStates());
  210.         $event = new EntitySearchResultLoadedEvent($this->definition$result);
  211.         $this->eventDispatcher->dispatch($event$event->getName());
  212.         return $result;
  213.     }
  214. }