vendor/shopware/core/Framework/DataAbstractionLayer/Search/Criteria.php line 126

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\DataAbstractionLayer\Search;
  3. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  4. use Shopware\Core\Framework\DataAbstractionLayer\FieldSerializer\JsonFieldSerializer;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Aggregation;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\Filter;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\Grouping\FieldGrouping;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Parser\AggregationParser;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Query\ScoreQuery;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  12. use Shopware\Core\Framework\Feature;
  13. use Shopware\Core\Framework\Log\Package;
  14. use Shopware\Core\Framework\Struct\StateAwareTrait;
  15. use Shopware\Core\Framework\Struct\Struct;
  16. /**
  17.  * @final tag:v6.5.0
  18.  */
  19. #[Package('core')]
  20. class Criteria extends Struct implements \Stringable
  21. {
  22.     use StateAwareTrait;
  23.     public const STATE_ELASTICSEARCH_AWARE 'elasticsearchAware';
  24.     /**
  25.      * no total count will be selected. Should be used if no pagination required (fastest)
  26.      */
  27.     public const TOTAL_COUNT_MODE_NONE 0;
  28.     /**
  29.      * exact total count will be selected. Should be used if an exact pagination is required (slow)
  30.      */
  31.     public const TOTAL_COUNT_MODE_EXACT 1;
  32.     /**
  33.      * fetches limit * 5 + 1. Should be used if pagination can work with "next page exists" (fast)
  34.      */
  35.     public const TOTAL_COUNT_MODE_NEXT_PAGES 2;
  36.     /**
  37.      * @var FieldSorting[]
  38.      */
  39.     protected $sorting = [];
  40.     /**
  41.      * @var Filter[]
  42.      */
  43.     protected $filters = [];
  44.     /**
  45.      * @var Filter[]
  46.      */
  47.     protected $postFilters = [];
  48.     /**
  49.      * @var Aggregation[]
  50.      */
  51.     protected $aggregations = [];
  52.     /**
  53.      * @var ScoreQuery[]
  54.      */
  55.     protected $queries = [];
  56.     /**
  57.      * @var FieldGrouping[]
  58.      */
  59.     protected $groupFields = [];
  60.     /**
  61.      * @var int|null
  62.      */
  63.     protected $offset;
  64.     /**
  65.      * @var int|null
  66.      */
  67.     protected $limit;
  68.     /**
  69.      * @var int
  70.      */
  71.     protected $totalCountMode self::TOTAL_COUNT_MODE_NONE;
  72.     /**
  73.      * @var Criteria[]
  74.      */
  75.     protected $associations = [];
  76.     /**
  77.      * @var array<string>|array<int, array<string>>
  78.      */
  79.     protected $ids = [];
  80.     /**
  81.      * @var bool
  82.      */
  83.     protected $inherited false;
  84.     /**
  85.      * @var string|null
  86.      */
  87.     protected $term;
  88.     /**
  89.      * @var array<string, array<string, string>>|null
  90.      */
  91.     protected $includes;
  92.     /**
  93.      * @var string|null
  94.      */
  95.     protected $title;
  96.     /**
  97.      * @var string[]
  98.      */
  99.     protected array $fields = [];
  100.     /**
  101.      * @param array<string|array<string>>|null $ids
  102.      */
  103.     public function __construct(?array $ids null)
  104.     {
  105.         if ($ids === null) {
  106.             return;
  107.         }
  108.         $ids array_filter($ids);
  109.         if (empty($ids)) {
  110.             Feature::triggerDeprecationOrThrow(
  111.                 'v6.5.0.0',
  112.                 'The `Criteria()` constructor does not support passing an empty array of ids from v6.5.0.0 onwards'
  113.             );
  114.             if (Feature::isActive('FEATURE_NEXT_16710')) {
  115.                 throw new \RuntimeException('Empty ids provided in criteria');
  116.             }
  117.         }
  118.         $this->ids $ids;
  119.     }
  120.     public function __toString(): string
  121.     {
  122.         $parsed = (new CriteriaArrayConverter(new AggregationParser()))->convert($this);
  123.         return JsonFieldSerializer::encodeJson($parsed);
  124.     }
  125.     /**
  126.      * @return array<string>|array<int, array<string>>
  127.      */
  128.     public function getIds(): array
  129.     {
  130.         return $this->ids;
  131.     }
  132.     public function getOffset(): ?int
  133.     {
  134.         return $this->offset;
  135.     }
  136.     public function getLimit(): ?int
  137.     {
  138.         return $this->limit;
  139.     }
  140.     public function getTotalCountMode(): int
  141.     {
  142.         return $this->totalCountMode;
  143.     }
  144.     /**
  145.      * @return FieldSorting[]
  146.      */
  147.     public function getSorting(): array
  148.     {
  149.         return $this->sorting;
  150.     }
  151.     /**
  152.      * @return Aggregation[]
  153.      */
  154.     public function getAggregations(): array
  155.     {
  156.         return $this->aggregations;
  157.     }
  158.     public function getAggregation(string $name): ?Aggregation
  159.     {
  160.         return $this->aggregations[$name] ?? null;
  161.     }
  162.     /**
  163.      * @return Filter[]
  164.      */
  165.     public function getFilters(): array
  166.     {
  167.         return $this->filters;
  168.     }
  169.     /**
  170.      * @param string $field
  171.      */
  172.     public function hasEqualsFilter($field): bool
  173.     {
  174.         return \count(array_filter($this->filters, static function (Filter $filter) use ($field) {
  175.             /* EqualsFilter $filter */
  176.             return $filter instanceof EqualsFilter && $filter->getField() === $field;
  177.         })) > 0;
  178.     }
  179.     /**
  180.      * @return Filter[]
  181.      */
  182.     public function getPostFilters(): array
  183.     {
  184.         return $this->postFilters;
  185.     }
  186.     /**
  187.      * @return ScoreQuery[]
  188.      */
  189.     public function getQueries(): array
  190.     {
  191.         return $this->queries;
  192.     }
  193.     /**
  194.      * @return Criteria[]
  195.      */
  196.     public function getAssociations(): array
  197.     {
  198.         return $this->associations;
  199.     }
  200.     /**
  201.      * Returns the criteria for the provided association path. Also supports nested paths
  202.      *
  203.      * e.g `$criteria->getAssociation('categories.media.thumbnails')`
  204.      *
  205.      * @throws InconsistentCriteriaIdsException
  206.      */
  207.     public function getAssociation(string $path): Criteria
  208.     {
  209.         $parts explode('.'$path);
  210.         $criteria $this;
  211.         foreach ($parts as $part) {
  212.             if ($part === 'extensions') {
  213.                 continue;
  214.             }
  215.             if (!$criteria->hasAssociation($part)) {
  216.                 $criteria->associations[$part] = new Criteria();
  217.             }
  218.             $criteria $criteria->associations[$part];
  219.         }
  220.         return $criteria;
  221.     }
  222.     public function addFilter(Filter ...$queries): self
  223.     {
  224.         foreach ($queries as $query) {
  225.             $this->filters[] = $query;
  226.         }
  227.         return $this;
  228.     }
  229.     public function setFilter(string $keyFilter $filter): self
  230.     {
  231.         $this->filters[$key] = $filter;
  232.         return $this;
  233.     }
  234.     public function addSorting(FieldSorting ...$sorting): self
  235.     {
  236.         foreach ($sorting as $sort) {
  237.             $this->sorting[] = $sort;
  238.         }
  239.         return $this;
  240.     }
  241.     public function addAggregation(Aggregation ...$aggregations): self
  242.     {
  243.         foreach ($aggregations as $aggregation) {
  244.             $this->aggregations[$aggregation->getName()] = $aggregation;
  245.         }
  246.         return $this;
  247.     }
  248.     public function addPostFilter(Filter ...$queries): self
  249.     {
  250.         foreach ($queries as $query) {
  251.             $this->postFilters[] = $query;
  252.         }
  253.         return $this;
  254.     }
  255.     public function addQuery(ScoreQuery ...$queries): self
  256.     {
  257.         foreach ($queries as $query) {
  258.             $this->queries[] = $query;
  259.         }
  260.         return $this;
  261.     }
  262.     /**
  263.      * Add for each part of the provided path an association
  264.      *
  265.      * e.g
  266.      *
  267.      * $criteria->addAssociation('categories.media.thumbnails')
  268.      *
  269.      * @throws InconsistentCriteriaIdsException
  270.      */
  271.     public function addAssociation(string $path): self
  272.     {
  273.         $parts explode('.'$path);
  274.         $criteria $this;
  275.         foreach ($parts as $part) {
  276.             if (mb_strtolower($part) === 'extensions') {
  277.                 continue;
  278.             }
  279.             $criteria $criteria->getAssociation($part);
  280.         }
  281.         return $this;
  282.     }
  283.     /**
  284.      * @param string[] $paths
  285.      *
  286.      * Allows to add multiple associations paths
  287.      *
  288.      * e.g.:
  289.      *
  290.      * $criteria->addAssociations([
  291.      *      'prices',
  292.      *      'cover.media',
  293.      *      'categories.cover.media'
  294.      * ]);
  295.      *
  296.      * @throws InconsistentCriteriaIdsException
  297.      */
  298.     public function addAssociations(array $paths): self
  299.     {
  300.         foreach ($paths as $path) {
  301.             $this->addAssociation($path);
  302.         }
  303.         return $this;
  304.     }
  305.     public function hasAssociation(string $field): bool
  306.     {
  307.         return isset($this->associations[$field]);
  308.     }
  309.     public function resetSorting(): self
  310.     {
  311.         $this->sorting = [];
  312.         return $this;
  313.     }
  314.     public function resetAssociations(): self
  315.     {
  316.         $this->associations = [];
  317.         return $this;
  318.     }
  319.     public function resetQueries(): self
  320.     {
  321.         $this->queries = [];
  322.         return $this;
  323.     }
  324.     public function resetFilters(): self
  325.     {
  326.         $this->filters = [];
  327.         return $this;
  328.     }
  329.     public function resetPostFilters(): self
  330.     {
  331.         $this->postFilters = [];
  332.         return $this;
  333.     }
  334.     public function resetAggregations(): self
  335.     {
  336.         $this->aggregations = [];
  337.         return $this;
  338.     }
  339.     public function setTotalCountMode(int $totalCountMode): self
  340.     {
  341.         $this->totalCountMode $totalCountMode;
  342.         return $this;
  343.     }
  344.     public function setLimit(?int $limit): self
  345.     {
  346.         $this->limit $limit;
  347.         return $this;
  348.     }
  349.     public function setOffset(?int $offset): self
  350.     {
  351.         $this->offset $offset;
  352.         return $this;
  353.     }
  354.     /**
  355.      * @return array<string>
  356.      */
  357.     public function getAggregationQueryFields(): array
  358.     {
  359.         return $this->collectFields([
  360.             $this->filters,
  361.             $this->queries,
  362.         ]);
  363.     }
  364.     /**
  365.      * @return array<string>
  366.      */
  367.     public function getSearchQueryFields(): array
  368.     {
  369.         return $this->collectFields([
  370.             $this->filters,
  371.             $this->postFilters,
  372.             $this->sorting,
  373.             $this->queries,
  374.             $this->groupFields,
  375.         ]);
  376.     }
  377.     /**
  378.      * @return array<string>
  379.      */
  380.     public function getFilterFields(): array
  381.     {
  382.         return $this->collectFields([
  383.             $this->filters,
  384.             $this->postFilters,
  385.         ]);
  386.     }
  387.     /**
  388.      * @return array<string>
  389.      */
  390.     public function getAllFields(): array
  391.     {
  392.         return $this->collectFields([
  393.             $this->filters,
  394.             $this->postFilters,
  395.             $this->sorting,
  396.             $this->queries,
  397.             $this->groupFields,
  398.             $this->aggregations,
  399.         ]);
  400.     }
  401.     /**
  402.      * @param array<string>|array<int, array<string>> $ids
  403.      */
  404.     public function setIds(array $ids): self
  405.     {
  406.         $this->ids $ids;
  407.         return $this;
  408.     }
  409.     public function getTerm(): ?string
  410.     {
  411.         return $this->term;
  412.     }
  413.     public function setTerm(?string $term): self
  414.     {
  415.         $this->term $term;
  416.         return $this;
  417.     }
  418.     /**
  419.      * @param array<string>|array<int, array<string>> $ids
  420.      */
  421.     public function cloneForRead(array $ids = []): Criteria
  422.     {
  423.         $self = new self($ids);
  424.         $self->setTitle($this->getTitle());
  425.         $associations = [];
  426.         foreach ($this->associations as $name => $association) {
  427.             $associations[$name] = clone $association;
  428.         }
  429.         $self->associations $associations;
  430.         $self->fields $this->fields;
  431.         return $self;
  432.     }
  433.     public function addGroupField(FieldGrouping $grouping): self
  434.     {
  435.         $this->groupFields[] = $grouping;
  436.         return $this;
  437.     }
  438.     /**
  439.      * @return FieldGrouping[]
  440.      */
  441.     public function getGroupFields(): array
  442.     {
  443.         return $this->groupFields;
  444.     }
  445.     public function resetGroupFields(): self
  446.     {
  447.         $this->groupFields = [];
  448.         return $this;
  449.     }
  450.     /**
  451.      * @param array<string, array<string, string>>|null $includes
  452.      */
  453.     public function setIncludes(?array $includes): void
  454.     {
  455.         $this->includes $includes;
  456.     }
  457.     /**
  458.      * @return array<string, array<string, string>>|null
  459.      */
  460.     public function getIncludes()
  461.     {
  462.         return $this->includes;
  463.     }
  464.     public function getApiAlias(): string
  465.     {
  466.         return 'dal_criteria';
  467.     }
  468.     public function useIdSorting(): bool
  469.     {
  470.         if (empty($this->getIds())) {
  471.             return false;
  472.         }
  473.         // manual sorting provided
  474.         if (!empty($this->getSorting())) {
  475.             return false;
  476.         }
  477.         // result will be sorted by interpreted search term and the calculated ranking
  478.         if (!empty($this->getTerm())) {
  479.             return false;
  480.         }
  481.         // result will be sorted by calculated ranking
  482.         if (!empty($this->getQueries())) {
  483.             return false;
  484.         }
  485.         return true;
  486.     }
  487.     public function removeAssociation(string $association): void
  488.     {
  489.         unset($this->associations[$association]);
  490.     }
  491.     public function getTitle(): ?string
  492.     {
  493.         return $this->title;
  494.     }
  495.     public function setTitle(?string $title): void
  496.     {
  497.         $this->title $title;
  498.     }
  499.     /**
  500.      * @param string[] $fields
  501.      *
  502.      * @internal
  503.      */
  504.     public function addFields(array $fields): self
  505.     {
  506.         Feature::throwException('v6.5.0.0''Partial data loading is not active'false);
  507.         $this->fields array_merge($this->fields$fields);
  508.         return $this;
  509.     }
  510.     /**
  511.      * @return string[]
  512.      *
  513.      * @internal
  514.      */
  515.     public function getFields(): array
  516.     {
  517.         return $this->fields;
  518.     }
  519.     /**
  520.      * @param array<array<CriteriaPartInterface>> $parts
  521.      *
  522.      * @return array<string>
  523.      */
  524.     private function collectFields(array $parts): array
  525.     {
  526.         $fields = [];
  527.         foreach ($parts as $part) {
  528.             /** @var CriteriaPartInterface $item */
  529.             foreach ($part as $item) {
  530.                 foreach ($item->getFields() as $field) {
  531.                     $fields[] = $field;
  532.                 }
  533.             }
  534.         }
  535.         return $fields;
  536.     }
  537. }