Question

I have a custom table with a product reference product_id. Now I would like to show product information (sku, name) in my backend grid, but I am unsure what is the best practice to do this?

My best guess for SKU is as follows:

$collection->join(
    'catalog/product',
    'product_id=`catalog/product`.entity_id',
    array('product_sku' => 'sku')
)

(code from the _prepareCollection() method in my grid block class)

But what about the product name? It can be found in catalog_product_entity_varchar. My understanding is that you can rather easy get it if your own resource model and collection is based on Mage_Eav_Model_Entity_Collection_Abstract because then you can use methods like joinAttribute. But my model is based on a simple table and extending from Mage_Core_Model_Resource_Db_Collection_Abstractand there is no joinAttribute method available.

So what is the best way to get the product name in this case?

Thanks for your time and help :-)

Update: To be more precise, I was talking about my resource model and collection. It matches a simple flat table with just a few attributes like

entity_id    product_id    created_at    user_id

My intention is to grid in the backend where I show some statistics:

ProductSku    Count(ProductSku)    MAX(created_at)

As far as I know, the best approch to do this, is via the grid block class and the method to go is _prepareCollection().

My method looks like this:

protected function _prepareCollection()
{
    // Get and set our collection for the grid
    $collection = Mage::getResourceModel($this->_getCollectionClass());
    $collection
        ->join(
            'catalog/product',
            'product_id=`catalog/product`.entity_id',
            array('product_sku' => 'sku')
            )
        ->addExpressionFieldToSelect('product_count', 'COUNT({{product_id}})', 'product_id')
        ->addExpressionFieldToSelect('newest', 'MAX({{created_at}})', array('created_at'=>'main_table.created_at'))
        ->getSelect()->group('product_id');
    $this->setCollection($collection);

    return parent::_prepareCollection();
}

This works well for the sku (which I refer to as product_sku in the _prepareColums() method. But what join do I need to insert here in order to get the name (and e.g. the manufacturer)?

Am I doing something wrong because I can't use joinLeft()?

Was it helpful?

Solution

In your collection class (/Some/Module/Model/Mysql4 (or Resource)/YourModel/Collection.php) add this method:

public function addProductData()
    {
        /** add particular attribute code to this array */
        $productAttributes = array('name', 'price', 'url_key');
        foreach ($productAttributes as $attributeCode) {
            $alias     = $attributeCode . '_table';
            $attribute = Mage::getSingleton('eav/config')
                ->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeCode);

            /** Adding eav attribute value */
            $this->getSelect()->join(
                array($alias => $attribute->getBackendTable()),
                "main_table.product_id = $alias.entity_id AND $alias.attribute_id={$attribute->getId()}",
                array($attributeCode => 'value')
            );
            $this->_map['fields'][$attributeCode] = 'value';
        }
        /** adding catalog_product_entity table fields */
        $this->join(
            'catalog/product',
            'product_id=`catalog/product`.entity_id',
            array('sku' => 'sku', 'type_id' => 'type_id')
        );
        $this->_map['fields']['sku']     = 'sku';
        $this->_map['fields']['type_id'] = 'type_id';
        return $this;
    }

In your grid block use this function:

 protected function _prepareCollection()
    {
        $collection = Mage::getModel('some/yourmodel')
            ->getCollection()->addProductData();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

OTHER TIPS

Hi Celldweller I hope you're doing well :-)

Maybe you were wrong in your explanation about the class Mage_Core_Model_Resource_Db_Collection_Abstract, you extend a resource collection not the model because you must not extend a model with a collection class if you want to respect the Magento structure. Am I right?

Based on my correction, I see different kind of approach, depending on how often you want to get the product name attribute. In any case, I think to do a sql query via the Magento Framework is the best way and efficient. It's more faster than to do a Mage::getModel('catalog/product')->load(1234)->getName() for each loaded item. So in fact it will be very similar to the code you use for the sku

CODE NOT TESTED

You want those information each time a collection is loaded

You may in your collection class set into a _beforeLoad method such a code:

protected function _beforeLoad()
{
    $productName = Mage::getSingleton('eav/config')->getAttribute('catalog_product','name');

    $this->getSelect()
        ->join( array('product_attribute' => $productName->getBackendTable()),
            'main_table.product_id = product_attribute.entity_id',
            array())
        ->where("product_attribute.attribute_id = ?", $productName->getId());
    }

    return parent::_beforeLoad();
}

You want those information ONLY for the grid

In your _prepareCollection, you will have to add a method in your collection with the same code as it was done above into the _beforeLoad then you can prepare the collection by using this method. Don't use both, I mean don't use together the same code in _beforeLoad and addProductName methods, use only one of them. Here is a sample:

Into your grid.php:

protected function _prepareCollection()
{
    ...
    $collection->addProductName();
    $this->setCollection($collection);
    return parent::_prepareCollection();
}

Into your Collection.php:

public function addProductName()
{
    $productName = Mage::getSingleton('eav/config')->getAttribute('catalog_product','name');

    $this->getSelect()
        -> join( array('product_attribute' => $productName->getBackendTable()),
            'main_table.product_id = product_attribute.entity_id',
            array())
        ->where("product_attribute.attribute_id = ?", $productName->getId());

    return $this;
}

I had almost the same problem, but i can't add a comment, because I not have 50 reputation. I spent a lot of time trying to figure out what is wrong (I used code of Sylvain Rayé). My product collection for some reason filtered. So I found a reason.

If you using some import tools (magmi, etc), they often do not create empty attributes at once. Therefore using ->where("product_attribute.attribute_id = ?", $productName->getId()) products that do not have this attribute, will disappear from selection.

Right way is using joinLeft like that:

$productName = Mage::getSingleton('eav/config')->getAttribute('catalog_product','name');

$this->getSelect()
     ->joinLeft(array('product_attribute' => $productName->getBackendTable()),
        "main_table.product_id = product_attribute.entity_id AND
         product_attribute.attribute_id = {$productName->getId()}",
        array());

Hope this helps someone.

Display custom attribute on product grid.

Please overwrite this block Mage_Adminhtml_Block_Catalog_Product_Grid in your extension and copy functions _prepareCollection and _prepareColumns into your extension's block file.

Add below code to select attribuet in _prepareCollection function of product grid Mage_Adminhtml_Block_Catalog_Product_Grid before $this->setCollection($collection) line.

$attributeCode = 'qc_status';//here your attribute code
        $collection->joinAttribute($attributeCode, 'catalog_product/'.$attributeCode, 'entity_id', null, 'left');
        $collection->addAttributeToSelect($attributeCode);

And then below code for column in _prepareColumns function of grid.

$attributeCodeConfig ='qc_status';//Your attribute code...

        $attributeId = Mage::getResourceModel('eav/entity_attribute')->getIdByCode('catalog_product', $attributeCodeConfig);

        $attribute = Mage::getModel('catalog/resource_eav_attribute')->load($attributeId);
        $attributeData = $attribute->getData();
        $frontEndLabel = $attributeData['frontend_label'];

        $attributeOptions = $attribute->getSource()->getAllOptions();
        $b = new Mage_Catalog_Model_Resource_Eav_Attribute();
        $attributeOptions2 = array();
        foreach ($attributeOptions as $value) {
            if(!empty($value['value'])) {
                $attributeOptions2[$value['value']] = $value['label'];
            }

        }


        if(count($attributeOptions2) > 0) {
            $this->addColumn($attributeCodeConfig,
                array(
                    'header'=> Mage::helper('catalog')->__($frontEndLabel),
                    'width' => '80px',
                    'index' => $attributeCodeConfig,
                    'type'  => 'options',
                    'options' => $attributeOptions2,

            ));
        } else {
            $this->addColumn($attributeCodeConfig,
                array(
                    'header'=> Mage::helper('catalog')->__($frontEndLabel),
                    'width' => '80px',
                    'index' => $attributeCodeConfig,

            ));
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top