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

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