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

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