Найкраща практика приєднання атрибутів продукту


11

У мене є власна таблиця з посиланням на товар product_id. Тепер я хотів би показати свою інформацію про товар (ску, ім’я) у своїй резервній сітці , але я не впевнений, яка найкраща практика для цього?

Моя найкраща здогадка SKUнаступна:

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

(код з _prepareCollection() методу в моєму класі блоку сітки)

А як щодо назви продукту? Її можна знайти в каталозі_продукт_складу_варчар. Я розумію, що ви можете досить легко отримати його, якщо ви базуєтесь на власній моделі ресурсів та колекції, 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();
}

Це добре працює для sku (який я називаю product_sku в _prepareColums()методі. Але що joinмені потрібно вставити сюди, щоб отримати ім’я (наприклад, виробник)?

Чи роблю я щось не так, бо не можу користуватися joinLeft()?

Відповіді:


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

Використовуйте приєднання замість joinLeft, я відредагував відповідь
mageUz

До! Я почуваюся дурним зараз! ;-) І я не знаю, чому я спробував це. Велике спасибі!
Celldweller

@Celldweller, вам навіть не потрібно використовувати $this->_map['fields']['sku'] = 'sku'або подібне в цьому випадку. Він потрібен лише у тому випадку, якщо у вас є кілька однакових імен полів і вам потрібно зробити переклад, щоб запобігти конфліктам. Це просто додавання накладних витрат для цього випадку використання. У іншому випадку використання ви можете використовувати $this->_map['fields']['my_sku'] = 'sku'потім ви можете використовувати зі збіркою і _prepareColumns:, $this->addColumn('my_sku', array(…))це допоможе вам запобігти конфлікту для фільтрації або сортування стовпців, якщо у вас є поле, яке skuвикористовується в різних таблицях БД, спільних для колекції
Sylvain Rayé

Чудова відповідь! Це може призвести до "пункту з тим самим ідентифікатором вже існує". Простий $this->getSelect()->group('main_table.product_id');вирішує проблему, але, можливо, код можна оптимізувати, щоб дублікати не створювалися в першу чергу?
Саймон

4

Привіт Celldweller Я сподіваюсь, що ти добре :-)

Можливо, ви помилялися у своєму поясненні про клас Mage_Core_Model_Resource_Db_Collection_Abstract, ви розширюєте колекцію ресурсів, а не модель, тому що ви не повинні розширювати модель з класом колекції, якщо хочете поважати структуру Magento. Я правий?

На основі моєї корекції я бачу різний підхід, залежно від того, як часто ви хочете отримати атрибут назви продукту. У будь-якому випадку, я думаю, що зробити запит sql через Magento Framework - це найкращий спосіб та ефективно. Це швидше, ніж робити Mage::getModel('catalog/product')->load(1234)->getName()для кожного завантаженого товару. Тож насправді це буде дуже схоже на код, який ви використовуєте для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тоді ви можете підготувати колекцію за допомогою цього методу. Не використовуйте обидва, я маю на увазі не використовувати разом один і той же код у _beforeLoadта addProductNameметодах, використовувати лише один з них. Ось зразок:

У ваше 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

О і btw: Звичайно, я не хочу робити продукт-> load () у такій ситуації. Стріляйте в мене, якщо я коли-небудь зважусь! ;-) Моя мета - мати все це в одній колекції, щоб можна було сортувати та фільтрувати в сітці. Дивіться оновлення в моїй початковій публікації для отримання детальної інформації.
Celldweller

Тож замініть joinLeft на приєднання, але ви вже прийняли іншу відповідь, хоча я відповів правильно і першим відповів :-(
Sylvain Rayé

Так, ви праві. Я був такий щасливий, що це, нарешті, спрацювало, що я не думав про це. Я вам дуже вдячний обом. Сподіваюся, ви можете мені пробачити! Я тобі завдячую пивом.
Celldweller

аха, не хвилюйся. Ми зустрічаємо вас у Берліні із задоволенням :-)
Sylvain Rayé

4

У мене була майже однакова проблема, але я не можу додати коментар, бо не маю 50 репутації. Я витратив багато часу, намагаючись з’ясувати, що не так (я використовував код Sylvain Rayé). Моя колекція товарів чомусь відфільтрована. Тому я знайшов причину.

Якщо ви використовуєте деякі інструменти імпорту (магмі та ін.), Вони часто не створюють порожні атрибути одразу. Тому використання ->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 у файл блоку вашого розширення.

Додайте код нижче, щоб вибрати атрибут у функції _prepareCollection у продуктовій сітці Mage_Adminhtml_Block_Catalog_Product_Grid перед рядком $ this-> setCollection ($ collection).

$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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.