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');

작동합니다. 그러나 컬렉션을 한 번 가져와야하는 경우에만 가능합니다. 루프에서 콜렉션을 가져 오거나 두 개의 연속 콜렉션이 필요한 경우 특정 상점을 설정할 수 없습니다.

그 이유는 Mage_Catalog_Model_Resource_Product_Flat클래스에 자체 _storeId속성이 있고 생성자에서 현재 상점 ID로 설정되어 있기 때문입니다. 이것이 처음으로 설정되는 이유입니다. 그런 다음 Mage_Eav_Model_Entity_Collection_Abstract::_init각 리소스 모듈 에 어떤 이유로 (하나는 있음을 알고 있음) 알 수 있습니다 . 따라서 두 번째 호출의 생성자가 없습니다.

이 모든 것이 잘못되어 내가 틀렸다고 확신하며 다른 마 젠토 버그 (또는 두 가지)가 아닙니다. 누군가가 그것에 빛을 비출 수 있기를 바랍니다.


인스턴스를 제공하므로 getResourceModel ()을 사용해야합니까? getModel ( 'catalog / resource_product_collection')이 작동 할 수도 있습니다.
Fooman의 Kristof

아니요, 절대적으로 동일합니다. 어떤 방식 으로든 자원 모델 싱글 톤을 인스턴스화합니다.
user487772

팀, 답변으로 추가하십시오!
Fabian Blechschmidt

@FabianBlechschmidt 님이 완료했습니다.
user487772

답변:


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, 지연 _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

1
코드를 살펴 보았지만 product_collection의 생성자는 리소스 모델을 인수로 허용합니다. 따라서을 만들고 Product_Resource_Flat상점 ID를 설정하고 복제 한 다음 다른 상점 ID를 설정 한 다음 컬렉션 생성자에 전달하면 가능합니까?
Melvyn

1
@Tim : 죄송합니다. 귀하의 의견 만 보았습니다. 네, 버그라고 생각합니다.
다니엘 Sloof

최대 좋은 답변, 그것은 1.14.2.0을 위해 일하고있어
user4531

10

그래서 나는 이것이 Magento의 두 가지 버그라고 생각합니다.

첫 번째는 catalog/product콜렉션에서 상점 ID를 설정할 수 없다는 사실입니다 . 그리고 두 번째는 리소스 모델을 비 싱글 톤으로 절대 얻을 수 없다는 것입니다.

따라서 어리석은 해결 방법은 모델을 두 번 인스턴스화하는 것입니다. 상점 ID를 처음 설정할 수 있으며 두 번째 인스턴스화에서이를 사용합니다.

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

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

왜 Mage :: getModel ( 'catalog / category')-> getProductCollection ()-> setStoreId ()의 세트 스토어가 작동하지 않고 귀하의 세트 스토어가 작동했는지 모르겠습니다.
그건

3

흥미롭게도, 사용 된 플랫 테이블은 한 번 설정되고 테이블 이름은 변경되지 않지만 EAV에서는 작동하지만 테이블 이름은 상점 ID를 포함하므로 플랫에서는 작동하지 않는 변경되지 않습니다. 해결 방법은 쿼리의 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.