If have a multiselect attribute and want to set the selection on a product.
$selectedOptions = "red,green,blue";
$product->..... // # what to do?
How can I do that?
attributesmultiselect-attributeproductprogramming
If have a multiselect attribute and want to set the selection on a product.
$selectedOptions = "red,green,blue";
$product->..... // # what to do?
How can I do that?
I assume that the attribute values are usual values, not from a custom source model.
If that is the case, then the sorting is done in the method Mage_Eav_Model_Entity_Attribute_Source_Table::addValueSortToCollection
.
Even if there is a custom source model you still need that method for sorting.
What I advice is to rewrite that method and change the way the sorting is done.
You can make that method look like this:
public function addValueSortToCollection($collection, $dir = Varien_Db_Select::SQL_ASC)
{
$valueTable1 = $this->getAttribute()->getAttributeCode() . '_t1';
$valueTable2 = $this->getAttribute()->getAttributeCode() . '_t2';
$valueExpr = $collection->getSelect()->getAdapter()
->getCheckSql("{$valueTable2}.value_id > 0", "{$valueTable2}.value", "{$valueTable1}.value");
$collection->getSelect()
->joinLeft(
array($valueTable1 => $this->getAttribute()->getBackend()->getTable()),
"e.entity_id={$valueTable1}.entity_id"
. " AND {$valueTable1}.attribute_id='{$this->getAttribute()->getId()}'"
. " AND {$valueTable1}.store_id=0",
array())
->joinLeft(
array($valueTable2 => $this->getAttribute()->getBackend()->getTable()),
"e.entity_id={$valueTable2}.entity_id"
. " AND {$valueTable2}.attribute_id='{$this->getAttribute()->getId()}'"
. " AND {$valueTable2}.store_id='{$collection->getStoreId()}'",
array($this->getAttribute()->getAttributeCode() => $valueExpr)
);
$collection->getSelect()
->order("{$this->getAttribute()->getAttributeCode()} {$dir}");
return $this;
}
Have a look at how it's been done in the layered navigation:
the responsible method is Mage_Catalog_Model_Resource_Layer_Filter_Attribute::getCount()
:
/**
* Retrieve array with products counts per attribute option
*
* @param Mage_Catalog_Model_Layer_Filter_Attribute $filter
* @return array
*/
public function getCount($filter)
{
// clone select from collection with filters
$select = clone $filter->getLayer()->getProductCollection()->getSelect();
// reset columns, order and limitation conditions
$select->reset(Zend_Db_Select::COLUMNS);
$select->reset(Zend_Db_Select::ORDER);
$select->reset(Zend_Db_Select::LIMIT_COUNT);
$select->reset(Zend_Db_Select::LIMIT_OFFSET);
$connection = $this->_getReadAdapter();
$attribute = $filter->getAttributeModel();
$tableAlias = sprintf('%s_idx', $attribute->getAttributeCode());
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
$connection->quoteInto("{$tableAlias}.store_id = ?", $filter->getStoreId()),
);
$select
->join(
array($tableAlias => $this->getMainTable()),
join(' AND ', $conditions),
array('value', 'count' => new Zend_Db_Expr("COUNT({$tableAlias}.entity_id)")))
->group("{$tableAlias}.value");
return $connection->fetchPairs($select);
}
Unfortunately you can't use that straight away with any collection because it's too tightly coupled to the filter model, which again doesn't handle arbitrary product collections.
So your best option is probably to copy what you need from there into an own resource model like this (untested):
class Your_Extension_Model_Resource_Attribute extends Mage_Core_Model_Resource_Db_Abstract
{
public function getCount($productCollection, $attributeCode, $storeId)
{
// clone select from collection with filters
//----------------------------------------------------------------
$select = clone $productCollection->getSelect();
//----------------------------------------------------------------
// reset columns, order and limitation conditions
$select->reset(Zend_Db_Select::COLUMNS);
$select->reset(Zend_Db_Select::ORDER);
$select->reset(Zend_Db_Select::LIMIT_COUNT);
$select->reset(Zend_Db_Select::LIMIT_OFFSET);
$connection = $this->_getReadAdapter();
//----------------------------------------------------------------
$attribute = Mage::getModel('eav/entity_attribute')->loadByCode($attributeCode);
//----------------------------------------------------------------
$tableAlias = sprintf('%s_idx', $attribute->getAttributeCode());
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
//----------------------------------------------------------------
$connection->quoteInto("{$tableAlias}.store_id = ?", $storeId),
//----------------------------------------------------------------
);
$select
->join(
array($tableAlias => $this->getMainTable()),
join(' AND ', $conditions),
array('value', 'count' => new Zend_Db_Expr("COUNT({$tableAlias}.entity_id)")))
->group("{$tableAlias}.value");
return $connection->fetchPairs($select);
}
}
And then call it like
$options = Mage::getResourceModel('your_extension/attribute')
->getCount($collection, 'color', Mage::app()->getStore()->getId());
$options
will be an array with the values as key and number of occurances as value. Filtering out the 0's should not be a problem from there.
Best Answer
Multiselect attributes can be set as a comma separated list (or also an array) containing the attribute value ids.
So first we have to convert the actual values to Magento's internal ids.