123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework\Search\Request;
- use Magento\Framework\Exception\StateException;
- use Magento\Framework\Search\Request\Query\Filter;
- use Magento\Framework\Phrase;
- /**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @api
- * @since 100.0.2
- */
- class Mapper
- {
- /**
- * @var QueryInterface
- */
- private $rootQuery;
- /**
- * @var array
- */
- private $queries;
- /**
- * @var array
- */
- private $filters;
- /**
- * @var string[]
- */
- private $mappedQueries;
- /**
- * @var string[]
- */
- private $mappedFilters;
- /**
- * @var array
- */
- private $aggregations;
- /**
- * @var \Magento\Framework\ObjectManagerInterface
- */
- private $objectManager;
- /**
- * @var string
- */
- private $rootQueryName;
- /**
- * @param \Magento\Framework\ObjectManagerInterface $objectManager
- * @param array $queries
- * @param string $rootQueryName
- * @param array $aggregations
- * @param array $filters
- * @throws \Exception
- * @throws \InvalidArgumentException
- * @throws StateException
- */
- public function __construct(
- \Magento\Framework\ObjectManagerInterface $objectManager,
- array $queries,
- $rootQueryName,
- array $aggregations = [],
- array $filters = []
- ) {
- $this->objectManager = $objectManager;
- $this->queries = $queries;
- $this->aggregations = $aggregations;
- $this->filters = $filters;
- $this->rootQueryName = $rootQueryName;
- }
- /**
- * Get Query Interface by name
- *
- * @return QueryInterface
- * @throws \Exception
- * @throws \InvalidArgumentException
- * @throws StateException
- */
- public function getRootQuery()
- {
- if (!$this->rootQuery) {
- $this->mappedQueries = [];
- $this->mappedFilters = [];
- $this->rootQuery = $this->mapQuery($this->rootQueryName);
- $this->validate();
- }
- return $this->rootQuery;
- }
- /**
- * Convert array to Query instance
- *
- * @param string $queryName
- * @return QueryInterface
- * @throws \Exception
- * @throws \InvalidArgumentException
- * @throws StateException
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- */
- private function mapQuery($queryName)
- {
- if (!isset($this->queries[$queryName])) {
- throw new \Exception('Query ' . $queryName . ' does not exist');
- } elseif (in_array($queryName, $this->mappedQueries)) {
- throw new StateException(
- new Phrase('A cycle was found. The "%1" query is already used in the request hierarchy.', [$queryName])
- );
- }
- $this->mappedQueries[] = $queryName;
- $query = $this->queries[$queryName];
- switch ($query['type']) {
- case QueryInterface::TYPE_MATCH:
- $query = $this->objectManager->create(
- \Magento\Framework\Search\Request\Query\Match::class,
- [
- 'name' => $query['name'],
- 'value' => $query['value'],
- 'boost' => isset($query['boost']) ? $query['boost'] : 1,
- 'matches' => $query['match']
- ]
- );
- break;
- case QueryInterface::TYPE_FILTER:
- if (isset($query['queryReference'][0])) {
- $reference = $this->mapQuery($query['queryReference'][0]['ref']);
- $referenceType = Filter::REFERENCE_QUERY;
- } elseif (isset($query['filterReference'][0])) {
- $reference = $this->mapFilter($query['filterReference'][0]['ref']);
- $referenceType = Filter::REFERENCE_FILTER;
- } else {
- throw new \Exception('Reference is not provided');
- }
- $query = $this->objectManager->create(
- \Magento\Framework\Search\Request\Query\Filter::class,
- [
- 'name' => $query['name'],
- 'boost' => isset($query['boost']) ? $query['boost'] : 1,
- 'reference' => $reference,
- 'referenceType' => $referenceType
- ]
- );
- break;
- case QueryInterface::TYPE_BOOL:
- $aggregatedByType = $this->aggregateQueriesByType($query['queryReference']);
- $query = $this->objectManager->create(
- \Magento\Framework\Search\Request\Query\BoolExpression::class,
- array_merge(
- ['name' => $query['name'], 'boost' => isset($query['boost']) ? $query['boost'] : 1],
- $aggregatedByType
- )
- );
- break;
- default:
- throw new \InvalidArgumentException('Invalid query type');
- }
- return $query;
- }
- /**
- * Convert array to Filter instance
- *
- * @param string $filterName
- * @throws \Exception
- * @return FilterInterface
- * @throws \Exception
- * @throws \InvalidArgumentException
- * @throws StateException
- */
- private function mapFilter($filterName)
- {
- if (!isset($this->filters[$filterName])) {
- throw new \Exception('Filter ' . $filterName . ' does not exist');
- } elseif (in_array($filterName, $this->mappedFilters)) {
- throw new StateException(
- new Phrase(
- 'A cycle was found. The "%1" filter is already used in the request hierarchy.',
- [$filterName]
- )
- );
- }
- $this->mappedFilters[] = $filterName;
- $filter = $this->filters[$filterName];
- switch ($filter['type']) {
- case FilterInterface::TYPE_TERM:
- $filter = $this->objectManager->create(
- \Magento\Framework\Search\Request\Filter\Term::class,
- [
- 'name' => $filter['name'],
- 'field' => $filter['field'],
- 'value' => $filter['value']
- ]
- );
- break;
- case FilterInterface::TYPE_RANGE:
- $filter = $this->objectManager->create(
- \Magento\Framework\Search\Request\Filter\Range::class,
- [
- 'name' => $filter['name'],
- 'field' => $filter['field'],
- 'from' => isset($filter['from']) ? $filter['from'] : null,
- 'to' => isset($filter['to']) ? $filter['to'] : null
- ]
- );
- break;
- case FilterInterface::TYPE_WILDCARD:
- $filter = $this->objectManager->create(
- \Magento\Framework\Search\Request\Filter\Wildcard::class,
- [
- 'name' => $filter['name'],
- 'field' => $filter['field'],
- 'value' => $filter['value']
- ]
- );
- break;
- case FilterInterface::TYPE_BOOL:
- $aggregatedByType = $this->aggregateFiltersByType($filter['filterReference']);
- $filter = $this->objectManager->create(
- \Magento\Framework\Search\Request\Filter\BoolExpression::class,
- array_merge(
- ['name' => $filter['name']],
- $aggregatedByType
- )
- );
- break;
- default:
- throw new \InvalidArgumentException('Invalid filter type');
- }
- return $filter;
- }
- /**
- * Aggregate Filters by clause
- *
- * @param array $data
- * @return array
- */
- private function aggregateFiltersByType($data)
- {
- $list = [];
- foreach ($data as $value) {
- $list[$value['clause']][$value['ref']] = $this->mapFilter($value['ref']);
- }
- return $list;
- }
- /**
- * Aggregate Queries by clause
- *
- * @param array $data
- * @return array
- */
- private function aggregateQueriesByType($data)
- {
- $list = [];
- foreach ($data as $value) {
- $list[$value['clause']][$value['ref']] = $this->mapQuery($value['ref']);
- }
- return $list;
- }
- /**
- * @return void
- * @throws StateException
- */
- private function validate()
- {
- $this->validateQueries();
- $this->validateFilters();
- }
- /**
- * @return void
- * @throws StateException
- */
- private function validateQueries()
- {
- $this->validateNotUsed($this->queries, $this->mappedQueries, 'Query %1 is not used in request hierarchy');
- }
- /**
- * @param array $elements
- * @param string[] $mappedElements
- * @param string $errorMessage
- * @return void
- * @throws \Magento\Framework\Exception\StateException
- */
- private function validateNotUsed($elements, $mappedElements, $errorMessage)
- {
- $allElements = array_keys($elements);
- $notUsedElements = implode(', ', array_diff($allElements, $mappedElements));
- if (!empty($notUsedElements)) {
- throw new StateException(new Phrase($errorMessage, [$notUsedElements]));
- }
- }
- /**
- * @return void
- * @throws StateException
- */
- private function validateFilters()
- {
- $this->validateNotUsed($this->filters, $this->mappedFilters, 'Filter %1 is not used in request hierarchy');
- }
- /**
- * Build BucketInterface[] from array
- *
- * @return array
- * @throws StateException
- */
- public function getBuckets()
- {
- $buckets = [];
- foreach ($this->aggregations as $bucketData) {
- $arguments = [
- 'name' => $bucketData['name'],
- 'field' => $bucketData['field'],
- 'metrics' => $this->mapMetrics($bucketData),
- ];
- switch ($bucketData['type']) {
- case BucketInterface::TYPE_TERM:
- $bucket = $this->objectManager->create(
- \Magento\Framework\Search\Request\Aggregation\TermBucket::class,
- $arguments
- );
- break;
- case BucketInterface::TYPE_RANGE:
- $bucket = $this->objectManager->create(
- \Magento\Framework\Search\Request\Aggregation\RangeBucket::class,
- array_merge(
- $arguments,
- ['ranges' => $this->mapRanges($bucketData)]
- )
- );
- break;
- case BucketInterface::TYPE_DYNAMIC:
- $bucket = $this->objectManager->create(
- \Magento\Framework\Search\Request\Aggregation\DynamicBucket::class,
- array_merge(
- $arguments,
- ['method' => $bucketData['method']]
- )
- );
- break;
- default:
- throw new StateException(new Phrase('The bucket type is invalid. Verify and try again.'));
- break;
- }
- $buckets[] = $bucket;
- }
- return $buckets;
- }
- /**
- * Build Metric[] from array
- *
- * @param array $bucketData
- * @return array
- */
- private function mapMetrics(array $bucketData)
- {
- $metricObjects = [];
- if (isset($bucketData['metric'])) {
- $metrics = $bucketData['metric'];
- foreach ($metrics as $metric) {
- $metricObjects[] = $this->objectManager->create(
- \Magento\Framework\Search\Request\Aggregation\Metric::class,
- [
- 'type' => $metric['type']
- ]
- );
- }
- }
- return $metricObjects;
- }
- /**
- * Build Range[] from array
- *
- * @param array $bucketData
- * @return array
- */
- private function mapRanges(array $bucketData)
- {
- $rangeObjects = [];
- if (isset($bucketData['range'])) {
- $ranges = $bucketData['range'];
- foreach ($ranges as $range) {
- $rangeObjects[] = $this->objectManager->create(
- \Magento\Framework\Search\Request\Aggregation\Range::class,
- [
- 'from' => $range['from'],
- 'to' => $range['to']
- ]
- );
- }
- }
- return $rangeObjects;
- }
- }
|