Last active
April 30, 2020 06:39
-
-
Save Vinai/df2efe00c5f5ea12e45e to your computer and use it in GitHub Desktop.
Helper to preload all simple products and configurable attributes for a product collection containing configurable products.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class VinaiKopp_ProductList_Helper_Data extends Mage_Core_Helper_Abstract | |
{ | |
/** | |
* Base product collection to work on | |
* | |
* @var Mage_Catalog_Model_Resource_Product_Collection | |
*/ | |
protected $_productCollection; | |
/** | |
* Array of the ids of configurable products from $_productCollection | |
* | |
* @var array | |
*/ | |
protected $_configurableProductIds; | |
/** | |
* All associated simple products from configurables in $_configurableProductIds | |
* | |
* @var Mage_Catalog_Model_Resource_Product_Type_Configurable_Product_Collection | |
*/ | |
protected $_simpleProducts; | |
/** | |
* Array of associated simple product ids. | |
* The array index are configurable product ids, the array values are | |
* arrays of the associated simple product ids. | |
* | |
* @var array | |
*/ | |
protected $_associatedSimpleProducts; | |
/** | |
* Array keys are the configurable product ids, | |
* the values are configurable attribute ids | |
* | |
* @var array | |
*/ | |
protected $_configurableProductAttributes; | |
/** | |
* Array of all configurable attribute codes used in the current collection. | |
* No association of which product used which configurable attributes. | |
* | |
* @var array | |
*/ | |
protected $_configurableAttributeCodes; | |
/** | |
* Set the product collection. | |
* If not specified defaults to the product collection of the layer model. | |
* | |
* @param Mage_Catalog_Model_Resource_Product_Collection $collection | |
* @return $this | |
*/ | |
public function setProductCollection(Mage_Catalog_Model_Resource_Product_Collection $collection) | |
{ | |
$this->_productCollection = $collection; | |
return $this; | |
} | |
/** | |
* Return the attribute values of the associated simple products | |
* | |
* @param Mage_Catalog_Model_Product $product Configurable product | |
* @param int|Mage_Core_Model_Store $store | |
* @return array | |
*/ | |
public function getProductConfigurableAttributes(Mage_Catalog_Model_Product $product, $store = null) | |
{ | |
if ($product->getTypeId() != Mage_Catalog_Model_Product_Type_Configurable::TYPE_CODE) { | |
return array(); | |
} | |
$storeId = Mage::app()->getStore($store)->getId(); | |
$usedProducts = $this->_getAssociatedSimpleProducts($product); | |
if (! $usedProducts) { | |
// This will happen if two configurable products share the same simple product | |
// The second configurable product will be skipped | |
return array(); | |
} | |
$attributeIds = $this->_getProductConfigurableAttributeIds($product); | |
$allAttributeCodes = $this->_getConfigurableAttributeCodes(); | |
$data = array(); | |
foreach ($attributeIds as $attributeId) { | |
$code = $allAttributeCodes[$attributeId]; | |
$sourceModel = Mage::getSingleton('eav/config') | |
->getAttribute('catalog_product', $code) | |
->setStoreId($storeId) | |
->getSource(); | |
foreach ($usedProducts as $simpleProduct) { | |
// check if the attribute is set in case it isn't set to be used in product listing | |
if (isset($simpleProduct[$code])) { | |
$value = $simpleProduct[$code]; | |
$data[$code][$value] = $sourceModel->getOptionText($value); | |
} | |
} | |
} | |
return $data; | |
} | |
/** | |
* Return array of configurable attribute ids of the given configurable product | |
* | |
* @param Mage_Catalog_Model_Product $product | |
* @return array | |
*/ | |
protected function _getProductConfigurableAttributeIds(Mage_Catalog_Model_Product $product) | |
{ | |
$attributes = $this->_getConfigurableProductAttributes(); | |
$productId = $product->getId(); | |
if (! isset($attributes[$productId])) { | |
Mage::throwException( | |
$this->__('Product %d is not part of the current product collection', $product->getId()) | |
); | |
} | |
return explode(',', $attributes[$productId]); | |
} | |
/** | |
* Load all configurable attributes used in the current product collection | |
* | |
* @return array | |
*/ | |
protected function _getConfigurableProductAttributes() | |
{ | |
if (! $this->_configurableProductAttributes) { | |
$productIds = $this->_getConfigurableProductIds(); | |
$attributes = $this->_getConfigurableAttributesForProductsFromResource($productIds); | |
$this->_configurableProductAttributes = $attributes; | |
} | |
return $this->_configurableProductAttributes; | |
} | |
/** | |
* This method actually would belong into a resource model, but for easier | |
* reference I dropped it into the helper here. | |
* | |
* @param array $productIds | |
* @return array | |
*/ | |
protected function _getConfigurableAttributesForProductsFromResource(array $productIds) | |
{ | |
/** @var Mage_Core_Model_Resource_Helper_Mysql4 $resourceHelper */ | |
$resourceHelper = Mage::getResourceHelper('core'); | |
$resource = Mage::getSingleton('core/resource'); | |
$adapter = $resource->getConnection('catalog_read'); | |
$select = $adapter->select() | |
->from($resource->getTableName('catalog/product_super_attribute'), array('product_id')) | |
->group('product_id') | |
->where('product_id IN(?)', $productIds); | |
$resourceHelper->addGroupConcatColumn($select, 'attribute_ids', 'attribute_id'); | |
$attributes = $adapter->fetchPairs($select); | |
return $attributes; | |
} | |
/** | |
* Return array of all configurable attributes in the current collection. | |
* Array indexes are the attribute ids, array values the attribute code | |
* | |
* @return array | |
*/ | |
protected function _getConfigurableAttributeCodes() | |
{ | |
if (is_null($this->_configurableAttributeCodes)) { | |
// build list of all configurable attribute codes for the current collection | |
$this->_configurableAttributeCodes = array(); | |
foreach ($this->_getConfigurableProductAttributes() as $attributes) { | |
$attributes = explode(',', $attributes); | |
foreach ($attributes as $attributeId) { | |
if ($attributeId && ! isset($this->_configurableAttributeCodes[$attributeId])) { | |
$attributeModel = Mage::getSingleton('eav/config') | |
->getAttribute('catalog_product', $attributeId); | |
$this->_configurableAttributeCodes[$attributeId] = $attributeModel->getAttributeCode(); | |
} | |
} | |
} | |
} | |
return $this->_configurableAttributeCodes; | |
} | |
/** | |
* Return the current product collection | |
* | |
* @return Mage_Catalog_Model_Resource_Product_Collection | |
*/ | |
protected function _getProductCollection() | |
{ | |
if (! $this->_productCollection) { | |
$this->_productCollection = Mage::getSingleton('catalog/layer')->getProductCollection(); | |
}; | |
return $this->_productCollection; | |
} | |
/** | |
* Return array of ids of configurable products in the current product collection | |
* | |
* @return array | |
*/ | |
protected function _getConfigurableProductIds() | |
{ | |
if (is_null($this->_configurableProductIds)) { | |
$this->_configurableProductIds = array(); | |
$products = $this->_getProductCollection(); | |
foreach ($products as $product) { | |
if ($product->getTypeId() == Mage_Catalog_Model_Product_Type_Configurable::TYPE_CODE) { | |
$this->_configurableProductIds[] = $product->getId(); | |
} | |
} | |
} | |
return $this->_configurableProductIds; | |
} | |
/** | |
* Return all associated simple products for the configurable products in | |
* the current product collection. | |
* Array key is the configurable product | |
* | |
* @return array | |
*/ | |
protected function _getSimpleProducts() | |
{ | |
if (is_null($this->_simpleProducts)) { | |
$parentIds = $this->_getConfigurableProductIds(); | |
$collection = Mage::getResourceModel('catalog/product_type_configurable_product_collection') | |
->addAttributeToFilter('is_saleable', 1) | |
->addAttributeToSelect('parent_id'); | |
$collection->getSelect()->where('link_table.parent_id IN(?)', $parentIds); | |
$collection->groupByAttribute('entity_id'); | |
$attributeCodes = $this->_getConfigurableAttributeCodes(); | |
$collection->addAttributeToSelect($attributeCodes); | |
foreach ($collection->getItems() as $row) { | |
$row = $row->getData(); | |
$simpleId = $row['entity_id']; | |
$parentId = $row['parent_id']; | |
$this->_simpleProducts[$simpleId] = $row; | |
$this->_associatedSimpleProducts[$parentId][] = $simpleId; | |
} | |
} | |
return $this->_simpleProducts; | |
} | |
/** | |
* Return array of associated simple product data | |
* | |
* @param Mage_Catalog_Model_Product $product The configurable product | |
* @return array Data for each associated simple product as array | |
*/ | |
protected function _getAssociatedSimpleProducts(Mage_Catalog_Model_Product $product) { | |
$simpleProducts = array(); | |
$parentId = $product->getId(); | |
$allSimpleProducts = $this->_getSimpleProducts(); | |
// If two configurable products share the same simple product the | |
// second one will not have a matching record in $this->_associatedSimpleProducts | |
if (isset($this->_associatedSimpleProducts[$parentId])) { | |
foreach ($this->_associatedSimpleProducts[$parentId] as $simpleProduct) { | |
$simpleProducts[] = $allSimpleProducts[$simpleProduct]; | |
} | |
} | |
return $simpleProducts; | |
} | |
/** | |
* The methods listed below belong into the resource model layer. For easier | |
* reference as an educational example I've listed them in this helper though. | |
* | |
* @see self::_getConfigurableAttributesForProductsFromResource() | |
* @see self::_getSimpleProducts() | |
* @return VinaiKopp_ProductList_Model_Resource_Configurable_Attributes | |
*/ | |
protected function _getResourceModel() | |
{ | |
return Mage::getResourceSingleton('vinaikopp_productlist/configurable_attributes'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment