加入产品属性的最佳实践


11

我有一个带有产品参考的自定义表product_id。现在,我想在后端网格中显示产品信息(SKU,名称),但是我不确定这样做的最佳实践是什么?

我的最佳猜测SKU如下:

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

(来自 我的网格块类中方法的代码_prepareCollection()

但是产品名称呢?可以在catalog_product_entity_varchar中找到。我的理解是,如果您自己的资源模型和集合是基于的,Mage_Eav_Model_Entity_Collection_Abstract则可以很容易地获得它,因为这样您就可以使用joinAttribute。但是我的模型是基于一个简单的表并从扩展而来Mage_Core_Model_Resource_Db_Collection_Abstract,没有joinAttribute可用的方法。

那么在这种情况下获得产品名称的最佳方法是什么?

感谢您的时间和帮助:-)

更新: 更准确地说,我在谈论我的资源模型和集合。它与仅具有几个属性的简单平面表匹配,例如

entity_id    product_id    created_at    user_id

我的意图是在后端显示一些统计数据:

ProductSku    Count(ProductSku)    MAX(created_at)

据我所知,执行此操作的最佳方法是通过网格块类,而执行的方法是_prepareCollection()

我的方法如下所示:

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();
}

这对于s​​ku效果很好(我在_prepareColums()方法中将其称为product_sku 。但是join,为了获得名称(例如制造商),我需要在此处插入什么?

我因为无法使用而做错了joinLeft()什么?

Answers:


13

在您的集合类(/Some/Module/Model/Mysql4 (or Resource)/YourModel/Collection.php)中添加以下方法:

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;
    }

在您的网格块中,使用以下功能:

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

这看起来很有希望,但不幸的是它没有用。我的收藏夹从扩展,Mage_Core_Model_Resource_Db_Collection_Abstract并且出现错误Call to undefined method Mycompany_Module_Model_Resource_Mymodel_Collection::joinLeft()。我猜这是因为我不使用EAV资源模型吗?
Celldweller

使用join代替joinLeft,我编辑了答案
mageUz 2013年

h!我现在觉得很蠢!;-)而且我不知道为什么要尝试。非常感谢你!
Celldweller

@Celldweller,$this->_map['fields']['sku'] = 'sku'在这种情况下,您甚至不需要绝对使用或类似方法。仅当您具有多个相同的字段名称并且需要进行翻译以防止冲突时才需要它。它只是增加了此用例的开销。在不同的使用情况,您可以使用$this->_map['fields']['my_sku'] = 'sku',那么你可以用收集使用和_prepareColumns$this->addColumn('my_sku', array(…)),它会帮助你防止对筛选或排序列冲突,如果你有一个字段sku在不同的数据库表共同用于收集
西尔RAYE

好答案!但是,这可能会导致“具有相同ID的商品已存在”的问题。一个简单的方法$this->getSelect()->group('main_table.product_id');可以解决此问题,但是也许可以优化代码,这样一来就不会创建重复项?
西蒙(Simon)

4

嗨,Celldweller,我希望你一切都好:-)

也许您在关于类的解释中是错误的Mage_Core_Model_Resource_Db_Collection_Abstract,您扩展了资源集合而不是模型,因为如果您想遵守Magento结构,则必须使用集合类扩展模型。我对吗?

根据我的更正,我看到了不同的方法,具体取决于您要获取产品名称属性的频率。无论如何,我认为通过Magento框架进行sql查询是最好的方式和效率。它比Mage::getModel('catalog/product')->load(1234)->getName()为每个加载的项目执行a更快。因此,实际上它将与您用于sku

代码未测试

每次加载集合时都需要这些信息

您可以在集合类中将_beforeLoad这样的方法设置为代码:

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();
}

您只需要网格的那些信息

在中_prepareCollection,您必须使用与上面相同的代码在集合中添加一个方法,_beforeLoad然后您可以使用此方法准备集合。不要同时使用两者,我的意思是不要在_beforeLoadaddProductName方法中一起使用相同的代码,而仅使用其中之一。这是一个示例:

进入您的grid.php

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

进入您的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;
}

很高兴再次阅读您的文章:-)非常感谢,但是我不能使用joinLeft()方法。我想这是仅EAV资源模型的方法?您说得对,我的第一个问题很不准确。我将对其进行编辑:)
Celldweller

哦,顺便说一句:当然,在这种情况下,我不想执行product-> load()。如果我敢的话,请射杀我!;-)我的目标是将所有这些都放在一个集合中,以便能够在网格中进行排序和过滤。有关更多详细信息,请参阅我的初始文章中的更新。
Celldweller

因此,用join代替joinLeft,但是您已经接受了另一个答案,尽管我回答正确,并且是第一个回答:-(
SylvainRayé13年

是,你说得对。我很高兴它终于成功了,我没有考虑过。我非常感谢你们俩。希望你能原谅我!我欠你啤酒。
Celldweller

啊,不用担心。我们很高兴在柏林与您会面:-)
SylvainRayé2013年

4

我遇到了几乎相同的问题,但是我无法添加评论,因为我没有50的声誉。我花了很多时间试图找出问题所在(我使用了SylvainRayé的代码)。我的产品收藏出于某种原因被过滤。所以我找到了原因。

如果使用某些导入工具(magmi等),它们通常不会立即创建空属性。因此,使用->where("product_attribute.attribute_id = ?", $productName->getId())不具有此属性的产品将从选择中消失。

正确的方法是这样使用的joinLeft

$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());

希望这对某人有帮助。


-2

在产品网格上显示自定义属性。

请覆盖您扩展程序中的此块Mage_Adminhtml_Block_Catalog_Product_Grid并将函数_prepareCollection和_prepareColumns复制到扩展程序的块文件中。

在$ this-> setCollection($ collection)行之前,在产品网格Mage_Adminhtml_Block_Catalog_Product_Grid的_prepareCollection函数中添加以下代码以选择属性。

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

然后下面的代码在网格的_prepareColumns函数中。

$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,

            ));
        }

更改核心文件不是一个好习惯。同样适用于new SomeModel()
sv3n

我们不必在核心文件中进行更改。我们可以覆盖该块(Mage_Adminhtml_Block_Catalog_Product_Grid)以完成我们的功能
Savoo,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.