Задача тривиальная. Мне нужно получить список товаров для конкретного магазина с включенным плоским каталогом. Наиболее очевидным решением является следующее:
$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-го вызова.
Все это выглядит так неправильно, что я почти уверен, что ошибаюсь, и это не очередной баг Magento (или два). Надеюсь, что кто-то может пролить свет на это.
источник
Ответы:
Какая версия Magento это? Вот мои результаты для Magento 1.9:
Плоский каталог включен:
Плоский каталог проиндексирован:
Некоторый набор данных в определенном представлении магазина:
Используемый код:
Результат, как и ожидалось:
редактировать:
Неважно, плоский каталог специально запрещен для администратора магазина:
Исследуя ...
edit2:
Похоже, ты прав.
_initSelect
вызывается до того, как мы сможем изменить storeId, который используется для генерации имени таблицы.Конечно (если мы не хотим идти по пути переписывания), мы можем:
getSelect()
, сделать сброс и установить новый из ()$collection->getEntity()->setStoreId(123)
а затем использовать отражение, чтобы позвонить_initSelect
снова__construct
задержкой_initSelect
и т. Д.).setCurrentStore
каждый раз, когда мы создаем коллекцию.Но все они чувствуют себя очень нахально ... Извините, это может быть неудовлетворительным ответом :-(
Edit3:
Таким образом , для обеспечения , по меньшей мере , в ответ:
Пожалуйста, не используйте это ;-)
источник
product_collection
конструктор принимает модель ресурса в качестве аргумента. Так что если вы создадитеProduct_Resource_Flat
, зададите идентификатор хранилища, клонируете его и зададите другой идентификатор хранилища, а затем передадите его конструктору коллекции, это будет выполнимо?Поэтому я считаю, что это две ошибки в Magento.
Во-первых, вы не можете установить идентификатор магазина в
catalog/product
коллекции. И второе: вы абсолютно не можете получить модель ресурсов как не-синглтон.Так что глупый обходной путь - дважды создавать экземпляр модели. Первый раз, когда идентификатор магазина может быть установлен, и второй экземпляр будет использовать его:
источник
Интересно, что используемая плоская таблица устанавливается один раз и никогда не изменяется, что работает для EAV, поскольку имя таблицы не меняется, но не для плоской, поскольку имя таблицы включает в себя идентификатор магазина. Обходной путь может заключаться в создании помощника, который будет заменять таблицу в части запроса FROM. Вот пример такого помощника:
Тогда вы можете использовать его просто с:
Я предполагаю, что это не вызовет проблем для SQL, поскольку вы извлекаете все данные из одной плоской таблицы, но, поскольку это одноэлементное хранилище, последнее использованное хранилище будет использоваться везде.
Альтернативное решение было бы сделать наблюдателя,
catalog_product_collection_load_before
который делает что-то вроде этого:Я согласен, что ребята из Magento должны исправить это в
_beforeLoad()
методе.источник
Почему бы не использовать обычный фильтр?
$collection->addAttributeToFilter('store_id', $store_id);
store_id указан как обычный столбец в таблице * _eav_entity , так что вы также можете фильтровать по нему. Работал на меня.
источник
Будь моим решением это решение с core / app_emulation:
источник