vendor/shopware/core/Framework/DataAbstractionLayer/Dbal/EntitySearcher.php line 47

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\DataAbstractionLayer\Dbal;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Framework\Context;
  5. use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Field\AutoIncrementField;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Field\Field;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Field\ReferenceVersionField;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Field\StorageAware;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Field\VersionField;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearcherInterface;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult;
  15. use Shopware\Core\Framework\Feature;
  16. use Shopware\Core\Framework\Log\Package;
  17. use Shopware\Core\System\NumberRange\DataAbstractionLayer\NumberRangeField;
  18. /**
  19.  * Used for all search operations in the system.
  20.  * The dbal entity searcher only joins and select fields which defined in sorting, filter or query classes.
  21.  * Fields which are not necessary to determines which ids are affected are not fetched.
  22.  *
  23.  * @deprecated tag:v6.5.0 - reason:becomes-internal - Will be internal
  24.  */
  25. #[Package('core')]
  26. class EntitySearcher implements EntitySearcherInterface
  27. {
  28.     private Connection $connection;
  29.     private EntityDefinitionQueryHelper $queryHelper;
  30.     private CriteriaQueryBuilder $criteriaQueryBuilder;
  31.     public function __construct(
  32.         Connection $connection,
  33.         EntityDefinitionQueryHelper $queryHelper,
  34.         CriteriaQueryBuilder $criteriaQueryBuilder
  35.     ) {
  36.         $this->connection $connection;
  37.         $this->queryHelper $queryHelper;
  38.         $this->criteriaQueryBuilder $criteriaQueryBuilder;
  39.     }
  40.     public function search(EntityDefinition $definitionCriteria $criteriaContext $context): IdSearchResult
  41.     {
  42.         if ($criteria->getLimit() === 0) {
  43.             return new IdSearchResult(0, [], $criteria$context);
  44.         }
  45.         $table $definition->getEntityName();
  46.         $query = new QueryBuilder($this->connection);
  47.         $fields = [];
  48.         foreach ($definition->getFields() as $field) {
  49.             if (!$field instanceof StorageAware || $field instanceof ReferenceVersionField || $field instanceof VersionField) {
  50.                 continue;
  51.             }
  52.             if ($field instanceof NumberRangeField) {
  53.                 $fields[$field->getStorageName()] = $field;
  54.                 continue;
  55.             }
  56.             if ($field instanceof AutoIncrementField) {
  57.                 $fields[$field->getStorageName()] = $field;
  58.                 continue;
  59.             }
  60.             if ($field->is(PrimaryKey::class)) {
  61.                 $fields[$field->getStorageName()] = $field;
  62.             }
  63.         }
  64.         /** @var StorageAware $field */
  65.         foreach ($fields as $field) {
  66.             $query->addSelect(
  67.                 EntityDefinitionQueryHelper::escape($table) . '.' EntityDefinitionQueryHelper::escape($field->getStorageName())
  68.             );
  69.         }
  70.         $query $this->criteriaQueryBuilder->build($query$definition$criteria$context);
  71.         if (!empty($criteria->getIds())) {
  72.             $this->queryHelper->addIdCondition($criteria$definition$query);
  73.         }
  74.         $this->addGroupBy($definition$criteria$context$query$table);
  75.         //add pagination
  76.         if ($criteria->getOffset() !== null) {
  77.             $query->setFirstResult($criteria->getOffset());
  78.         }
  79.         if ($criteria->getLimit() !== null) {
  80.             $query->setMaxResults($criteria->getLimit());
  81.         }
  82.         $this->addTotalCountMode($criteria$query);
  83.         if ($criteria->getTitle()) {
  84.             $query->setTitle($criteria->getTitle() . '::search-ids');
  85.         }
  86.         //execute and fetch ids
  87.         $rows $query->executeQuery()->fetchAllAssociative();
  88.         $total $this->getTotalCount($criteria$query$rows);
  89.         if ($criteria->getTotalCountMode() === Criteria::TOTAL_COUNT_MODE_NEXT_PAGES) {
  90.             $rows = \array_slice($rows0$criteria->getLimit());
  91.         }
  92.         $converted = [];
  93.         foreach ($rows as $row) {
  94.             $pk = [];
  95.             $data = [];
  96.             foreach ($row as $storageName => $value) {
  97.                 $field $fields[$storageName] ?? null;
  98.                 if (!$field) {
  99.                     $data[$storageName] = $value;
  100.                     continue;
  101.                 }
  102.                 $value $field->getSerializer()->decode($field$value);
  103.                 // @deprecated tag:v6.5.0 - The keys of IdSearchResult should always be field's propertyName instead of storageName
  104.                 $data[$field->getPropertyName()] = $value;
  105.                 if (!Feature::isActive('v6.5.0.0')) {
  106.                     $data[$storageName] = $value;
  107.                 }
  108.                 if (!$field->is(PrimaryKey::class)) {
  109.                     continue;
  110.                 }
  111.                 // @deprecated tag:v6.5.0 - The keys of IdSearchResult should always be field's propertyName instead of storageName
  112.                 $pk[$field->getPropertyName()] = $value;
  113.                 if (!Feature::isActive('v6.5.0.0')) {
  114.                     $pk[$storageName] = $value;
  115.                 }
  116.             }
  117.             /**
  118.              * @deprecated tag:v6.5.0 - Will be change to $arrayKey = implode('-', $pk) due to no duplicated ids as mentioned above;
  119.              */
  120.             $arrayKey implode('-'array_unique(array_values($pk)));
  121.             if (\count($pk) === 1) {
  122.                 $pk array_shift($pk);
  123.             }
  124.             $converted[$arrayKey] = [
  125.                 'primaryKey' => $pk,
  126.                 'data' => $data,
  127.             ];
  128.         }
  129.         if ($criteria->useIdSorting()) {
  130.             $converted $this->sortByIdArray($criteria->getIds(), $converted);
  131.         }
  132.         return new IdSearchResult($total$converted$criteria$context);
  133.     }
  134.     private function addTotalCountMode(Criteria $criteriaQueryBuilder $query): void
  135.     {
  136.         if ($criteria->getTotalCountMode() !== Criteria::TOTAL_COUNT_MODE_NEXT_PAGES) {
  137.             return;
  138.         }
  139.         $query->setMaxResults($criteria->getLimit() * 1);
  140.     }
  141.     private function getTotalCount(Criteria $criteriaQueryBuilder $query, array $data): int
  142.     {
  143.         if ($criteria->getTotalCountMode() !== Criteria::TOTAL_COUNT_MODE_EXACT) {
  144.             return \count($data);
  145.         }
  146.         $query->resetQueryPart('orderBy');
  147.         $query->setMaxResults(null);
  148.         $query->setFirstResult(0);
  149.         $total = new QueryBuilder($query->getConnection());
  150.         $total->select(['COUNT(*)'])
  151.             ->from(sprintf('(%s) total'$query->getSQL()))
  152.             ->setParameters($query->getParameters(), $query->getParameterTypes());
  153.         return (int) $total->executeQuery()->fetchOne();
  154.     }
  155.     private function addGroupBy(EntityDefinition $definitionCriteria $criteriaContext $contextQueryBuilder $querystring $table): void
  156.     {
  157.         if ($criteria->getGroupFields()) {
  158.             foreach ($criteria->getGroupFields() as $grouping) {
  159.                 $accessor $this->queryHelper->getFieldAccessor($grouping->getField(), $definition$definition->getEntityName(), $context);
  160.                 $query->addGroupBy($accessor);
  161.             }
  162.             return;
  163.         }
  164.         if ($query->hasState(EntityDefinitionQueryHelper::HAS_TO_MANY_JOIN)) {
  165.             $query->addGroupBy(
  166.                 EntityDefinitionQueryHelper::escape($table) . '.' EntityDefinitionQueryHelper::escape('id')
  167.             );
  168.         }
  169.     }
  170.     private function sortByIdArray(array $ids, array $data): array
  171.     {
  172.         $sorted = [];
  173.         foreach ($ids as $id) {
  174.             if (\is_array($id)) {
  175.                 $id implode('-'$id);
  176.             }
  177.             if (\array_key_exists($id$data)) {
  178.                 $sorted[$id] = $data[$id];
  179.             }
  180.         }
  181.         return $sorted;
  182.     }
  183. }