วิธีตั้งค่า ID ร้านค้าบน Mage_Catalog_Model_Resource_Product_Collection


34

งานนั้นไม่สำคัญ ฉันต้องการรับรายการผลิตภัณฑ์สำหรับมุมมองร้านค้าโดยเฉพาะด้วยการเปิดใช้งานแค็ตตาล็อกแบบแบน ทางออกที่ชัดเจนที่สุดคือ:

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

ในความเป็นจริงsetStore()วิธีการไม่ได้สร้างความแตกต่างใด ๆ ที่นี่เพราะมันถูกเรียกหลังจาก_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คุณสมบัติเป็นของตัวเองและใน Constructor นั้นจะถูกตั้งค่าเป็น ID ร้านค้าปัจจุบัน นั่นเป็นเหตุผลที่มันจะถูกตั้งค่าเป็นครั้งแรก ด้วยเหตุผลบางอย่าง (สวรรค์รู้ว่าฉันหวังว่าจะมีหนึ่ง) ในMage_Eav_Model_Entity_Collection_Abstract::_initแต่ละโมดูลทรัพยากรถูกเรียกเป็นซิงเกิล ดังนั้นไม่มี Constructor สำหรับการโทรครั้งที่สอง

ทั้งหมดนี้ดูผิดไปมากจนฉันค่อนข้างมั่นใจว่าฉันผิดและไม่ใช่ Magento bug ตัวอื่น (หรือสองตัว) หวังว่าใครบางคนสามารถหลั่งน้ำตาแสงบนมัน


คุณต้องใช้ getResourceModel () ตามนี้ให้ตัวอย่างหรือไม่ getModel ('catalog / resource_product_collection') อาจใช้งานได้
Kristof ที่ Fooman

ไม่มันเหมือนกันหมด มันเป็นอินสแตนซ์ของโมเดลทรัพยากร singleton ในทางใดทางหนึ่ง
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()ทำการรีเซ็ตและตั้งค่าใหม่จาก ()
  • $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สตรัคของยอมรับรูปแบบทรัพยากรเป็นอาร์กิวเมนต์ ดังนั้นถ้าคุณสร้าง a Product_Resource_Flatให้ตั้งเป็นรหัสร้านค้าโคลนและตั้งค่ารหัสร้านค้าอื่นจากนั้นส่งต่อไปยังตัวสร้างคอลเลกชันซึ่งจะทำได้หรือไม่
Melvyn

1
@Tim: ขออภัยเพียงแค่เห็นความคิดเห็นของคุณ ใช่ฉันคิดว่ามันเป็นข้อผิดพลาด
Daniel Sloof

สำหรับคำตอบที่ดีมันใช้งานได้กับ 1.14.2.0
4531

10

ดังนั้นฉันคิดว่านี่เป็นข้อผิดพลาดสองอย่างใน Magento

อย่างแรกคือข้อเท็จจริงที่ว่าคุณไม่สามารถตั้งค่า ID ร้านค้าในการcatalog/productรวบรวมได้ และอย่างที่สองคือคุณไม่สามารถรับโมเดลทรัพยากรอย่างที่ไม่ใช่แบบซิงเกิล

วิธีแก้ปัญหางี่เง่าคือยกตัวอย่างรูปแบบสองครั้ง ในครั้งแรกที่สามารถตั้งค่า ID ร้านค้าและการสร้างอินสแตนซ์ที่สองจะใช้:

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

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

ฉันไม่รู้ว่าทำไมชุดร้านค้าของฉันใน Mage :: getModel ('แคตตาล็อก / หมวดหมู่') -> getProductCollection () -> setStoreId () ไม่ทำงานและคุณทำงาน โดยวิธีขอบคุณ
Nickool

3

ที่น่าสนใจคือโต๊ะแบนที่ใช้ถูกตั้งค่าไว้หนึ่งครั้งและไม่เคยเปลี่ยนซึ่งใช้งานได้กับ EAV เนื่องจากชื่อตารางไม่เปลี่ยนแปลง แต่ไม่เหมาะสำหรับแบนเนื่องจากชื่อตารางนั้นมี ID ร้านค้า วิธีแก้ปัญหาคือการสร้างผู้ช่วยที่จะสลับตารางในส่วนของแบบสอบถาม นี่คือตัวอย่างของผู้ช่วยดังกล่าว:

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

ฉันยอมรับว่าพวกวีโอไอพีควรแก้ไขปัญหานี้ด้วย_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.