PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php

https://github.com/FiveDigital/magento2
PHP | 2068 lines | 1245 code | 224 blank | 599 comment | 189 complexity | 59745017240ce7e5ab96444c5331e450 MD5 | raw file
Possible License(s): CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Catalog
  23. * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Product collection
  28. *
  29. * @category Mage
  30. * @package Mage_Catalog
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Catalog_Model_Resource_Product_Collection extends Mage_Catalog_Model_Resource_Collection_Abstract
  34. {
  35. /**
  36. * Alias for index table
  37. */
  38. const INDEX_TABLE_ALIAS = 'price_index';
  39. /**
  40. * Alias for main table
  41. */
  42. const MAIN_TABLE_ALIAS = 'e';
  43. /**
  44. * Catalog Product Flat is enabled cache per store
  45. *
  46. * @var array
  47. */
  48. protected $_flatEnabled = array();
  49. /**
  50. * Product websites table name
  51. *
  52. * @var string
  53. */
  54. protected $_productWebsiteTable;
  55. /**
  56. * Product categories table name
  57. *
  58. * @var string
  59. */
  60. protected $_productCategoryTable;
  61. /**
  62. * Is add URL rewrites to collection flag
  63. *
  64. * @var bool
  65. */
  66. protected $_addUrlRewrite = false;
  67. /**
  68. * Add URL rewrite for category
  69. *
  70. * @var int
  71. */
  72. protected $_urlRewriteCategory = '';
  73. /**
  74. * Is add final price to product collection flag
  75. *
  76. * @var unknown_type
  77. */
  78. protected $_addFinalPrice = false;
  79. /**
  80. * Cache for all ids
  81. *
  82. * @var array
  83. */
  84. protected $_allIdsCache = null;
  85. /**
  86. * Is add tax percents to product collection flag
  87. *
  88. * @var bool
  89. */
  90. protected $_addTaxPercents = false;
  91. /**
  92. * Product limitation filters
  93. * Allowed filters
  94. * store_id int;
  95. * category_id int;
  96. * category_is_anchor int;
  97. * visibility array|int;
  98. * website_ids array|int;
  99. * store_table string;
  100. * use_price_index bool; join price index table flag
  101. * customer_group_id int; required for price; customer group limitation for price
  102. * website_id int; required for price; website limitation for price
  103. *
  104. * @var array
  105. */
  106. protected $_productLimitationFilters = array();
  107. /**
  108. * Category product count select
  109. *
  110. * @var Zend_Db_Select
  111. */
  112. protected $_productCountSelect = null;
  113. /**
  114. * Enter description here ...
  115. *
  116. * @var bool
  117. */
  118. protected $_isWebsiteFilter = false;
  119. /**
  120. * Additional field filters, applied in _productLimitationJoinPrice()
  121. *
  122. * @var array
  123. */
  124. protected $_priceDataFieldFilters = array();
  125. /**
  126. * Map of price fields
  127. *
  128. * @var array
  129. */
  130. protected $_map = array('fields' => array(
  131. 'price' => 'price_index.price',
  132. 'final_price' => 'price_index.final_price',
  133. 'min_price' => 'price_index.min_price',
  134. 'max_price' => 'price_index.max_price',
  135. 'tier_price' => 'price_index.tier_price',
  136. 'special_price' => 'price_index.special_price',
  137. ));
  138. /**
  139. * Price expression sql
  140. *
  141. * @var string|null
  142. */
  143. protected $_priceExpression;
  144. /**
  145. * Additional price expression sql part
  146. *
  147. * @var string|null
  148. */
  149. protected $_additionalPriceExpression;
  150. /**
  151. * Max prise (statistics data)
  152. *
  153. * @var float
  154. */
  155. protected $_maxPrice;
  156. /**
  157. * Min prise (statistics data)
  158. *
  159. * @var float
  160. */
  161. protected $_minPrice;
  162. /**
  163. * Prise standard deviation (statistics data)
  164. *
  165. * @var float
  166. */
  167. protected $_priceStandardDeviation;
  168. /**
  169. * Prises count (statistics data)
  170. *
  171. * @var int
  172. */
  173. protected $_pricesCount = null;
  174. /**
  175. * Cloned Select after dispatching 'catalog_prepare_price_select' event
  176. *
  177. * @var Varien_Db_Select
  178. */
  179. protected $_catalogPreparePriceSelect = null;
  180. /**
  181. * Get cloned Select after dispatching 'catalog_prepare_price_select' event
  182. *
  183. * @return Varien_Db_Select
  184. */
  185. public function getCatalogPreparedSelect()
  186. {
  187. return $this->_catalogPreparePriceSelect;
  188. }
  189. /**
  190. * Prepare additional price expression sql part
  191. *
  192. * @param Varien_Db_Select $select
  193. * @return Mage_Catalog_Model_Resource_Product_Collection
  194. */
  195. protected function _preparePriceExpressionParameters($select)
  196. {
  197. // prepare response object for event
  198. $response = new Varien_Object();
  199. $response->setAdditionalCalculations(array());
  200. $tableAliases = array_keys($select->getPart(Zend_Db_Select::FROM));
  201. if (in_array(self::INDEX_TABLE_ALIAS, $tableAliases)) {
  202. $table = self::INDEX_TABLE_ALIAS;
  203. } else {
  204. $table = reset($tableAliases);
  205. }
  206. // prepare event arguments
  207. $eventArgs = array(
  208. 'select' => $select,
  209. 'table' => $table,
  210. 'store_id' => $this->getStoreId(),
  211. 'response_object' => $response
  212. );
  213. Mage::dispatchEvent('catalog_prepare_price_select', $eventArgs);
  214. $additional = join('', $response->getAdditionalCalculations());
  215. $this->_priceExpression = $table . '.min_price';
  216. $this->_additionalPriceExpression = $additional;
  217. $this->_catalogPreparePriceSelect = clone $select;
  218. return $this;
  219. }
  220. /**
  221. * Get price expression sql part
  222. *
  223. * @param Varien_Db_Select $select
  224. * @return string
  225. */
  226. public function getPriceExpression($select)
  227. {
  228. if (is_null($this->_priceExpression)) {
  229. $this->_preparePriceExpressionParameters($select);
  230. }
  231. return $this->_priceExpression;
  232. }
  233. /**
  234. * Get additional price expression sql part
  235. *
  236. * @param Varien_Db_Select $select
  237. * @return string
  238. */
  239. public function getAdditionalPriceExpression($select)
  240. {
  241. if (is_null($this->_additionalPriceExpression)) {
  242. $this->_preparePriceExpressionParameters($select);
  243. }
  244. return $this->_additionalPriceExpression;
  245. }
  246. /**
  247. * Get currency rate
  248. *
  249. * @return float
  250. */
  251. public function getCurrencyRate()
  252. {
  253. return Mage::app()->getStore($this->getStoreId())->getCurrentCurrencyRate();
  254. }
  255. /**
  256. * Retrieve Catalog Product Flat Helper object
  257. *
  258. * @return Mage_Catalog_Helper_Product_Flat
  259. */
  260. public function getFlatHelper()
  261. {
  262. return Mage::helper('Mage_Catalog_Helper_Product_Flat');
  263. }
  264. /**
  265. * Retrieve is flat enabled flag
  266. * Return always false if magento run admin
  267. *
  268. * @return bool
  269. */
  270. public function isEnabledFlat()
  271. {
  272. // Flat Data can be used only on frontend
  273. if (Mage::app()->getStore()->isAdmin()) {
  274. return false;
  275. }
  276. if (!isset($this->_flatEnabled[$this->getStoreId()])) {
  277. $this->_flatEnabled[$this->getStoreId()] = $this->getFlatHelper()->isAvailable();
  278. }
  279. return $this->_flatEnabled[$this->getStoreId()];
  280. }
  281. /**
  282. * Initialize resources
  283. *
  284. */
  285. protected function _construct()
  286. {
  287. if ($this->isEnabledFlat()) {
  288. $this->_init('Mage_Catalog_Model_Product', 'Mage_Catalog_Model_Resource_Product_Flat');
  289. } else {
  290. $this->_init('Mage_Catalog_Model_Product', 'Mage_Catalog_Model_Resource_Product');
  291. }
  292. $this->_initTables();
  293. }
  294. /**
  295. * Standard resource collection initalization
  296. * Needed for child classes
  297. *
  298. * @param string $model
  299. * @param string $entityModel
  300. * @return Mage_Catalog_Model_Resource_Product_Collection
  301. */
  302. protected function _init($model, $entityModel)
  303. {
  304. if ($this->isEnabledFlat()) {
  305. $entityModel = 'Mage_Catalog_Model_Resource_Product_Flat';
  306. }
  307. return parent::_init($model, $entityModel);
  308. }
  309. /**
  310. * Define product website and category product tables
  311. *
  312. */
  313. protected function _initTables()
  314. {
  315. $this->_productWebsiteTable = $this->getResource()->getTable('catalog_product_website');
  316. $this->_productCategoryTable = $this->getResource()->getTable('catalog_category_product');
  317. }
  318. /**
  319. * Prepare static entity fields
  320. *
  321. * @return Mage_Catalog_Model_Resource_Product_Collection
  322. */
  323. protected function _prepareStaticFields()
  324. {
  325. if ($this->isEnabledFlat()) {
  326. return $this;
  327. }
  328. return parent::_prepareStaticFields();
  329. }
  330. /**
  331. * Retrieve collection empty item
  332. * Redeclared for specifying id field name without getting resource model inside model
  333. *
  334. * @return Varien_Object
  335. */
  336. public function getNewEmptyItem()
  337. {
  338. $object = parent::getNewEmptyItem();
  339. if ($this->isEnabledFlat()) {
  340. $object->setIdFieldName($this->getEntity()->getIdFieldName());
  341. }
  342. return $object;
  343. }
  344. /**
  345. * Set entity to use for attributes
  346. *
  347. * @param Mage_Eav_Model_Entity_Abstract $entity
  348. * @return Mage_Catalog_Model_Resource_Product_Collection
  349. */
  350. public function setEntity($entity)
  351. {
  352. if ($this->isEnabledFlat() && ($entity instanceof Mage_Core_Model_Resource_Db_Abstract)) {
  353. $this->_entity = $entity;
  354. return $this;
  355. }
  356. return parent::setEntity($entity);
  357. }
  358. /**
  359. * Set Store scope for collection
  360. *
  361. * @param mixed $store
  362. * @return Mage_Catalog_Model_Resource_Product_Collection
  363. */
  364. public function setStore($store)
  365. {
  366. parent::setStore($store);
  367. if ($this->isEnabledFlat()) {
  368. $this->getEntity()->setStoreId($this->getStoreId());
  369. }
  370. return $this;
  371. }
  372. /**
  373. * Initialize collection select
  374. * Redeclared for remove entity_type_id condition
  375. * in catalog_product_entity we store just products
  376. *
  377. * @return Mage_Catalog_Model_Resource_Product_Collection
  378. */
  379. protected function _initSelect()
  380. {
  381. if ($this->isEnabledFlat()) {
  382. $this->getSelect()
  383. ->from(array(self::MAIN_TABLE_ALIAS => $this->getEntity()->getFlatTableName()), null)
  384. ->columns(array('status' => new Zend_Db_Expr(Mage_Catalog_Model_Product_Status::STATUS_ENABLED)));
  385. $this->addAttributeToSelect(array('entity_id', 'type_id', 'attribute_set_id'));
  386. if ($this->getFlatHelper()->isAddChildData()) {
  387. $this->getSelect()
  388. ->where('e.is_child=?', 0);
  389. $this->addAttributeToSelect(array('child_id', 'is_child'));
  390. }
  391. } else {
  392. $this->getSelect()->from(array(self::MAIN_TABLE_ALIAS => $this->getEntity()->getEntityTable()));
  393. }
  394. return $this;
  395. }
  396. /**
  397. * Load attributes into loaded entities
  398. *
  399. * @param bool $printQuery
  400. * @param bool $logQuery
  401. * @return Mage_Catalog_Model_Resource_Product_Collection
  402. */
  403. public function _loadAttributes($printQuery = false, $logQuery = false)
  404. {
  405. if ($this->isEnabledFlat()) {
  406. return $this;
  407. }
  408. return parent::_loadAttributes($printQuery, $logQuery);
  409. }
  410. /**
  411. * Add attribute to entities in collection
  412. * If $attribute=='*' select all attributes
  413. *
  414. * @param array|string|integer|Mage_Core_Model_Config_Element $attribute
  415. * @param false|string $joinType
  416. * @return Mage_Catalog_Model_Resource_Product_Collection
  417. */
  418. public function addAttributeToSelect($attribute, $joinType = false)
  419. {
  420. if ($this->isEnabledFlat()) {
  421. if (!is_array($attribute)) {
  422. $attribute = array($attribute);
  423. }
  424. foreach ($attribute as $attributeCode) {
  425. if ($attributeCode == '*') {
  426. foreach ($this->getEntity()->getAllTableColumns() as $column) {
  427. $this->getSelect()->columns('e.' . $column);
  428. $this->_selectAttributes[$column] = $column;
  429. $this->_staticFields[$column] = $column;
  430. }
  431. } else {
  432. $columns = $this->getEntity()->getAttributeForSelect($attributeCode);
  433. if ($columns) {
  434. foreach ($columns as $alias => $column) {
  435. $this->getSelect()->columns(array($alias => 'e.' . $column));
  436. $this->_selectAttributes[$column] = $column;
  437. $this->_staticFields[$column] = $column;
  438. }
  439. }
  440. }
  441. }
  442. return $this;
  443. }
  444. return parent::addAttributeToSelect($attribute, $joinType);
  445. }
  446. /**
  447. * Add tax class id attribute to select and join price rules data if needed
  448. *
  449. * @return Mage_Catalog_Model_Resource_Product_Collection
  450. */
  451. protected function _beforeLoad()
  452. {
  453. Mage::dispatchEvent('catalog_product_collection_load_before', array('collection' => $this));
  454. return parent::_beforeLoad();
  455. }
  456. /**
  457. * Processing collection items after loading
  458. * Adding url rewrites, minimal prices, final prices, tax percents
  459. *
  460. * @return Mage_Catalog_Model_Resource_Product_Collection
  461. */
  462. protected function _afterLoad()
  463. {
  464. if ($this->_addUrlRewrite) {
  465. $this->_addUrlRewrite($this->_urlRewriteCategory);
  466. }
  467. $this->_prepareUrlDataObject();
  468. if (count($this) > 0) {
  469. Mage::dispatchEvent('catalog_product_collection_load_after', array('collection' => $this));
  470. }
  471. foreach ($this as $product) {
  472. if ($product->isRecurring() && $profile = $product->getRecurringProfile()) {
  473. $product->setRecurringProfile(unserialize($profile));
  474. }
  475. }
  476. return $this;
  477. }
  478. /**
  479. * Prepare Url Data object
  480. *
  481. * @return Mage_Catalog_Model_Resource_Product_Collection
  482. */
  483. protected function _prepareUrlDataObject()
  484. {
  485. $objects = array();
  486. /** @var $item Mage_Catalog_Model_Product */
  487. foreach ($this->_items as $item) {
  488. if ($this->getFlag('do_not_use_category_id')) {
  489. $item->setDoNotUseCategoryId(true);
  490. }
  491. if (!$item->isVisibleInSiteVisibility() && $item->getItemStoreId()) {
  492. $objects[$item->getEntityId()] = $item->getItemStoreId();
  493. }
  494. }
  495. if ($objects && $this->hasFlag('url_data_object')) {
  496. $objects = Mage::getResourceSingleton('Mage_Catalog_Model_Resource_Url')
  497. ->getRewriteByProductStore($objects);
  498. foreach ($this->_items as $item) {
  499. if (isset($objects[$item->getEntityId()])) {
  500. $object = new Varien_Object($objects[$item->getEntityId()]);
  501. $item->setUrlDataObject($object);
  502. }
  503. }
  504. }
  505. return $this;
  506. }
  507. /**
  508. * Add collection filters by identifiers
  509. *
  510. * @param mixed $productId
  511. * @param boolean $exclude
  512. * @return Mage_Catalog_Model_Resource_Product_Collection
  513. */
  514. public function addIdFilter($productId, $exclude = false)
  515. {
  516. if (empty($productId)) {
  517. $this->_setIsLoaded(true);
  518. return $this;
  519. }
  520. if (is_array($productId)) {
  521. if (!empty($productId)) {
  522. if ($exclude) {
  523. $condition = array('nin' => $productId);
  524. } else {
  525. $condition = array('in' => $productId);
  526. }
  527. } else {
  528. $condition = '';
  529. }
  530. } else {
  531. if ($exclude) {
  532. $condition = array('neq' => $productId);
  533. } else {
  534. $condition = $productId;
  535. }
  536. }
  537. $this->addFieldToFilter('entity_id', $condition);
  538. return $this;
  539. }
  540. /**
  541. * Adding product website names to result collection
  542. * Add for each product websites information
  543. *
  544. * @return Mage_Catalog_Model_Resource_Product_Collection
  545. */
  546. public function addWebsiteNamesToResult()
  547. {
  548. $productWebsites = array();
  549. foreach ($this as $product) {
  550. $productWebsites[$product->getId()] = array();
  551. }
  552. if (!empty($productWebsites)) {
  553. $select = $this->getConnection()->select()
  554. ->from(array('product_website' => $this->_productWebsiteTable))
  555. ->join(
  556. array('website' => $this->getResource()->getTable('core_website')),
  557. 'website.website_id = product_website.website_id',
  558. array('name'))
  559. ->where('product_website.product_id IN (?)', array_keys($productWebsites))
  560. ->where('website.website_id > ?', 0);
  561. $data = $this->getConnection()->fetchAll($select);
  562. foreach ($data as $row) {
  563. $productWebsites[$row['product_id']][] = $row['website_id'];
  564. }
  565. }
  566. foreach ($this as $product) {
  567. if (isset($productWebsites[$product->getId()])) {
  568. $product->setData('websites', $productWebsites[$product->getId()]);
  569. }
  570. }
  571. return $this;
  572. }
  573. /**
  574. * Add store availability filter. Include availability product
  575. * for store website
  576. *
  577. * @param mixed $store
  578. * @return Mage_Catalog_Model_Resource_Product_Collection
  579. */
  580. public function addStoreFilter($store = null)
  581. {
  582. if ($store === null) {
  583. $store = $this->getStoreId();
  584. }
  585. $store = Mage::app()->getStore($store);
  586. if (!$store->isAdmin()) {
  587. $this->setStoreId($store);
  588. $this->_productLimitationFilters['store_id'] = $store->getId();
  589. $this->_applyProductLimitations();
  590. }
  591. return $this;
  592. }
  593. /**
  594. * Add website filter to collection
  595. *
  596. * @param unknown_type $websites
  597. * @return Mage_Catalog_Model_Resource_Product_Collection
  598. */
  599. public function addWebsiteFilter($websites = null)
  600. {
  601. if (!is_array($websites)) {
  602. $websites = array(Mage::app()->getWebsite($websites)->getId());
  603. }
  604. $this->_productLimitationFilters['website_ids'] = $websites;
  605. $this->_applyProductLimitations();
  606. return $this;
  607. }
  608. /**
  609. * Get filters applied to collection
  610. *
  611. * @return array
  612. */
  613. public function getLimitationFilters()
  614. {
  615. return $this->_productLimitationFilters;
  616. }
  617. /**
  618. * Specify category filter for product collection
  619. *
  620. * @param Mage_Catalog_Model_Category $category
  621. * @return Mage_Catalog_Model_Resource_Product_Collection
  622. */
  623. public function addCategoryFilter(Mage_Catalog_Model_Category $category)
  624. {
  625. $this->_productLimitationFilters['category_id'] = $category->getId();
  626. if ($category->getIsAnchor()) {
  627. unset($this->_productLimitationFilters['category_is_anchor']);
  628. } else {
  629. $this->_productLimitationFilters['category_is_anchor'] = 1;
  630. }
  631. if ($this->getStoreId() == Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID) {
  632. $this->_applyZeroStoreProductLimitations();
  633. } else {
  634. $this->_applyProductLimitations();
  635. }
  636. return $this;
  637. }
  638. /**
  639. * Join minimal price attribute to result
  640. *
  641. * @return Mage_Catalog_Model_Resource_Product_Collection
  642. */
  643. public function joinMinimalPrice()
  644. {
  645. $this->addAttributeToSelect('price')
  646. ->addAttributeToSelect('minimal_price');
  647. return $this;
  648. }
  649. /**
  650. * Retrieve max value by attribute
  651. *
  652. * @param string $attribute
  653. * @return mixed
  654. */
  655. public function getMaxAttributeValue($attribute)
  656. {
  657. $select = clone $this->getSelect();
  658. $attribute = $this->getEntity()->getAttribute($attribute);
  659. $attributeCode = $attribute->getAttributeCode();
  660. $tableAlias = $attributeCode . '_max_value';
  661. $fieldAlias = 'max_' . $attributeCode;
  662. $condition = 'e.entity_id = ' . $tableAlias . '.entity_id
  663. AND '.$this->_getConditionSql($tableAlias . '.attribute_id', $attribute->getId());
  664. $select->join(
  665. array($tableAlias => $attribute->getBackend()->getTable()),
  666. $condition,
  667. array($fieldAlias => new Zend_Db_Expr('MAX('.$tableAlias.'.value)'))
  668. )
  669. ->group('e.entity_type_id');
  670. $data = $this->getConnection()->fetchRow($select);
  671. if (isset($data[$fieldAlias])) {
  672. return $data[$fieldAlias];
  673. }
  674. return null;
  675. }
  676. /**
  677. * Retrieve ranging product count for arrtibute range
  678. *
  679. * @param string $attribute
  680. * @param int $range
  681. * @return array
  682. */
  683. public function getAttributeValueCountByRange($attribute, $range)
  684. {
  685. $select = clone $this->getSelect();
  686. $attribute = $this->getEntity()->getAttribute($attribute);
  687. $attributeCode = $attribute->getAttributeCode();
  688. $tableAlias = $attributeCode . '_range_count_value';
  689. $condition = 'e.entity_id = ' . $tableAlias . '.entity_id
  690. AND ' . $this->_getConditionSql($tableAlias . '.attribute_id', $attribute->getId());
  691. $select->reset(Zend_Db_Select::GROUP);
  692. $select->join(
  693. array($tableAlias => $attribute->getBackend()->getTable()),
  694. $condition,
  695. array(
  696. 'count_' . $attributeCode => new Zend_Db_Expr('COUNT(DISTINCT e.entity_id)'),
  697. 'range_' . $attributeCode => new Zend_Db_Expr(
  698. 'CEIL((' . $tableAlias . '.value+0.01)/' . $range . ')')
  699. )
  700. )
  701. ->group('range_' . $attributeCode);
  702. $data = $this->getConnection()->fetchAll($select);
  703. $res = array();
  704. foreach ($data as $row) {
  705. $res[$row['range_' . $attributeCode]] = $row['count_' . $attributeCode];
  706. }
  707. return $res;
  708. }
  709. /**
  710. * Retrieve product count by some value of attribute
  711. *
  712. * @param string $attribute
  713. * @return array($value=>$count)
  714. */
  715. public function getAttributeValueCount($attribute)
  716. {
  717. $select = clone $this->getSelect();
  718. $attribute = $this->getEntity()->getAttribute($attribute);
  719. $attributeCode = $attribute->getAttributeCode();
  720. $tableAlias = $attributeCode . '_value_count';
  721. $select->reset(Zend_Db_Select::GROUP);
  722. $condition = 'e.entity_id=' . $tableAlias . '.entity_id
  723. AND '.$this->_getConditionSql($tableAlias . '.attribute_id', $attribute->getId());
  724. $select->join(
  725. array($tableAlias => $attribute->getBackend()->getTable()),
  726. $condition,
  727. array(
  728. 'count_' . $attributeCode => new Zend_Db_Expr('COUNT(DISTINCT e.entity_id)'),
  729. 'value_' . $attributeCode => new Zend_Db_Expr($tableAlias . '.value')
  730. )
  731. )
  732. ->group('value_' . $attributeCode);
  733. $data = $this->getConnection()->fetchAll($select);
  734. $res = array();
  735. foreach ($data as $row) {
  736. $res[$row['value_' . $attributeCode]] = $row['count_' . $attributeCode];
  737. }
  738. return $res;
  739. }
  740. /**
  741. * Return all attribute values as array in form:
  742. * array(
  743. * [entity_id_1] => array(
  744. * [store_id_1] => store_value_1,
  745. * [store_id_2] => store_value_2,
  746. * ...
  747. * [store_id_n] => store_value_n
  748. * ),
  749. * ...
  750. * )
  751. *
  752. * @param string $attribute attribute code
  753. * @return array
  754. */
  755. public function getAllAttributeValues($attribute)
  756. {
  757. /** @var $select Varien_Db_Select */
  758. $select = clone $this->getSelect();
  759. $attribute = $this->getEntity()->getAttribute($attribute);
  760. $select->reset()
  761. ->from($attribute->getBackend()->getTable(), array('entity_id', 'store_id', 'value'))
  762. ->where('attribute_id = ?', (int)$attribute->getId());
  763. $data = $this->getConnection()->fetchAll($select);
  764. $res = array();
  765. foreach ($data as $row) {
  766. $res[$row['entity_id']][$row['store_id']] = $row['value'];
  767. }
  768. return $res;
  769. }
  770. /**
  771. * Get SQL for get record count without left JOINs
  772. *
  773. * @return Varien_Db_Select
  774. */
  775. public function getSelectCountSql()
  776. {
  777. return $this->_getSelectCountSql();
  778. }
  779. /**
  780. * Get SQL for get record count
  781. *
  782. * @param bool $resetLeftJoins
  783. * @return Varien_Db_Select
  784. */
  785. protected function _getSelectCountSql($select = null, $resetLeftJoins = true)
  786. {
  787. $this->_renderFilters();
  788. $countSelect = (is_null($select)) ?
  789. $this->_getClearSelect() :
  790. $this->_buildClearSelect($select);
  791. $countSelect->columns('COUNT(DISTINCT e.entity_id)');
  792. if ($resetLeftJoins) {
  793. $countSelect->resetJoinLeft();
  794. }
  795. return $countSelect;
  796. }
  797. /**
  798. * Prepare statistics data
  799. *
  800. * @return Mage_Catalog_Model_Resource_Product_Collection
  801. */
  802. protected function _prepareStatisticsData()
  803. {
  804. $select = clone $this->getSelect();
  805. $priceExpression = $this->getPriceExpression($select) . ' ' . $this->getAdditionalPriceExpression($select);
  806. $sqlEndPart = ') * ' . $this->getCurrencyRate() . ', 2)';
  807. $select = $this->_getSelectCountSql($select, false);
  808. $select->columns(array(
  809. 'max' => 'ROUND(MAX(' . $priceExpression . $sqlEndPart,
  810. 'min' => 'ROUND(MIN(' . $priceExpression . $sqlEndPart,
  811. 'std' => $this->getConnection()->getStandardDeviationSql('ROUND((' . $priceExpression . $sqlEndPart)
  812. ));
  813. $select->where($this->getPriceExpression($select) . ' IS NOT NULL');
  814. $row = $this->getConnection()->fetchRow($select, $this->_bindParams, Zend_Db::FETCH_NUM);
  815. $this->_pricesCount = (int)$row[0];
  816. $this->_maxPrice = (float)$row[1];
  817. $this->_minPrice = (float)$row[2];
  818. $this->_priceStandardDeviation = (float)$row[3];
  819. return $this;
  820. }
  821. /**
  822. * Retreive clear select
  823. *
  824. * @return Varien_Db_Select
  825. */
  826. protected function _getClearSelect()
  827. {
  828. return $this->_buildClearSelect();
  829. }
  830. /**
  831. * Build clear select
  832. *
  833. * @param Varien_Db_Select $select
  834. * @return Varien_Db_Select
  835. */
  836. protected function _buildClearSelect($select = null)
  837. {
  838. if (is_null($select)) {
  839. $select = clone $this->getSelect();
  840. }
  841. $select->reset(Zend_Db_Select::ORDER);
  842. $select->reset(Zend_Db_Select::LIMIT_COUNT);
  843. $select->reset(Zend_Db_Select::LIMIT_OFFSET);
  844. $select->reset(Zend_Db_Select::COLUMNS);
  845. return $select;
  846. }
  847. /**
  848. * Retrive all ids for collection
  849. *
  850. * @param unknown_type $limit
  851. * @param unknown_type $offset
  852. * @return array
  853. */
  854. public function getAllIds($limit = null, $offset = null)
  855. {
  856. $idsSelect = $this->_getClearSelect();
  857. $idsSelect->columns('e.' . $this->getEntity()->getIdFieldName());
  858. $idsSelect->limit($limit, $offset);
  859. $idsSelect->resetJoinLeft();
  860. return $this->getConnection()->fetchCol($idsSelect, $this->_bindParams);
  861. }
  862. /**
  863. * Retreive product count select for categories
  864. *
  865. * @return Varien_Db_Select
  866. */
  867. public function getProductCountSelect()
  868. {
  869. if ($this->_productCountSelect === null) {
  870. $this->_productCountSelect = clone $this->getSelect();
  871. $this->_productCountSelect->reset(Zend_Db_Select::COLUMNS)
  872. ->reset(Zend_Db_Select::GROUP)
  873. ->reset(Zend_Db_Select::ORDER)
  874. ->distinct(false)
  875. ->join(array('count_table' => $this->getTable('catalog_category_product_index')),
  876. 'count_table.product_id = e.entity_id',
  877. array(
  878. 'count_table.category_id',
  879. 'product_count' => new Zend_Db_Expr('COUNT(DISTINCT count_table.product_id)')
  880. )
  881. )
  882. ->where('count_table.store_id = ?', $this->getStoreId())
  883. ->group('count_table.category_id');
  884. }
  885. return $this->_productCountSelect;
  886. }
  887. /**
  888. * Destruct product count select
  889. *
  890. * @return Mage_Catalog_Model_Resource_Product_Collection
  891. */
  892. public function unsProductCountSelect()
  893. {
  894. $this->_productCountSelect = null;
  895. return $this;
  896. }
  897. /**
  898. * Adding product count to categories collection
  899. *
  900. * @param Mage_Eav_Model_Entity_Collection_Abstract $categoryCollection
  901. * @return Mage_Catalog_Model_Resource_Product_Collection
  902. */
  903. public function addCountToCategories($categoryCollection)
  904. {
  905. $isAnchor = array();
  906. $isNotAnchor = array();
  907. foreach ($categoryCollection as $category) {
  908. if ($category->getIsAnchor()) {
  909. $isAnchor[] = $category->getId();
  910. } else {
  911. $isNotAnchor[] = $category->getId();
  912. }
  913. }
  914. $productCounts = array();
  915. if ($isAnchor || $isNotAnchor) {
  916. $select = $this->getProductCountSelect();
  917. Mage::dispatchEvent(
  918. 'catalog_product_collection_before_add_count_to_categories',
  919. array('collection' => $this)
  920. );
  921. if ($isAnchor) {
  922. $anchorStmt = clone $select;
  923. $anchorStmt->limit(); //reset limits
  924. $anchorStmt->where('count_table.category_id IN (?)', $isAnchor);
  925. $productCounts += $this->getConnection()->fetchPairs($anchorStmt);
  926. $anchorStmt = null;
  927. }
  928. if ($isNotAnchor) {
  929. $notAnchorStmt = clone $select;
  930. $notAnchorStmt->limit(); //reset limits
  931. $notAnchorStmt->where('count_table.category_id IN (?)', $isNotAnchor);
  932. $notAnchorStmt->where('count_table.is_parent = 1');
  933. $productCounts += $this->getConnection()->fetchPairs($notAnchorStmt);
  934. $notAnchorStmt = null;
  935. }
  936. $select = null;
  937. $this->unsProductCountSelect();
  938. }
  939. foreach ($categoryCollection as $category) {
  940. $_count = 0;
  941. if (isset($productCounts[$category->getId()])) {
  942. $_count = $productCounts[$category->getId()];
  943. }
  944. $category->setProductCount($_count);
  945. }
  946. return $this;
  947. }
  948. /**
  949. * Retrieve unique attribute set ids in collection
  950. *
  951. * @return array
  952. */
  953. public function getSetIds()
  954. {
  955. $select = clone $this->getSelect();
  956. /** @var $select Varien_Db_Select */
  957. $select->reset(Zend_Db_Select::COLUMNS);
  958. $select->distinct(true);
  959. $select->columns('attribute_set_id');
  960. return $this->getConnection()->fetchCol($select);
  961. }
  962. /**
  963. * Return array of unique product type ids in collection
  964. *
  965. * @return array
  966. */
  967. public function getProductTypeIds()
  968. {
  969. $select = clone $this->getSelect();
  970. /** @var $select Varien_Db_Select */
  971. $select->reset(Zend_Db_Select::COLUMNS);
  972. $select->distinct(true);
  973. $select->columns('type_id');
  974. return $this->getConnection()->fetchCol($select);
  975. }
  976. /**
  977. * Joins url rewrite rules to collection
  978. *
  979. * @return Mage_Catalog_Model_Resource_Product_Collection
  980. */
  981. public function joinUrlRewrite()
  982. {
  983. $this->joinTable(
  984. 'core_url_rewrite',
  985. 'entity_id=entity_id',
  986. array('request_path'),
  987. '{{table}}.type = ' . Mage_Core_Model_Url_Rewrite::TYPE_PRODUCT,
  988. 'left'
  989. );
  990. return $this;
  991. }
  992. /**
  993. * Add URL rewrites data to product
  994. * If collection loadded - run processing else set flag
  995. *
  996. * @param int $categoryId
  997. * @return Mage_Catalog_Model_Resource_Product_Collection
  998. */
  999. public function addUrlRewrite($categoryId = '')
  1000. {
  1001. $this->_addUrlRewrite = true;
  1002. if (Mage::getStoreConfig(Mage_Catalog_Helper_Product::XML_PATH_PRODUCT_URL_USE_CATEGORY, $this->getStoreId())) {
  1003. $this->_urlRewriteCategory = $categoryId;
  1004. } else {
  1005. $this->_urlRewriteCategory = 0;
  1006. }
  1007. if ($this->isLoaded()) {
  1008. $this->_addUrlRewrite();
  1009. }
  1010. return $this;
  1011. }
  1012. /**
  1013. * Add URL rewrites to collection
  1014. *
  1015. */
  1016. protected function _addUrlRewrite()
  1017. {
  1018. $urlRewrites = null;
  1019. if ($this->_cacheConf) {
  1020. if (!($urlRewrites = Mage::app()->loadCache($this->_cacheConf['prefix'] . 'urlrewrite'))) {
  1021. $urlRewrites = null;
  1022. } else {
  1023. $urlRewrites = unserialize($urlRewrites);
  1024. }
  1025. }
  1026. if (!$urlRewrites) {
  1027. $productIds = array();
  1028. foreach($this->getItems() as $item) {
  1029. $productIds[] = $item->getEntityId();
  1030. }
  1031. if (!count($productIds)) {
  1032. return;
  1033. }
  1034. $select = $this->getConnection()->select()
  1035. ->from($this->getTable('core_url_rewrite'), array('product_id', 'request_path'))
  1036. ->where('store_id = ?', Mage::app()->getStore()->getId())
  1037. ->where('is_system = ?', 1)
  1038. ->where('category_id = ? OR category_id IS NULL', $this->_urlRewriteCategory)
  1039. ->where('product_id IN(?)', $productIds)
  1040. ->order('category_id ' . self::SORT_ORDER_DESC); // more priority is data with category id
  1041. $urlRewrites = array();
  1042. foreach ($this->getConnection()->fetchAll($select) as $row) {
  1043. if (!isset($urlRewrites[$row['product_id']])) {
  1044. $urlRewrites[$row['product_id']] = $row['request_path'];
  1045. }
  1046. }
  1047. if ($this->_cacheConf) {
  1048. Mage::app()->saveCache(
  1049. serialize($urlRewrites),
  1050. $this->_cacheConf['prefix'] . 'urlrewrite',
  1051. array_merge($this->_cacheConf['tags'], array(Mage_Catalog_Model_Product_Url::CACHE_TAG)),
  1052. $this->_cacheLifetime
  1053. );
  1054. }
  1055. }
  1056. foreach($this->getItems() as $item) {
  1057. if (isset($urlRewrites[$item->getEntityId()])) {
  1058. $item->setData('request_path', $urlRewrites[$item->getEntityId()]);
  1059. } else {
  1060. $item->setData('request_path', false);
  1061. }
  1062. }
  1063. }
  1064. /**
  1065. * Add minimal price data to result
  1066. *
  1067. * @return Mage_Catalog_Model_Resource_Product_Collection
  1068. */
  1069. public function addMinimalPrice()
  1070. {
  1071. return $this->addPriceData();
  1072. }
  1073. /**
  1074. * Add price data for calculate final price
  1075. *
  1076. * @return Mage_Catalog_Model_Resource_Product_Collection
  1077. */
  1078. public function addFinalPrice()
  1079. {
  1080. return $this->addPriceData();
  1081. }
  1082. /**
  1083. * Join prices from price rules to products collection
  1084. *
  1085. * @return Mage_Catalog_Model_Resource_Product_Collection
  1086. */
  1087. protected function _joinPriceRules()
  1088. {
  1089. if ($this->isEnabledFlat()) {
  1090. $customerGroup = Mage::getSingleton('Mage_Customer_Model_Session')->getCustomerGroupId();
  1091. $priceColumn = 'e.display_price_group_' . $customerGroup;
  1092. $this->getSelect()->columns(array('_rule_price' => $priceColumn));
  1093. return $this;
  1094. }
  1095. if (!Mage::helper('Mage_Catalog_Helper_Data')->isModuleEnabled('Mage_CatalogRule')) {
  1096. return $this;
  1097. }
  1098. $wId = Mage::app()->getWebsite()->getId();
  1099. $gId = Mage::getSingleton('Mage_Customer_Model_Session')->getCustomerGroupId();
  1100. $storeDate = Mage::app()->getLocale()->storeTimeStamp($this->getStoreId());
  1101. $conditions = 'price_rule.product_id = e.entity_id AND ';
  1102. $conditions .= "price_rule.rule_date = '".$this->getResource()->formatDate($storeDate, false)."' AND ";
  1103. $conditions .= $this->getConnection()->quoteInto('price_rule.website_id = ? AND', $wId);
  1104. $conditions .= $this->getConnection()->quoteInto('price_rule.customer_group_id = ?', $gId);
  1105. $this->getSelect()->joinLeft(
  1106. array('price_rule' => $this->getTable('catalogrule_product_price')),
  1107. $conditions,
  1108. array('rule_price' => 'rule_price')
  1109. );
  1110. return $this;
  1111. }
  1112. /**
  1113. * Retreive all ids
  1114. *
  1115. * @param boolean $resetCache
  1116. * @return array
  1117. */
  1118. public function getAllIdsCache($resetCache = false)
  1119. {
  1120. $ids = null;
  1121. if (!$resetCache) {
  1122. $ids = $this->_allIdsCache;
  1123. }
  1124. if (is_null($ids)) {
  1125. $ids = $this->getAllIds();
  1126. $this->setAllIdsCache($ids);
  1127. }
  1128. return $ids;
  1129. }
  1130. /**
  1131. * Set all ids
  1132. *
  1133. * @param array $value
  1134. * @return Mage_Catalog_Model_Resource_Product_Collection
  1135. */
  1136. public function setAllIdsCache($value)
  1137. {
  1138. $this->_allIdsCache = $value;
  1139. return $this;
  1140. }
  1141. /**
  1142. * Add Price Data to result
  1143. *
  1144. * @param int $customerGroupId
  1145. * @param int $websiteId
  1146. * @return Mage_Catalog_Model_Resource_Product_Collection
  1147. */
  1148. public function addPriceData($customerGroupId = null, $websiteId = null)
  1149. {
  1150. $this->_productLimitationFilters['use_price_index'] = true;
  1151. if (!isset($this->_productLimitationFilters['customer_group_id']) && is_null($customerGroupId)) {
  1152. $customerGroupId = Mage::getSingleton('Mage_Customer_Model_Session')->getCustomerGroupId();
  1153. }
  1154. if (!isset($this->_productLimitationFilters['website_id']) && is_null($websiteId)) {
  1155. $websiteId = Mage::app()->getStore($this->getStoreId())->getWebsiteId();
  1156. }
  1157. if (!is_null($customerGroupId)) {
  1158. $this->_productLimitationFilters['customer_group_id'] = $customerGroupId;
  1159. }
  1160. if (!is_null($websiteId)) {
  1161. $this->_productLimitationFilters['website_id'] = $websiteId;
  1162. }
  1163. $this->_applyProductLimitations();
  1164. return $this;
  1165. }
  1166. /**
  1167. * Add attribute to filter
  1168. *
  1169. * @param Mage_Eav_Model_Entity_Attribute_Abstract|string $attribute
  1170. * @param array $condition
  1171. * @param string $joinType
  1172. * @return Mage_Catalog_Model_Resource_Product_Collection
  1173. */
  1174. public function addAttributeToFilter($attribute, $condition = null, $joinType = 'inner')
  1175. {
  1176. if ($this->isEnabledFlat()) {
  1177. if ($attribute instanceof Mage_Eav_Model_Entity_Attribute_Abstract) {
  1178. $attribute = $attribute->getAttributeCode();
  1179. }
  1180. if (is_array($attribute)) {
  1181. $sqlArr = array();
  1182. foreach ($attribute as $condition) {
  1183. $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType);
  1184. }
  1185. $conditionSql = '('.join(') OR (', $sqlArr).')';
  1186. $this->getSelect()->where($conditionSql);
  1187. return $this;
  1188. }
  1189. if (!isset($this->_selectAttributes[$attribute])) {
  1190. $this->addAttributeToSelect($attribute);
  1191. }
  1192. if (isset($this->_selectAttributes[$attribute])) {
  1193. $this->getSelect()->where($this->_getConditionSql('e.' . $attribute, $condition));
  1194. }
  1195. return $this;
  1196. }
  1197. $this->_allIdsCache = null;
  1198. if (is_string($attribute) && $attribute == 'is_saleable') {
  1199. $columns = $this->getSelect()->getPart(Zend_Db_Select::COLUMNS);
  1200. foreach ($columns as $columnEntry) {
  1201. list($correlationName, $column, $alias) = $columnEntry;
  1202. if ($alias == 'is_saleable') {
  1203. if ($column instanceof Zend_Db_Expr) {
  1204. $field = $column;
  1205. } else {
  1206. $adapter = $this->getSelect()->getAdapter();
  1207. if (empty($correlationName)) {
  1208. $field = $adapter->quoteColumnAs($column, $alias, true);
  1209. } else {
  1210. $field = $adapter->quoteColumnAs(array($correlationName, $column), $alias, true);
  1211. }
  1212. }
  1213. $this->getSelect()->where("{$field} = ?", $condition);
  1214. break;
  1215. }
  1216. }
  1217. return $this;
  1218. } else {
  1219. return parent::addAttributeToFilter($attribute, $condition, $joinType);
  1220. }
  1221. }
  1222. /**
  1223. * Add requere tax percent flag for product collection
  1224. *
  1225. * @return Mage_Catalog_Model_Resource_Product_Collection
  1226. */
  1227. public function addTaxPercents()
  1228. {
  1229. $this->_addTaxPercents = true;
  1230. return $this;
  1231. }
  1232. /**
  1233. * Get require tax percent flag value
  1234. *
  1235. * @return bool
  1236. */
  1237. public function requireTaxPercent()
  1238. {
  1239. return $this->_addTaxPercents;
  1240. }
  1241. /**
  1242. * Adding product custom options to result collection
  1243. *
  1244. * @return Mage_Catalog_Model_Resource_Product_Collection
  1245. */
  1246. public function addOptionsToResult()
  1247. {
  1248. $productIds = array();
  1249. foreach ($this as $product) {
  1250. $productIds[] = $product->getId();
  1251. }
  1252. if (!empty($productIds)) {
  1253. $options = Mage::getModel('Mage_Catalog_Model_Product_Option')
  1254. ->getCollection()
  1255. ->addTitleToResult(Mage::app()->getStore()->getId())
  1256. ->addPriceToResult(Mage::app()->getStore()->getId())
  1257. ->addProductToFilter($productIds)
  1258. ->addValuesToResult();
  1259. foreach ($options as $option) {
  1260. if($this->getItemById($option->getProductId())) {
  1261. $this->getItemById($option->getProductId())->addOption($option);
  1262. }
  1263. }
  1264. }
  1265. return $this;
  1266. }
  1267. /**
  1268. * Filter products with required options
  1269. *
  1270. * @return Mage_Catalog_Model_Resource_Product_Collection
  1271. */
  1272. public function addFilterByRequiredOptions()
  1273. {
  1274. $this->addAttributeToFilter('required_options', array(array('neq' => '1'), array('null' => true)), 'left');
  1275. return $this;
  1276. }
  1277. /**
  1278. * Set product visibility filter for enabled products
  1279. *
  1280. * @param array $visibility
  1281. * @return Mage_Catalog_Model_Resource_Product_Collection
  1282. */
  1283. public function setVisibility($visibility)
  1284. {
  1285. $this->_productLimitationFilters['visibility'] = $visibility;
  1286. $this->_applyProductLimitations();
  1287. return $this;
  1288. }
  1289. /**
  1290. * Add attribute to sort order
  1291. *
  1292. * @param string $attribute
  1293. * @param string $dir
  1294. * @return Mage_Catalog_Model_Resource_Product_Collection
  1295. */
  1296. public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC)
  1297. {
  1298. if ($attribute == 'position') {
  1299. if (isset($this->_joinFields[$attribute])) {
  1300. $this->getSelect()->order($this->_getAttributeFieldName($attribute) . ' ' . $dir);
  1301. return $this;
  1302. }
  1303. if ($this->isEnabledFlat()) {
  1304. $this->getSelect()->order("cat_index_position {$dir}");
  1305. }
  1306. // optimize if using cat index
  1307. $filters = $this->_productLimitationFilters;
  1308. if (isset($filters['category_id']) || isset($filters['visibility'])) {
  1309. $this->getSelect()->order('cat_index.position ' . $dir);
  1310. } else {
  1311. $this->getSelect()->order('e.entity_id ' . $dir);
  1312. }
  1313. return $this;
  1314. } elseif($attribute == 'is_saleable'){
  1315. $this->getSelect()->order("is_saleable " . $dir);
  1316. return $this;
  1317. }
  1318. $storeId = $this->getStoreId();
  1319. if ($attribute == 'price' && $storeId != 0) {
  1320. $this->addPriceData();
  1321. $this->getSelect()->order("price_index.min_price {$dir}");
  1322. return $this;
  1323. }
  1324. if ($this->isEnabledFlat()) {
  1325. $column = $this->getEntity()->getAttributeSortColumn($attribute);
  1326. if ($column) {
  1327. $this->getSelect()->order("e.{$column} {$dir}");
  1328. }
  1329. else if (isset($this->_joinFields[$attribute])) {
  1330. $this->getSelect()->order($this->_getAttributeFieldName($attribute) . ' ' . $dir);
  1331. }
  1332. return $this;
  1333. } else {
  1334. $attrInstance = $this->getEntity()->getAttribute($attribute);
  1335. if ($attrInstance && $attrInstance->usesSource()) {
  1336. $attrInstance->getSource()
  1337. ->addValueSortToCollection($this, $dir);
  1338. return $this;
  1339. }
  1340. }
  1341. return parent::addAttributeToSort($attribute, $dir);
  1342. }
  1343. /**
  1344. * Prepare limitation filters
  1345. *
  1346. * @return Mage_Catalog_Model_Resource_Product_Collection
  1347. */
  1348. protected function _prepareProductLimitationFilters()
  1349. {
  1350. if (isset($this->_productLimitationFilters['visibility'])
  1351. && !isset($this->_productLimitationFilters['store_id'])
  1352. ) {
  1353. $this->_productLimitationFilters['store_id'] = $this->getStoreId();
  1354. }
  1355. if (isset($this->_productLimitationFilters['category_id'])
  1356. && !isset($this->_productLimitationFilters['store_id'])
  1357. ) {
  1358. $this->_productLimitationFilters['store_id'] = $this->getStoreId();
  1359. }
  1360. if (isset($this->_productLimitationFilters['store_id'])
  1361. && isset($this->_productLimitationFilters['visibility'])
  1362. && !isset($this->_productLimitationFilters['category_id'])
  1363. ) {
  1364. $this->_productLimitationFilters['category_id'] = Mage::app()
  1365. ->getStore($this->_productLimitationFilters['store_id'])
  1366. ->getRootCategoryId();
  1367. }
  1368. return $this;
  1369. }
  1370. /**
  1371. * Join website product limitation
  1372. *
  1373. * @return Mage_Catalog_Model_Resource_Product_Collection
  1374. */
  1375. protected function _productLimitationJoinWebsite()
  1376. {
  1377. $joinWebsite = false;
  1378. $filters = $this->_productLimitationFilters;
  1379. $conditions = array('product_website.product_id = e.entity_id');
  1380. if (isset($filters['website_ids'])) {
  1381. $joinWebsite = true;
  1382. if (count($filters['website_ids']) > 1) {
  1383. $this->getSelect()->distinct(true);
  1384. }
  1385. $conditions[] = $this->getConnection()
  1386. ->quoteInto('product_website.website_id IN(?)', $filters['website_ids']);
  1387. } elseif (isset($filters['store_id'])
  1388. && (!isset($filters['visibility']) && !isset($filters['category_id']))
  1389. && !$this->isEnabledFlat()
  1390. ) {
  1391. $joinWebsite = true;
  1392. $websiteId = Mage::app()->getStore($filters['store_id'])->getWebsiteId();
  1393. $conditions[] = $this->getConnection()
  1394. ->quoteInto('product_website.website_id = ?', $websiteId);
  1395. }
  1396. $fromPart = $this->getSelect()->getPart(Zend_Db_Select::FROM);
  1397. if (isset($fromPart['product_website'])) {
  1398. if (!$joinWebsite) {
  1399. unset($fromPart['product_website']);
  1400. } else {
  1401. $fromPart['product_website']['joinCondition'] = join(' AND ', $conditions);
  1402. }
  1403. $this->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart);
  1404. } elseif ($joinWebsite) {
  1405. $this->getSelect()->join(
  1406. array('product_website' => $this->getTable('catalog_product_website')),
  1407. join(' AND ', $conditions),
  1408. array()
  1409. );
  1410. }
  1411. return $this;
  1412. }
  1413. /**
  1414. * Join additional (alternative) store visibility filter
  1415. *
  1416. * @return Mage_Catalog_Model_Resource_Product_Collection
  1417. */
  1418. protected function _productLimitationJoinStore()
  1419. {
  1420. $filters = $this->_productLimitationFilters;
  1421. if (!isset($filters['store_table'])) {
  1422. return $this;
  1423. }
  1424. $hasColumn = false;
  1425. foreach ($this->getSelect()->getPa

Large files files are truncated, but you can click here to view the full file