Mage_Catalog_Model_Resource_Product_CollectionにストアIDを設定する方法は?


34

タスクは簡単です。フラットカタログを有効にして、特定のストアビューの製品のリストを取得する必要があります。最も明白な解決策は次のとおりです。

$collection = Mage::getResourceModel('catalog/product_collection')
    ->setStore($storeId);

実際、setStore()メソッドはストアIDに基づいてフラットテーブルの名前を取得する_initSelect()メソッドの後に呼び出されるため、ここでは何の違いもありませんMage_Catalog_Model_Resource_Product_Collection。ストアIDはまだ設定されていないため、現在のストアIDが使用されます。

したがって、明らかな回避策は、モデルを取得する前に現在のストアIDを設定することです。

Mage::app()->setCurrentStore($storeId);

$collection = Mage::getResourceModel('catalog/product_collection');

それが動作します。ただし、コレクションを1回取得する必要がある場合のみ。ループ内でコレクションを取得する必要がある場合、または2つのバックツーバックコレクションだけが必要な場合は、コレクションに特定のストアを設定できません。

その理由は Mage_Catalog_Model_Resource_Product_Flatクラスには独自の_storeIdプロパティがあり、コンストラクターでは現在のストアIDに設定されるためです。それが最初に設定される理由です。それから、何らかの理由で(天国は私が希望していることを知っていMage_Eav_Model_Entity_Collection_Abstract::_initます)、各リソースモジュールはシングルトンとしてフェッチされます。したがって、2回目の呼び出しのコンストラクタはありません。

これはすべて非常に間違っているように見えるので、私は間違っていると確信しており、Magentoの別のバグ(または2つ)ではありません。誰かがそれに光を当てることを願っています。


インスタンスを取得するため、getResourceModel()を使用する必要がありますか?getModel( 'catalog / resource_product_collection')が機能する場合があります。
フリストンのクリストフ14

いいえ、まったく同じです。リソースモデルシングルトンをインスタンス化しています。
user487772 14

ティム、答えとして追加してください!
ファビアンBlechschmidt 14

@FabianBlechschmidt完了しました。
user487772 14

回答:


13

これはMagentoのどのバージョンですか?Magento 1.9の結果は次のとおりです。

有効なフラットカタログ:

フラットカタログにインデックスが付けられます。

特定のストアビューのデータセット:

使用されるコード:

<?php

require_once 'app/Mage.php';

Mage::app('admin');

$collection = Mage::getResourceModel('catalog/product_collection')
    ->addAttributeToSelect('*')                                                                                                                                                                                                                                                 
    ->addFieldToFilter('entity_id', array('eq' => 231))
    ->setStore(2);

var_dump($collection->getFirstItem()->getName());

結果は期待どおりです。

string(18) "But I Am Le French"

編集:

管理者ストアでは、フラットカタログは特に禁止されています。

// Flat Data can be used only on frontend
if (Mage::app()->getStore()->isAdmin()) {
    return false;
}

調査しています...

edit2:

あなたは正しいようです。 _initSelectテーブル名の生成に使用されるstoreIdを変更する前に呼び出されます。

もちろん(書き換えルートに行きたくない場合)次のことができます。

  • getSelect()、リセットを行い、新しいfrom()を設定します
  • $collection->getEntity()->setStoreId(123) そして、リフレクションを使用して呼び出します _initSelect再度
  • 独自のリソースモデルを作成し、フラットから拡張し、適切なタイミングでstoreIdを挿入する方法を提供します(__construct、delaying _initSelectなど)。
  • setCurrentStoreコレクションを作成するたびに呼び出します。

しかし、これらはすべて非常にハック感があります...申し訳ありませんが、これは不十分な答えかもしれません:-(

edit3:

少なくとも提供するためにそう答えました:

// Get collection and update store ID.
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->getEntity()->setStoreId(2);

// Reset the select.
$collection->getSelect()->reset();

// Update table name.
$reflectionMethod = new ReflectionMethod($collection, '_initSelect');
$reflectionMethod->setAccessible(true);
$reflectionMethod->invoke($collection);

// Do any other operations on the collection now.
$collection->addAttributeToSelect('*');

使用しないでください;-)


それでそれもバグだと思いますか?
user487772 14

1
コードをざっと読みましたが、product_collectionのコンストラクタは引数としてリソースモデルを受け入れます。では、を作成しProduct_Resource_Flat、ストアIDを設定し、クローンを作成して別のストアIDを設定し、それをコレクションコンストラクターに渡しますか?
メルビン14

1
@ティム:申し訳ありませんが、あなたのコメントを見ただけです。はい、それはバグだと思います。
ダニエル・スルーフ14

1.14.2.0
user4531

10

だから、私はこれらをMagentoの2つのバグだと考えています。

1つ目は、catalog/productコレクションにストアIDを設定できないという事実です。そして2つ目は、リソースモデルを非シングルトンとして絶対に取得できないことです。

愚かな回避策は、モデルを2回インスタンス化することです。初めてストアIDを設定でき、2番目のインスタンス化がそれを使用します。

Mage::getResourceModel('catalog/product_collection')->setStore($storeId);

$collection = Mage::getResourceModel('catalog/product_collection')

Mage :: getModel( 'catalog / category')-> getProductCollection()-> setStoreId()のセットストアが機能せず、あなたの機能が動作した理由がわかりません。方法でお願いします
Nickool

3

興味深いことに、使用されるフラットテーブルは一度設定されるだけで変更されず、テーブル名にはストアIDが含まれるため、テーブル名は変わらないがフラットにはならないため、EAVで機能します。回避策は、クエリのFROM部分のテーブルを交換するヘルパーを作成することです。そのようなヘルパーの例を次に示します。

class My_Module_Helper_Data extends Mage_Core_Helper_Abstract
{
    public function getProductCollectionForStore($store)
    {
        $collection = Mage::getResourceModel('catalog/product_collection');

        // Change the store on the entity
        // This doesn't change it in the (already constructed) SQL query
        $collection->setStore($store);

        if (! $collection->isEnabledFlat()) {
            return $collection;
        }

        // Change the used table to the $store we want
        $select = $collection->getSelect();
        $from = $select->getPart('from');

        // Here, getFlatTableName() will pick up the store set above
        $from[$collection::MAIN_TABLE_ALIAS]['table'] =
        $from[$collection::MAIN_TABLE_ALIAS]['tableName'] = 
            $collection->getEntity()->getFlatTableName();

        $select->setPart('from', $from);
        return $collection;
    }
}

次に、以下で簡単に使用できます。

$collection = Mage::helper('my_module')->getProductCollectionForStore('somestore')
    ->addAttributeToSelect('name');

単一のフラットテーブルからすべてのデータをフェッチするので、これはSQLに問題を引き起こさないと思いますが、シングルトンであるため、最後に使用されたストアは他の場所で使用されます。

別の解決策は、次のようなことを行うオブザーバーを作成するcatalog_product_collection_load_beforeことです。

class My_Module_Model_Observer
{
    public function setCorrectFlatStore(Varien_Event_Observer $observer)
    {
        $collection = $observer->getCollection();
        if (! $collection->isEnabledFlat()) {
            return;
        }

        $select = $collection->getSelect();
        $from = $select->getPart('from');

        // If somebody called setStore() on the collection make sure
        // to update the used flat table
        $from[$collection::MAIN_TABLE_ALIAS]['table'] =
        $from[$collection::MAIN_TABLE_ALIAS]['tableName'] =
            $collection->getEntity()->getFlatTableName();

        $select->setPart('from', $from);
    }
}

Magentoの人は_beforeLoad()メソッドでこれを修正する必要があることに同意します。


0

通常のフィルターを使用しないのはなぜですか?

$collection->addAttributeToFilter('store_id', $store_id);

store_idは、* _eav_entityテーブルの通常の列として指定されているため、フィルタリングすることもできます。私のために働いた。


0

core / app_emulationでこのソリューションを私の作品にしてください:

$storeId = 3;
$emulationModel = Mage::getModel('core/app_emulation');

// Emulate shop environment to disable using flat model and get collection for specific store
$emulationModel->startEnvironmentEmulation($storeId);
$products = Mage::getModel('catalog/product')->getCollection();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.