Forçar a coleta de produtos a usar EAV em vez de mesa plana

9

No Magento 2, como posso desativar temporariamente o catálogo plano? Eu tenho uma coleção de produtos associada a uma loja de front-end e quero que ela seja carregada por meio de tabelas EAV.

Examinei como as coleções determinam se as tabelas simples devem ser usadas, mas não encontrei uma maneira de injetar a configuração em nenhum lugar.

No Magento 1, eu teria alterado o valor da configuração carregada para "catálogo plano ativado":

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

Ainda preciso recorrer a um estado global como este? Se sim, como? Ou existe uma maneira mais elegante?

Fabian Schmengler
fonte

Respostas:

9

O objeto responsável por determinar se o índice simples está disponível (classe Magento\Catalog\Model\Indexer\Product\Flat\State) é uma instância compartilhada imutável. Mas é possível usar nossa própria instância, usando tipos virtuais.

Este é o meu 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>

Agora, eu tenho um tipo de fábrica de coleção de produtos virtual, onde minha própria instância "State" $isAvailable = falseé usada eventualmente:

disabledFlatStateProductCollectionFactory
 |
 + disabledFlatStateProductCollection
    |
    + disabledFlatState

E para as classes em que preciso de uma fábrica de coleções com índice plano desabilitado, especifique o tipo virtual disabledFlatStateProductCollectionFactorypara o parâmetro do construtor correspondente:

<arguments>
  <argument name="collectionFactory" xsi:type="object">disabledFlatStateProductCollectionFactory</argument>
</arguments>
Fabian Schmengler
fonte
Substituição é a coisa mais poderosa que a implementação DI do Magento oferece a você! Boa solução, voto pessoal pessoal de mim!
Ivan Chepurnyi
Isso não funciona para mim. :( Se eu tiver minha classe personalizada: public function __construct (\ Magento \ Catalog \ Model \ ResourceModel \ Product \ CollectionFactory $ collectionFactory) {$ this -> _ collectionFactory = $ collectionFactory;} Com o di.xml como você explicou, eu não 't ver que Magento é usando o tipo virtual em vez de coleta de produto regular.
mstojanov
6

Quando uma coleção de produtos é carregada, o fato de usar EAV ou tabelas simples é determinado por esse resultado \Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat().
Você pode escrever um aroundou afterplugin, que retornará falsese você estiver no contexto de uma determinada visualização da loja.

Ou melhor ainda, os valores para sinalizador plano são armazenados (armazenados em cache) no membro _flatEnabledda mesma classe.

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

Você pode escrever o mesmo aroundou afterplugin para o método \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable().
Dessa forma, seu plugin é executado apenas uma vez. Pode ser útil se você tiver uma lógica pesada por trás ou se for usado em outros lugares.

Parece mais elegante do que alterar um valor de configuração rapidamente.

Marius
fonte
Encontrei uma solução diferente sem nenhum código personalizado, usando tipos virtuais. Mas desde que o seu se aproxima e deu uma dica importante, ter um <del> kitkat </ del> <ins> generosidade </ ins>
Fabian Schmengler
Como escrever um plugin depois para \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()?
Liam Mitchell
1

A maneira mais elegante seria usar o mesmo código que habilita o modo plano ao salvar a configuração. Pode ser encontrado em 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);
        }
    }
}

Então, eu tenho certeza que você poderia fazer algo assim:

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

Onde $this->_productFlatIndexerProcessoré uma instância de \Magento\Catalog\Model\Indexer\Product\Flat\Processor.

Alternativa possível

No entanto, esse método não salva a configuração, portanto, quando o sistema verifica se o flat está ativado por meio da configuração, ele ainda retorna verdadeiro.

Uma alternativa possível (a ser testada) seria usar um plugin no isFlatEnabledmétodo deMagento\Catalog\Model\Indexer\Product\Flat\State (o método é realmente definido na Magento\Catalog\Model\Indexer\AbstractFlatStateclasse).

Com base no que você deseja alcançar, você pode configurar um plug-in after para forçar esse método a retornar false sob certas condições.

Raphael na Digital Pianism
fonte
Tenho certeza de que chamar setScheduled(false)o indexador não funciona porque está apenas desativando a indexação agendada e não terá impacto nas coleções. Mas, independentemente disso, ele também salva o modo, que definitivamente não é o que eu quero.
Fabian Schmengler
@fschmengler totalmente certo, especialmente porque o código que verifica se a tabela plana está ativada usa a configuração diretamente. A solução alternativa vai superar isso embora;)
Raphael em Digital pianismo