I'm facing an interesting problem regarding a custom modification to the backend Catalog Product grid.
NB: I'm currently using a module adding columns to this grid via an observer.
Nevertheless, the problem is also happening if I create a copy of app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php
under app/code/local
.
Here are the modifications I have made, I've changed the attribute I'm using with the native tax_class_id
attribute so anyone can replicate the issue:
Modified the _prepareCollection
method:
Before:
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('sku')
->addAttributeToSelect('name')
->addAttributeToSelect('attribute_set_id')
->addAttributeToSelect('type_id');
After:
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('sku')
->addAttributeToSelect('name')
->addAttributeToSelect('attribute_set_id')
->addAttributeToSelect('tax_class_id')
->addAttributeToSelect('type_id');
Modified the _prepareColumns
method by adding:
// Get the attribute corresponding to my custom attribute
$attribute = Mage::getResourceModel('eav/entity_attribute_collection')
->setCodeFilter("tax_class_id")
->getFirstItem();
// Get the attribute options
$attrOptions = $attribute->getSource()->getAllOptions(false);
// Convert the options to an array that can be used as the 'options' parameter for the addColumn method
$optionsArr = array();
foreach ($attrOptions as $option)
{
$optionsArr[$option['value']] = $option['label'];
}
$this->addColumn('tax_class_id',
array(
'header'=> Mage::helper('catalog')->__('Tax'),
'width' => '60px',
'index' => 'tax_class_id',
'type' => 'options',
'filter_index' => 'tax_class_id',
'options' => $optionsArr
));
That works perfectly fine in the following cases:
- Access Catalog > Product grid
- Filter by product type, attribute set, sku, price, quantity, visibility, status as well as the new custom column.
- Sort by product type, attribute set, sku, price, quantity, visibility, status as well as the new custom column.
- Browse via pager
- Change page size
However as soon as I start dealing with the name column, every cell of my custom column become empty/the product value is not displayed anymore, so when I:
- Filter by name
- Sort by name
How is that specific name column affecting my current custom column and how can I fix the issue ?
Best Answer
After digging very deep into Magento code and getting my hands dirty as I expected, I've found the root cause of the problem.
When the collection is loaded (implicitely via
getFirstItem
in @Simon test script), the_loadAttributes
method fromMage_Eav_Model_Entity_Collection_Abstract
is triggered.The goal of this method is to load the attributes we've requested via the
addAttributeToSelect
method.Here is a quick summary of the method code flow:
int
/catalog_product_entity_id
anddecimal
/catalog_product_entity_decimal
)price
attribute and one for thetax_class_id
attribute)That very last part of the code is very important, as this is where the bug is located (if you did not guess until now, it is a Magento bug).
So let's look at the code now, in our
_loadAttributes
method, we have the following code:Problem is, right before the loop, the
getLoadAttributesSelectGroups
method fromMage_Eav_Model_Resource_Helper_Mysql4
looks like this:Did you spot the
return
statement ? We return an array of arrays. So the loop in our_loadAttributes
method is never really used as there will always be one and only item (containing arrays) in the$selectGroups
variable.As this variable is not properly set, we keep going and reach the heart of the bug which is causing
int
being converted todecimals
:So our
$selects
variable contains two selects from two different tables of two different types (int and decimal).What does the MySQL documentation has to tell us about this:
So, implicitely, MySQL converts our int values to decimal values as it is not possible to convert the other way around.
And that only happens if you try to select decimal and int attributes, as if you select varchar attributes for instance, the int and decimal results will be converted to varchar and the problem disappears.
First, we need to find what is buggy:
_loadAttributes
method ?getLoadAttributesSelectGroups
method ?Well, I have found only one other reference to the
getLoadAttributesSelectGroups
method, it is under the_loadModelAttributes
of theMage_Eav_Model_Entity_Abstract
model and it looks like this:So in Magento developers mind, that function should definitely be returning an array with several entries as everytime this function is called, a
foreach
statement is used to loop through it.So I'll give you the fix I've applied:
In
getLoadAttributesSelectGroups
method ofMage_Eav_Model_Resource_Helper_Mysql4
, replace:With:
In
_loadAttributes
method ofMage_Eav_Model_Entity_Collection_Abstract
, replace:With:
In the
_loadModelAttribures
of theMage_Eav_Model_Entity_Abstract
, replace:With:
Edit: regarding the bug on Magento 2, I've created a Pull Request that can be found here: https://github.com/magento/magento2/pull/3705 (related issue: https://github.com/magento/magento2/issues/3704)
Edit 2: regarding the bug on Magento 1, I've reported the bug you can find the report here: https://www.magentocommerce.com/bug-tracking/issue/index/id/1346