PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/magento/framework/Search/Request/Mapper.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 407 lines | 267 code | 22 blank | 118 comment | 11 complexity | d705da988d3c5fb87a4493778258570e MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Search\Request;
  7. use Magento\Framework\Exception\StateException;
  8. use Magento\Framework\Search\Request\Query\Filter;
  9. use Magento\Framework\Phrase;
  10. /**
  11. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  12. */
  13. class Mapper
  14. {
  15. /**
  16. * @var QueryInterface
  17. */
  18. private $rootQuery;
  19. /**
  20. * @var array
  21. */
  22. private $queries;
  23. /**
  24. * @var array
  25. */
  26. private $filters;
  27. /**
  28. * @var string[]
  29. */
  30. private $mappedQueries;
  31. /**
  32. * @var string[]
  33. */
  34. private $mappedFilters;
  35. /**
  36. * @var array
  37. */
  38. private $aggregations;
  39. /**
  40. * @var \Magento\Framework\ObjectManagerInterface
  41. */
  42. private $objectManager;
  43. /**
  44. * @var string
  45. */
  46. private $rootQueryName;
  47. /**
  48. * @param \Magento\Framework\ObjectManagerInterface $objectManager
  49. * @param array $queries
  50. * @param string $rootQueryName
  51. * @param array $aggregations
  52. * @param array $filters
  53. * @throws \Exception
  54. * @throws \InvalidArgumentException
  55. * @throws StateException
  56. */
  57. public function __construct(
  58. \Magento\Framework\ObjectManagerInterface $objectManager,
  59. array $queries,
  60. $rootQueryName,
  61. array $aggregations = [],
  62. array $filters = []
  63. ) {
  64. $this->objectManager = $objectManager;
  65. $this->queries = $queries;
  66. $this->aggregations = $aggregations;
  67. $this->filters = $filters;
  68. $this->rootQueryName = $rootQueryName;
  69. }
  70. /**
  71. * Get Query Interface by name
  72. *
  73. * @return QueryInterface
  74. * @throws \Exception
  75. * @throws \InvalidArgumentException
  76. * @throws StateException
  77. */
  78. public function getRootQuery()
  79. {
  80. if (!$this->rootQuery) {
  81. $this->mappedQueries = [];
  82. $this->mappedFilters = [];
  83. $this->rootQuery = $this->mapQuery($this->rootQueryName);
  84. $this->validate();
  85. }
  86. return $this->rootQuery;
  87. }
  88. /**
  89. * Convert array to Query instance
  90. *
  91. * @param string $queryName
  92. * @return QueryInterface
  93. * @throws \Exception
  94. * @throws \InvalidArgumentException
  95. * @throws StateException
  96. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  97. */
  98. private function mapQuery($queryName)
  99. {
  100. if (!isset($this->queries[$queryName])) {
  101. throw new \Exception('Query ' . $queryName . ' does not exist');
  102. } elseif (in_array($queryName, $this->mappedQueries)) {
  103. throw new StateException(
  104. new Phrase('Cycle found. Query %1 already used in request hierarchy', [$queryName])
  105. );
  106. }
  107. $this->mappedQueries[] = $queryName;
  108. $query = $this->queries[$queryName];
  109. switch ($query['type']) {
  110. case QueryInterface::TYPE_MATCH:
  111. $query = $this->objectManager->create(
  112. 'Magento\Framework\Search\Request\Query\Match',
  113. [
  114. 'name' => $query['name'],
  115. 'value' => $query['value'],
  116. 'boost' => isset($query['boost']) ? $query['boost'] : 1,
  117. 'matches' => $query['match']
  118. ]
  119. );
  120. break;
  121. case QueryInterface::TYPE_FILTER:
  122. if (isset($query['queryReference'][0])) {
  123. $reference = $this->mapQuery($query['queryReference'][0]['ref']);
  124. $referenceType = Filter::REFERENCE_QUERY;
  125. } elseif (isset($query['filterReference'][0])) {
  126. $reference = $this->mapFilter($query['filterReference'][0]['ref']);
  127. $referenceType = Filter::REFERENCE_FILTER;
  128. } else {
  129. throw new \Exception('Reference is not provided');
  130. }
  131. $query = $this->objectManager->create(
  132. 'Magento\Framework\Search\Request\Query\Filter',
  133. [
  134. 'name' => $query['name'],
  135. 'boost' => isset($query['boost']) ? $query['boost'] : 1,
  136. 'reference' => $reference,
  137. 'referenceType' => $referenceType
  138. ]
  139. );
  140. break;
  141. case QueryInterface::TYPE_BOOL:
  142. $aggregatedByType = $this->aggregateQueriesByType($query['queryReference']);
  143. $query = $this->objectManager->create(
  144. 'Magento\Framework\Search\Request\Query\BoolExpression',
  145. array_merge(
  146. ['name' => $query['name'], 'boost' => isset($query['boost']) ? $query['boost'] : 1],
  147. $aggregatedByType
  148. )
  149. );
  150. break;
  151. default:
  152. throw new \InvalidArgumentException('Invalid query type');
  153. }
  154. return $query;
  155. }
  156. /**
  157. * Convert array to Filter instance
  158. *
  159. * @param string $filterName
  160. * @throws \Exception
  161. * @return FilterInterface
  162. * @throws \Exception
  163. * @throws \InvalidArgumentException
  164. * @throws StateException
  165. */
  166. private function mapFilter($filterName)
  167. {
  168. if (!isset($this->filters[$filterName])) {
  169. throw new \Exception('Filter ' . $filterName . ' does not exist');
  170. } elseif (in_array($filterName, $this->mappedFilters)) {
  171. throw new StateException(
  172. new Phrase('Cycle found. Filter %1 already used in request hierarchy', [$filterName])
  173. );
  174. }
  175. $this->mappedFilters[] = $filterName;
  176. $filter = $this->filters[$filterName];
  177. switch ($filter['type']) {
  178. case FilterInterface::TYPE_TERM:
  179. $filter = $this->objectManager->create(
  180. 'Magento\Framework\Search\Request\Filter\Term',
  181. [
  182. 'name' => $filter['name'],
  183. 'field' => $filter['field'],
  184. 'value' => $filter['value']
  185. ]
  186. );
  187. break;
  188. case FilterInterface::TYPE_RANGE:
  189. $filter = $this->objectManager->create(
  190. 'Magento\Framework\Search\Request\Filter\Range',
  191. [
  192. 'name' => $filter['name'],
  193. 'field' => $filter['field'],
  194. 'from' => isset($filter['from']) ? $filter['from'] : null,
  195. 'to' => isset($filter['to']) ? $filter['to'] : null
  196. ]
  197. );
  198. break;
  199. case FilterInterface::TYPE_WILDCARD:
  200. $filter = $this->objectManager->create(
  201. 'Magento\Framework\Search\Request\Filter\Wildcard',
  202. [
  203. 'name' => $filter['name'],
  204. 'field' => $filter['field'],
  205. 'value' => $filter['value']
  206. ]
  207. );
  208. break;
  209. case FilterInterface::TYPE_BOOL:
  210. $aggregatedByType = $this->aggregateFiltersByType($filter['filterReference']);
  211. $filter = $this->objectManager->create(
  212. 'Magento\Framework\Search\Request\Filter\BoolExpression',
  213. array_merge(
  214. ['name' => $filter['name']],
  215. $aggregatedByType
  216. )
  217. );
  218. break;
  219. default:
  220. throw new \InvalidArgumentException('Invalid filter type');
  221. }
  222. return $filter;
  223. }
  224. /**
  225. * Aggregate Filters by clause
  226. *
  227. * @param array $data
  228. * @return array
  229. */
  230. private function aggregateFiltersByType($data)
  231. {
  232. $list = [];
  233. foreach ($data as $value) {
  234. $list[$value['clause']][$value['ref']] = $this->mapFilter($value['ref']);
  235. }
  236. return $list;
  237. }
  238. /**
  239. * Aggregate Queries by clause
  240. *
  241. * @param array $data
  242. * @return array
  243. */
  244. private function aggregateQueriesByType($data)
  245. {
  246. $list = [];
  247. foreach ($data as $value) {
  248. $list[$value['clause']][$value['ref']] = $this->mapQuery($value['ref']);
  249. }
  250. return $list;
  251. }
  252. /**
  253. * @return void
  254. * @throws StateException
  255. */
  256. private function validate()
  257. {
  258. $this->validateQueries();
  259. $this->validateFilters();
  260. }
  261. /**
  262. * @return void
  263. * @throws StateException
  264. */
  265. private function validateQueries()
  266. {
  267. $this->validateNotUsed($this->queries, $this->mappedQueries, 'Query %1 is not used in request hierarchy');
  268. }
  269. /**
  270. * @param array $elements
  271. * @param string[] $mappedElements
  272. * @param string $errorMessage
  273. * @return void
  274. * @throws \Magento\Framework\Exception\StateException
  275. */
  276. private function validateNotUsed($elements, $mappedElements, $errorMessage)
  277. {
  278. $allElements = array_keys($elements);
  279. $notUsedElements = implode(', ', array_diff($allElements, $mappedElements));
  280. if (!empty($notUsedElements)) {
  281. throw new StateException(new Phrase($errorMessage, [$notUsedElements]));
  282. }
  283. }
  284. /**
  285. * @return void
  286. * @throws StateException
  287. */
  288. private function validateFilters()
  289. {
  290. $this->validateNotUsed($this->filters, $this->mappedFilters, 'Filter %1 is not used in request hierarchy');
  291. }
  292. /**
  293. * Build BucketInterface[] from array
  294. *
  295. * @return array
  296. * @throws StateException
  297. */
  298. public function getBuckets()
  299. {
  300. $buckets = [];
  301. foreach ($this->aggregations as $bucketData) {
  302. $arguments = [
  303. 'name' => $bucketData['name'],
  304. 'field' => $bucketData['field'],
  305. 'metrics' => $this->mapMetrics($bucketData),
  306. ];
  307. switch ($bucketData['type']) {
  308. case BucketInterface::TYPE_TERM:
  309. $bucket = $this->objectManager->create(
  310. 'Magento\Framework\Search\Request\Aggregation\TermBucket',
  311. $arguments
  312. );
  313. break;
  314. case BucketInterface::TYPE_RANGE:
  315. $bucket = $this->objectManager->create(
  316. 'Magento\Framework\Search\Request\Aggregation\RangeBucket',
  317. array_merge(
  318. $arguments,
  319. ['ranges' => $this->mapRanges($bucketData)]
  320. )
  321. );
  322. break;
  323. case BucketInterface::TYPE_DYNAMIC:
  324. $bucket = $this->objectManager->create(
  325. 'Magento\Framework\Search\Request\Aggregation\DynamicBucket',
  326. array_merge(
  327. $arguments,
  328. ['method' => $bucketData['method']]
  329. )
  330. );
  331. break;
  332. default:
  333. throw new StateException(new Phrase('Invalid bucket type'));
  334. break;
  335. }
  336. $buckets[] = $bucket;
  337. }
  338. return $buckets;
  339. }
  340. /**
  341. * Build Metric[] from array
  342. *
  343. * @param array $bucketData
  344. * @return array
  345. */
  346. private function mapMetrics(array $bucketData)
  347. {
  348. $metricObjects = [];
  349. if (isset($bucketData['metric'])) {
  350. $metrics = $bucketData['metric'];
  351. foreach ($metrics as $metric) {
  352. $metricObjects[] = $this->objectManager->create(
  353. 'Magento\Framework\Search\Request\Aggregation\Metric',
  354. [
  355. 'type' => $metric['type']
  356. ]
  357. );
  358. }
  359. }
  360. return $metricObjects;
  361. }
  362. /**
  363. * Build Range[] from array
  364. *
  365. * @param array $bucketData
  366. * @return array
  367. */
  368. private function mapRanges(array $bucketData)
  369. {
  370. $rangeObjects = [];
  371. if (isset($bucketData['range'])) {
  372. $ranges = $bucketData['range'];
  373. foreach ($ranges as $range) {
  374. $rangeObjects[] = $this->objectManager->create(
  375. 'Magento\Framework\Search\Request\Aggregation\Range',
  376. [
  377. 'from' => $range['from'],
  378. 'to' => $range['to']
  379. ]
  380. );
  381. }
  382. }
  383. return $rangeObjects;
  384. }
  385. }