Mage_Catalog_Model_Resource_Product_Collection पर स्टोर आईडी कैसे सेट करें?


34

कार्य तुच्छ है। मुझे विशेष रूप से स्टोर करने के लिए उत्पादों की सूची प्राप्त करने की आवश्यकता है, जिसमें एक फ्लैट कैटलॉग सक्षम है। सबसे स्पष्ट समाधान निम्नलिखित है:

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

वास्तव में setStore()विधि यहाँ कोई अंतर नहीं कर रही है क्योंकि इसे _initSelect()विधि के बाद कहा जाता है जिसे Mage_Catalog_Model_Resource_Product_Collectionस्टोर आईडी के आधार पर फ्लैट टेबल का नाम मिलता है। जैसा कि स्टोर आईडी अभी सेट नहीं है, यह वर्तमान स्टोर आईडी लेता है।

तो स्पष्ट समाधान एक मॉडल प्राप्त करने से पहले एक वर्तमान स्टोर आईडी सेट करना होगा।

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

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

यह काम करेगा। लेकिन केवल अगर आपको एक बार एक संग्रह प्राप्त करने की आवश्यकता है। यदि आपको लूप में एक संग्रह प्राप्त करने की आवश्यकता है या आपको केवल दो बैक-टू-बैक संग्रह की आवश्यकता है, तो आप उनके लिए एक विशिष्ट स्टोर सेट करने में सक्षम नहीं होंगे।

कारण यह है कि Mage_Catalog_Model_Resource_Product_Flatवर्ग की अपनी _storeIdसंपत्ति है और निर्माणकर्ता में यह वर्तमान स्टोर आईडी पर सेट है। इसलिए इसे पहली बार सेट किया जाएगा। फिर किसी कारण से (स्वर्ग जानता है कि मुझे आशा है कि एक है) Mage_Eav_Model_Entity_Collection_Abstract::_initप्रत्येक संसाधन मॉड्यूल में एक सिंगलटन के रूप में लाया जाता है। तो 2 कॉल के लिए कोई कंस्ट्रक्टर नहीं।

यह सब इतना गलत लगता है कि मुझे पूरा यकीन है कि मैं गलत हूं और यह एक और मैगेंटो बग (या दो) नहीं है। आशा है कि कोई इस पर प्रकाश डाल सकता है।


क्या आपको getResourceModel () का उपयोग करना है क्योंकि यह आपको उदाहरण देता है? getModel ('कैटलॉग / रिसोर्स_प्रोडक्ट_कलेक्शन') बस काम कर सकती है।
पर फोमन

नहीं, यह बिल्कुल वैसा ही है। यह किसी भी तरह से रिसोर्स मॉडल सिंगलटन को इंस्टेंट कर रहा है।
user487772

टिम, कृपया इसे उत्तर के रूप में जोड़ें!
फेबियन ब्लेसश्मिड

@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स्टोरेज को संशोधित करने में सक्षम होने से पहले कहा जाता है, जिसका उपयोग तालिका नाम बनाने के लिए किया जाता है।

बेशक (यदि हम फिर से लिखना नहीं चाहते हैं) हम कर सकते हैं:

  • getSelect(), एक रीसेट करें और () से एक नया सेट करें
  • $collection->getEntity()->setStoreId(123)और फिर _initSelectदोबारा कॉल करने के लिए प्रतिबिंब का उपयोग करें
  • बस अपना स्वयं का संसाधन मॉडल बनाएं और फ्लैट से विस्तार करें, सही समय पर स्टोरआईड डालने का कुछ तरीका दें ( __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सेट बनाते हैं , तो यह स्टोर आईडी है, इसे क्लोन करें और एक अलग स्टोर आईडी सेट करें, फिर इसे संग्रह निर्माता को पास करें, क्या यह संभव होगा?
मेल्विन

1
@ समय: क्षमा करें, केवल आपकी टिप्पणी देखी। हां मुझे लगता है कि यह एक बग है।
डैनियल स्लॉफ जूल

शानदार जवाब के लिए, यह 1.14.2.0 के लिए काम कर रहा है
user4531

10

इसलिए मैं इन दो मैगेंटो में कीड़े को मानता हूं।

पहले एक तथ्य यह है कि आप catalog/productसंग्रह पर आईडी स्टोर नहीं कर सकते । और दूसरा यह है कि आप बिल्कुल गैर-सिंगलटन के रूप में संसाधन मॉडल प्राप्त नहीं कर सकते।

तो बेवकूफ वर्कअराउंड मॉडल को दो बार इंस्टेंट करना है। पहली बार स्टोर आईडी को सेट किया जा सकता है और दूसरा इंस्टेंटेशन इसका उपयोग करेगा:

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

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

मुझे नहीं पता कि मेरा सेट में मेरा स्टोर :: getModel ('कैटलॉग / श्रेणी') -> getProductCollection () -> setStoreId () काम नहीं किया और आपका काम हो गया। वैसे धन्यवाद
निकोल

3

दिलचस्प बात यह है कि प्रयुक्त फ्लैट टेबल को एक बार सेट किया जाता है और कभी नहीं बदला जाता है जो ईएवी के लिए काम करता है क्योंकि टेबल का नाम नहीं बदलता है लेकिन फ्लैट के लिए नहीं क्योंकि टेबल के नाम में स्टोर आईडी शामिल है। वर्कअराउंड एक सहायक बनाने के लिए होगा जो क्वेरी के 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');

मुझे लगता है कि इससे एसक्यूएल के लिए कोई परेशानी नहीं होगी क्योंकि आप एक ही फ्लैट टेबल से सभी डेटा प्राप्त कर रहे हैं, लेकिन चूंकि यह एक सिंगलटन है जिसका उपयोग अंतिम स्टोर हर जगह किया जाएगा।

वैकल्पिक समाधान यह होगा कि एक पर्यवेक्षक 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

कोर / 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();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.