Làm cách nào để đặt ID cửa hàng trên Mage_Catalog_Model_Resource_ Productt_Collection?


34

Nhiệm vụ là tầm thường. Tôi cần lấy danh sách các sản phẩm để xem cửa hàng cụ thể với danh mục phẳng được bật. Giải pháp rõ ràng nhất là như sau:

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

Trong thực tế, setStore()phương thức này không tạo ra bất kỳ sự khác biệt nào ở đây bởi vì nó được gọi sau _initSelect()phương thức Mage_Catalog_Model_Resource_Product_Collectionlấy tên của bảng phẳng dựa trên ID cửa hàng. Vì ID cửa hàng chưa được đặt, nó sẽ lấy ID cửa hàng hiện tại.

Vì vậy, cách giải quyết rõ ràng sẽ là đặt ID cửa hàng hiện tại trước khi lấy mô hình.

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

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

Nó sẽ làm việc. Nhưng chỉ khi bạn cần có được một bộ sưu tập một lần. Nếu bạn cần lấy một bộ sưu tập trong vòng lặp hoặc bạn chỉ cần hai bộ sưu tập quay lại, bạn sẽ không thể đặt một cửa hàng cụ thể cho chúng.

Lý do là Mage_Catalog_Model_Resource_Product_Flatlớp có thuộc tính riêng của nó _storeIdvà trong hàm tạo, nó được đặt thành ID cửa hàng hiện tại. Đó là lý do tại sao nó sẽ được thiết lập lần đầu tiên. Sau đó, vì một số lý do (trời biết tôi hy vọng có một) trong Mage_Eav_Model_Entity_Collection_Abstract::_initmỗi mô-đun tài nguyên được tìm nạp dưới dạng đơn lẻ. Vì vậy, không có nhà xây dựng cho cuộc gọi thứ 2.

Tất cả điều này có vẻ sai đến nỗi tôi khá chắc chắn rằng tôi đã sai và đó không phải là một lỗi Magento (hoặc hai) khác. Hy vọng ai đó có thể làm sáng tỏ về nó.


Bạn có phải sử dụng getResourceModel () vì điều này cung cấp cho bạn ví dụ không? getModel ('catalog / resource_product_collection') có thể chỉ hoạt động.
Kristof tại Fooman

Không, nó hoàn toàn giống nhau. Đó là khởi tạo mô hình tài nguyên singleton theo bất kỳ cách nào.
dùng487772

Tim, thêm nó như một câu trả lời xin vui lòng!
Fabian Blechschmidt

@FabianBlechschmidt thực hiện.
dùng487772

Câu trả lời:


13

Phiên bản này của Magento là gì? Đây là kết quả của tôi cho Magento 1.9:

Danh mục phẳng được kích hoạt:

Danh mục phẳng được lập chỉ mục:

Một số dữ liệu được đặt trong chế độ xem cửa hàng cụ thể:

Mã đã được sử dụng:

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

Kết quả như mong đợi:

string(18) "But I Am Le French"

chỉnh sửa:

Nevermind, danh mục phẳng đặc biệt bị cấm cho cửa hàng quản trị:

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

Điều tra ...

chỉnh sửa2:

Có vẻ như bạn đúng. _initSelectđược gọi trước khi chúng ta có thể sửa đổi storeId được sử dụng để tạo tên bảng.

Tất nhiên (nếu chúng tôi không muốn đi theo con đường viết lại), chúng tôi có thể:

  • getSelect(), thực hiện đặt lại và đặt mới từ ()
  • $collection->getEntity()->setStoreId(123)và sau đó sử dụng sự phản chiếu để gọi _initSelectlại
  • Chỉ cần tạo mô hình tài nguyên của riêng chúng tôi và mở rộng từ căn hộ, đưa ra một số cách chèn storeId vào đúng thời điểm ( __construct, trì hoãn _initSelect, v.v.).
  • gọi setCurrentStoremọi lúc chúng tôi tạo ra bộ sưu tập.

Nhưng tất cả đều cảm thấy rất khó chịu ... Xin lỗi, đây có thể là một câu trả lời không thỏa đáng :-(

chỉnh sửa 3:

Vì vậy, để cung cấp ít nhất một câu trả lời:

// 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('*');

Vui lòng không sử dụng ;-)


Vì vậy, bạn cũng nghĩ rằng đó là một lỗi?
dùng487772

1
Tôi lướt qua mã, nhưng hàm tạo product_collectioncủa nó chấp nhận một mô hình tài nguyên làm đối số. Vì vậy, nếu bạn tạo một Product_Resource_Flat, đặt id cửa hàng của nó, sao chép nó và đặt một id cửa hàng khác, sau đó chuyển nó đến hàm tạo của bộ sưu tập, điều đó có khả thi không?
Melvyn

1
@Tim: Xin lỗi, chỉ thấy bình luận của bạn. Có tôi nghĩ đó là một lỗi.
Daniel Sloof

cho câu trả lời tuyệt vời, nó hoạt động cho 1.14.2.0
user4531 7/12/15

10

Vì vậy, tôi coi đây là hai lỗi trong Magento.

Đầu tiên là thực tế là bạn không thể đặt ID cửa hàng trên catalog/productbộ sưu tập. Và thứ hai là bạn hoàn toàn không thể lấy mô hình tài nguyên dưới dạng đơn lẻ.

Vì vậy, cách giải quyết ngu ngốc là khởi tạo mô hình hai lần. Lần đầu tiên ID cửa hàng có thể được đặt và lần khởi tạo thứ hai sẽ sử dụng nó:

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

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

Tôi không biết tại sao cửa hàng thiết lập của mình trong Mage :: getModel ('danh mục / danh mục') -> get SẢNtCollection () -> setStoreId () không hoạt động và bạn đã làm việc. nhân tiện cảm ơn bạn
Nickool

3

Thật thú vị, bảng phẳng đã sử dụng được đặt một lần và không bao giờ thay đổi, hoạt động cho EAV do tên bảng không thay đổi nhưng không thay đổi vì tên bảng bao gồm ID cửa hàng. Một cách giải quyết khác là tạo ra một người trợ giúp có thể trao đổi bảng trong phần TỪ của truy vấn. Đây là một ví dụ về một người trợ giúp như vậy:

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

Sau đó, bạn có thể sử dụng nó đơn giản với:

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

Tôi tưởng tượng điều này sẽ không gây rắc rối cho SQL vì bạn đang tìm nạp tất cả dữ liệu từ một bảng phẳng duy nhất nhưng vì đó là một đơn vị nên cửa hàng được sử dụng cuối cùng sẽ được sử dụng ở mọi nơi khác.

Giải pháp thay thế sẽ là làm cho một người quan sát catalog_product_collection_load_beforethực hiện điều gì đó như thế này:

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

Tôi đồng ý rằng các chàng trai Magento nên khắc phục điều này trong _beforeLoad()phương pháp.


0

Tại sao không sử dụng bộ lọc thông thường?

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

store_id được đưa ra dưới dạng một cột thông thường trong bảng * _eav_entity , do đó bạn cũng có thể lọc theo nó. Đã làm cho tôi.


0

Hãy là công việc của tôi giải pháp này với 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();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.