Заставить коллекцию продуктов использовать EAV вместо плоского стола


9

В Magento 2, как я могу временно отключить плоский каталог? У меня есть коллекция продуктов, связанная с внешним магазином, и я хочу, чтобы она загружалась через таблицы EAV.

Я посмотрел, как коллекции определяют, следует ли использовать плоские таблицы, но не нашел способа внедрить настройки в любом месте.

В Magento 1 я бы изменил значение загруженной конфигурации на «плоский каталог включен»:

Mage::app()->getStore($storeId)->setConfig('catalog/frontend/flat_catalog_product', 0);

Нужно ли мне прибегать к такому глобальному состоянию? Если да, то как? Или есть более элегантный способ?

Ответы:


9

Объект, который должен определить, доступен ли плоский индекс (класс Magento\Catalog\Model\Indexer\Product\Flat\State), является неизменным общим экземпляром. Но можно использовать наш собственный экземпляр, используя виртуальные типы.

Это мое di.xml:

  <virtualType name="disabledFlatStateProductCollectionFactory" type="Magento\Catalog\Model\ResourceModel\Product\CollectionFactory">
    <arguments>
      <argument name="instanceName" xsi:type="string">disabledFlatStateProductCollection</argument>
    </arguments>
  </virtualType>
  <virtualType name="disabledFlatStateProductCollection" type="Magento\Catalog\Model\ResourceModel\Product\Collection">
    <arguments>
      <argument name="catalogProductFlatState" xsi:type="object">disabledFlatState</argument>
    </arguments>
  </virtualType>
  <virtualType name="disabledFlatState" type="Magento\Catalog\Model\Indexer\Product\Flat\State">
    <arguments>
      <argument name="isAvailable" xsi:type="boolean">false</argument>
    </arguments>
  </virtualType>

Теперь у меня есть тип фабрики виртуальных коллекций продуктов, где в $isAvailable = falseконечном итоге используется мой собственный экземпляр State с :

disabledFlatStateProductCollectionFactory
 |
 + disabledFlatStateProductCollection
    |
    + disabledFlatState

А для классов, где мне нужна фабрика коллекций с отключенным плоским индексом, я указываю виртуальный тип disabledFlatStateProductCollectionFactoryдля соответствующего параметра конструктора:

<arguments>
  <argument name="collectionFactory" xsi:type="object">disabledFlatStateProductCollectionFactory</argument>
</arguments>

Замена - самая мощная вещь, которую дает вам реализация DI Magento! Хорошее решение, личное мнение от меня!
Иван Чепурный

Это не работает для меня. :( Если у меня есть свой пользовательский класс: public, функция __construct (\ Magento \ Catalog \ Model \ ResourceModel \ Product \ CollectionFactory $ collectionFactory) {$ this -> _ collectionFactory = $ collectionFactory;} С помощью di.xml, как вы объяснили, я не буду не вижу, что Magento использует виртуальный тип вместо обычной коллекции продуктов
mstojanov

6

Когда коллекция продуктов загружена, тот факт, что она использует EAV или плоские таблицы, определяется этим результатом \Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat().
Вы можете написать aroundили afterплагин, который возвращается, falseесли вы находитесь в контексте определенного представления магазина.

Или, что еще лучше, значения для плоского флага хранятся (кэшируются) в элементе _flatEnabledиз того же класса.

public function isEnabledFlat()
{
    if (!isset($this->_flatEnabled[$this->getStoreId()])) {
        $this->_flatEnabled[$this->getStoreId()] = $this->getFlatState()->isAvailable();
    }
    return $this->_flatEnabled[$this->getStoreId()];
}

Вы можете написать то же самое aroundили afterплагин для метода \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable().
Таким образом, ваш плагин выполняется только один раз. Это может быть полезно, если у вас есть тяжелая логика или если он используется в других местах.

Это выглядит более элегантно, чем изменение значения конфигурации на лету.


Я нашел другое решение без какого-либо пользовательского кода, используя виртуальные типы. Но так как ваш самый близкий и дал важный совет, имейте <del> kitkat </ del> <ins> bounty </ ins>
Фабиан Шменглер

Как написать плагин после \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()?
Лиам Митчелл

1

Более элегантный способ - использовать тот же код, что и код, который включает плоский режим при сохранении конфигурации. Его можно найти под Magento/Catalog/Model/Indexer/Product/Flat/System/Config/Mode:

public function processValue()
{
    if ((bool)$this->getValue() != (bool)$this->getOldValue()) {
        if ((bool)$this->getValue()) {
            $this->indexerState->loadByIndexer(\Magento\Catalog\Model\Indexer\Product\Flat\Processor::INDEXER_ID);
            $this->indexerState->setStatus(\Magento\Framework\Indexer\StateInterface::STATUS_INVALID);
            $this->indexerState->save();
        } else {
            $this->_productFlatIndexerProcessor->getIndexer()->setScheduled(false);
        }
    }
}

Так что я уверен, что вы могли бы сделать что-то подобное:

$this->_productFlatIndexerProcessor->getIndexer()->setScheduled(false);

Где $this->_productFlatIndexerProcessorэто экземпляр \Magento\Catalog\Model\Indexer\Product\Flat\Processor.

Возможная альтернатива

Однако этот метод не сохраняет конфигурацию, поэтому, когда система проверяет, включена ли квартира через конфигурацию, она все равно возвращает значение true.

Возможной альтернативой (подлежащей проверке) будет использование плагина для isFlatEnabledметода fromMagento\Catalog\Model\Indexer\Product\Flat\State (метод фактически определен в Magento\Catalog\Model\Indexer\AbstractFlatStateклассе).

В зависимости от того, чего вы хотите достичь, вы можете установить плагин after, чтобы этот метод возвращал false при определенных условиях.


Я почти уверен, что вызов setScheduled(false)индексатора не работает, потому что он отключает только запланированное индексирование и не влияет на коллекции. Но независимо от этого, он также сохраняет режим, который, безусловно, не то, что я хочу.
Фабиан Шменглер

@fschmengler совершенно прав, особенно потому, что код, который проверяет, включен ли плоский стол, напрямую использует конфигурацию. Альтернативное решение преодолеет это хотя;)
Рафаэль в Цифровом Пианизме
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.