PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/magento/module-catalog/Model/ResourceModel/Layer/Filter/Price.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 384 lines | 227 code | 39 blank | 118 comment | 25 complexity | ec551b52e154ffc4e4131a9d8ba4c0b0 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Catalog\Model\ResourceModel\Layer\Filter;
  7. /**
  8. * Catalog Layer Price Filter resource model
  9. */
  10. class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
  11. {
  12. /**
  13. * Minimal possible price
  14. */
  15. const MIN_POSSIBLE_PRICE = .01;
  16. /**
  17. * Core event manager proxy
  18. *
  19. * @var \Magento\Framework\Event\ManagerInterface
  20. */
  21. protected $_eventManager = null;
  22. /**
  23. * @var \Magento\Catalog\Model\Layer
  24. */
  25. private $layer;
  26. /**
  27. * @var \Magento\Customer\Model\Session
  28. */
  29. private $session;
  30. /**
  31. * @var \Magento\Store\Model\StoreManagerInterface
  32. */
  33. private $storeManager;
  34. /**
  35. * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  36. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  37. * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
  38. * @param \Magento\Customer\Model\Session $session
  39. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  40. * @param string $connectionName
  41. */
  42. public function __construct(
  43. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  44. \Magento\Framework\Event\ManagerInterface $eventManager,
  45. \Magento\Catalog\Model\Layer\Resolver $layerResolver,
  46. \Magento\Customer\Model\Session $session,
  47. \Magento\Store\Model\StoreManagerInterface $storeManager,
  48. $connectionName = null
  49. ) {
  50. $this->layer = $layerResolver->get();
  51. $this->session = $session;
  52. $this->storeManager = $storeManager;
  53. $this->_eventManager = $eventManager;
  54. parent::__construct($context, $connectionName);
  55. }
  56. /**
  57. * Retrieve array with products counts per price range
  58. *
  59. * @param int $range
  60. * @return array
  61. */
  62. public function getCount($range)
  63. {
  64. $select = $this->_getSelect();
  65. $priceExpression = $this->_getFullPriceExpression($select);
  66. /**
  67. * Check and set correct variable values to prevent SQL-injections
  68. */
  69. $range = floatval($range);
  70. if ($range == 0) {
  71. $range = 1;
  72. }
  73. $countExpr = new \Zend_Db_Expr('COUNT(*)');
  74. $rangeExpr = new \Zend_Db_Expr("FLOOR(({$priceExpression}) / {$range}) + 1");
  75. $select->columns(['range' => $rangeExpr, 'count' => $countExpr]);
  76. $select->group($rangeExpr)->order("({$rangeExpr}) ASC");
  77. return $this->getConnection()->fetchPairs($select);
  78. }
  79. /**
  80. * Retrieve clean select with joined price index table
  81. *
  82. * @return \Magento\Framework\DB\Select
  83. */
  84. protected function _getSelect()
  85. {
  86. $collection = $this->layer->getProductCollection();
  87. $collection->addPriceData(
  88. $this->session->getCustomerGroupId(),
  89. $this->storeManager->getStore()->getWebsiteId()
  90. );
  91. if ($collection->getCatalogPreparedSelect() !== null) {
  92. $select = clone $collection->getCatalogPreparedSelect();
  93. } else {
  94. $select = clone $collection->getSelect();
  95. }
  96. // reset columns, order and limitation conditions
  97. $select->reset(\Magento\Framework\DB\Select::COLUMNS);
  98. $select->reset(\Magento\Framework\DB\Select::ORDER);
  99. $select->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
  100. $select->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);
  101. // remove join with main table
  102. $fromPart = $select->getPart(\Magento\Framework\DB\Select::FROM);
  103. if (!isset(
  104. $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS]
  105. ) || !isset(
  106. $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS]
  107. )
  108. ) {
  109. return $select;
  110. }
  111. // processing FROM part
  112. $priceIndexJoinPart = $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS];
  113. $priceIndexJoinConditions = explode('AND', $priceIndexJoinPart['joinCondition']);
  114. $priceIndexJoinPart['joinType'] = \Magento\Framework\DB\Select::FROM;
  115. $priceIndexJoinPart['joinCondition'] = null;
  116. $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS] = $priceIndexJoinPart;
  117. unset($fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS]);
  118. $select->setPart(\Magento\Framework\DB\Select::FROM, $fromPart);
  119. foreach ($fromPart as $key => $fromJoinItem) {
  120. $fromPart[$key]['joinCondition'] = $this->_replaceTableAlias($fromJoinItem['joinCondition']);
  121. }
  122. $select->setPart(\Magento\Framework\DB\Select::FROM, $fromPart);
  123. // processing WHERE part
  124. $wherePart = $select->getPart(\Magento\Framework\DB\Select::WHERE);
  125. foreach ($wherePart as $key => $wherePartItem) {
  126. $wherePart[$key] = $this->_replaceTableAlias($wherePartItem);
  127. }
  128. $select->setPart(\Magento\Framework\DB\Select::WHERE, $wherePart);
  129. $excludeJoinPart = \Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS . '.entity_id';
  130. foreach ($priceIndexJoinConditions as $condition) {
  131. if (strpos($condition, $excludeJoinPart) !== false) {
  132. continue;
  133. }
  134. $select->where($this->_replaceTableAlias($condition));
  135. }
  136. $select->where($this->_getPriceExpression($select) . ' IS NOT NULL');
  137. return $select;
  138. }
  139. /**
  140. * Replace table alias in condition string
  141. *
  142. * @param string|null $conditionString
  143. * @return string|null
  144. */
  145. protected function _replaceTableAlias($conditionString)
  146. {
  147. if ($conditionString === null) {
  148. return null;
  149. }
  150. $connection = $this->getConnection();
  151. $oldAlias = [
  152. \Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS . '.',
  153. $connection->quoteIdentifier(
  154. \Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS
  155. ) . '.',
  156. ];
  157. $newAlias = [
  158. \Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS . '.',
  159. $connection->quoteIdentifier(
  160. \Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS
  161. ) . '.',
  162. ];
  163. return str_replace($oldAlias, $newAlias, $conditionString);
  164. }
  165. /**
  166. * Price expression generated by products collection
  167. *
  168. * @param \Magento\Framework\DB\Select $select
  169. * @param bool $replaceAlias
  170. * @return string
  171. */
  172. protected function _getPriceExpression($select, $replaceAlias = true)
  173. {
  174. $priceExpression = $this->layer->getProductCollection()->getPriceExpression($select);
  175. $additionalPriceExpression = $this->layer->getProductCollection()->getAdditionalPriceExpression(
  176. $select
  177. );
  178. $result = empty($additionalPriceExpression)
  179. ? $priceExpression
  180. : "({$priceExpression} {$additionalPriceExpression})";
  181. if ($replaceAlias) {
  182. $result = $this->_replaceTableAlias($result);
  183. }
  184. return $result;
  185. }
  186. /**
  187. * Get full price expression generated by products collection
  188. *
  189. * @param \Magento\Framework\DB\Select $select
  190. * @return \Zend_Db_Expr
  191. */
  192. protected function _getFullPriceExpression($select)
  193. {
  194. return new \Zend_Db_Expr(
  195. 'ROUND((' . $this->_getPriceExpression($select)
  196. . ') * ' . $this->layer->getProductCollection()->getCurrencyRate() . ', 2)'
  197. );
  198. }
  199. /**
  200. * Get comparing value sql part
  201. *
  202. * @param float $price
  203. * @param bool $decrease
  204. * @return float
  205. */
  206. protected function _getComparingValue($price, $decrease = true)
  207. {
  208. $currencyRate = $this->layer->getProductCollection()->getCurrencyRate();
  209. if ($decrease) {
  210. return ($price - self::MIN_POSSIBLE_PRICE / 2) / $currencyRate;
  211. }
  212. return ($price + self::MIN_POSSIBLE_PRICE / 2) / $currencyRate;
  213. }
  214. /**
  215. * Load range of product prices, preceding the price
  216. *
  217. * @param float $price
  218. * @param int $index
  219. * @param null|int $lowerPrice
  220. * @return array|false
  221. */
  222. public function loadPreviousPrices($price, $index, $lowerPrice = null)
  223. {
  224. $select = $this->_getSelect();
  225. $priceExpression = $this->_getPriceExpression($select);
  226. $select->columns('COUNT(*)')->where("{$priceExpression} < " . $this->_getComparingValue($price));
  227. if ($lowerPrice !== null) {
  228. $select->where("{$priceExpression} >= " . $this->_getComparingValue($lowerPrice));
  229. }
  230. $offset = $this->getConnection()->fetchOne($select);
  231. if (!$offset) {
  232. return false;
  233. }
  234. return $this->loadPrices($index - $offset + 1, $offset - 1, $lowerPrice);
  235. }
  236. /**
  237. * Load range of product prices
  238. *
  239. * @param int $limit
  240. * @param null|int $offset
  241. * @param null|int $lowerPrice
  242. * @param null|int $upperPrice
  243. * @return array
  244. */
  245. public function loadPrices($limit, $offset = null, $lowerPrice = null, $upperPrice = null)
  246. {
  247. $select = $this->_getSelect();
  248. $priceExpression = $this->_getPriceExpression($select);
  249. $select->columns(['min_price_expr' => $this->_getFullPriceExpression($select)]);
  250. if ($lowerPrice !== null) {
  251. $select->where("{$priceExpression} >= " . $this->_getComparingValue($lowerPrice));
  252. }
  253. if ($upperPrice !== null) {
  254. $select->where("{$priceExpression} < " . $this->_getComparingValue($upperPrice));
  255. }
  256. $select->order("{$priceExpression} ASC")->limit($limit, $offset);
  257. return $this->getConnection()->fetchCol($select);
  258. }
  259. /**
  260. * Load range of product prices, next to the price
  261. *
  262. * @param float $price
  263. * @param int $rightIndex
  264. * @param null|int $upperPrice
  265. * @return array|false
  266. */
  267. public function loadNextPrices($price, $rightIndex, $upperPrice = null)
  268. {
  269. $select = $this->_getSelect();
  270. $pricesSelect = clone $select;
  271. $priceExpression = $this->_getPriceExpression($pricesSelect);
  272. $select->columns(
  273. 'COUNT(*)'
  274. )->where(
  275. "{$priceExpression} > " . $this->_getComparingValue($price, false)
  276. );
  277. if ($upperPrice !== null) {
  278. $select->where("{$priceExpression} < " . $this->_getComparingValue($upperPrice));
  279. }
  280. $offset = $this->getConnection()->fetchOne($select);
  281. if (!$offset) {
  282. return false;
  283. }
  284. $pricesSelect->columns(
  285. ['min_price_expr' => $this->_getFullPriceExpression($pricesSelect)]
  286. )->where(
  287. "{$priceExpression} >= " . $this->_getComparingValue($price)
  288. );
  289. if ($upperPrice !== null) {
  290. $pricesSelect->where("{$priceExpression} < " . $this->_getComparingValue($upperPrice));
  291. }
  292. $pricesSelect->order("{$priceExpression} DESC")->limit($rightIndex - $offset + 1, $offset - 1);
  293. return array_reverse($this->getConnection()->fetchCol($pricesSelect));
  294. }
  295. /**
  296. * Apply price range filter to product collection
  297. *
  298. * @param \Magento\Catalog\Model\Layer\Filter\FilterInterface $filter
  299. * @param mixed $interval
  300. * @return $this
  301. */
  302. public function applyPriceRange(\Magento\Catalog\Model\Layer\Filter\FilterInterface $filter, $interval)
  303. {
  304. if (!$interval) {
  305. return $this;
  306. }
  307. list($from, $to) = $interval;
  308. if ($from === '' && $to === '') {
  309. return $this;
  310. }
  311. $select = $filter->getLayer()->getProductCollection()->getSelect();
  312. $priceExpr = $this->_getPriceExpression($select, false);
  313. if ($to !== '') {
  314. $to = (double)$to;
  315. if ($from == $to) {
  316. $to += self::MIN_POSSIBLE_PRICE;
  317. }
  318. }
  319. if ($from !== '') {
  320. $select->where($priceExpr . ' >= ' . $this->_getComparingValue($from));
  321. }
  322. if ($to !== '') {
  323. $select->where($priceExpr . ' < ' . $this->_getComparingValue($to));
  324. }
  325. return $this;
  326. }
  327. /**
  328. * Initialize connection and define main table name
  329. *
  330. * @return void
  331. */
  332. protected function _construct()
  333. {
  334. $this->_init('catalog_product_index_price', 'entity_id');
  335. }
  336. /**
  337. * Retrieve joined price index table alias
  338. *
  339. * @return string
  340. */
  341. protected function _getIndexTableAlias()
  342. {
  343. return 'price_index';
  344. }
  345. }