製品属性を結合するためのベストプラクティス


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

これはsku(_prepareColums()メソッドではproduct_skuと呼んでいます)に適してい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 2013年

joinLeftの代わりにjoinを使用して、答えを編集しました
mageUz 2013年

どー!今バカになってる!;-)そして、なぜそれを試したのか分かりません。どうもありがとうございました!
Celldweller 2013年

@Celldweller、$this->_map['fields']['sku'] = 'sku'この場合は絶対に使用する必要はありません。複数の同じフィールド名があり、競合を防ぐために変換を行う必要がある場合にのみ必要です。これは、この使用例のオーバーヘッドを追加するだけです。別のユースケースでは、あなたが使用することができます$this->_map['fields']['my_sku'] = 'sku'あなたがコレクションで使用することができ、その後_prepareColumns$this->addColumn('my_sku', array(…))あなたはフィールドにしている場合、それはあなたがフィルタリングやソート列の競合を防ぐことができますskuコレクションに異なるDBテーブルの共通に使用される
シルヴァン・レイ

素晴らしい答えです!ただし、「同じIDのアイテムが既に存在する」という問題が発生する可能性があります。単純な方法$this->getSelect()->group('main_table.product_id');で問題が解決しますが、コードを最適化して、最初から重複が作成されないようにできますか?
Simon

4

こんにちはCelldwellerさん、元気にしてください:-)

Mage_Core_Model_Resource_Db_Collection_AbstractMagento構造を尊重したい場合は、コレクションクラスを使用してモデルを拡張してはならないため、クラスについての説明が間違っていた可能性があります。モデルではなくリソースコレクションを拡張します。私は正しいですか?

私の修正に基づいて、製品名属性を取得する頻度に応じて、さまざまな種類のアプローチが見られます。いずれにせよ、Magentoフレームワーク経由でSQLクエリを実行するのが最善の方法であり、効率的です。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その後、このメソッドを使用してコレクションを準備できます。両方を使用しないでください。つまり、同じコード_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 2013年

ああ、ところで:もちろん、そのような状況ではproduct-> load()を実行したくありません。勇気があれば撃て!;-)私の目標は、グリッドで並べ替えとフィルタリングを実行できるように、すべてを1つのコレクションに含めることです。詳細については、最初の投稿の更新を参照してください。
Celldweller 2013年

そのため、joinLeftをjoinに置き換えますが、私は正しく答え、最初に答えたものですが、もう1つの答えを受け入れました:-(
SylvainRayéNov

はい、そうです。ようやくうまくいったのでとても嬉しかったです。お二人に心より感謝申し上げます。あなたが私を許してくれることを願っています!私はあなたにビールを借りています。
Celldweller 2013年

ああ心配する必要はありません。ベルリンでお会いしましょう:-)
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 2018

コアファイルを変更する必要はありません。機能を実行するためにそのブロック(Mage_Adminhtml_Block_Catalog_Product_Grid)を上書きできます
Savoo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.