Forzar que la colección de productos use EAV en lugar de una mesa plana

9

En Magento 2, ¿cómo puedo desactivar temporalmente el catálogo plano? Tengo una colección de productos asociada a una tienda frontend y quiero que se cargue a través de tablas EAV.

Observé cómo las colecciones determinan si se deben usar tablas planas, pero no encontré una manera de inyectar la configuración en ninguna parte.

En Magento 1, habría cambiado el valor de configuración cargado para "catálogo plano habilitado":

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

¿Todavía necesito recurrir a un estado global como este? ¿Si es así, cómo? ¿O hay una forma más elegante?

Fabian Schmengler
fuente

Respuestas:

9

El objeto responsable de determinar si el índice plano está disponible (clase Magento\Catalog\Model\Indexer\Product\Flat\State) es una instancia compartida inmutable. Pero es posible usar nuestra propia instancia, usando tipos virtuales.

Este es mi 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>

Ahora, tengo un tipo de fábrica de colección de productos virtual, donde $isAvailable = falseeventualmente se usa mi propia instancia de "Estado" :

disabledFlatStateProductCollectionFactory
 |
 + disabledFlatStateProductCollection
    |
    + disabledFlatState

Y para las clases donde necesito una fábrica de colecciones con índice plano deshabilitado, especifico el tipo virtual disabledFlatStateProductCollectionFactorypara el parámetro constructor correspondiente:

<arguments>
  <argument name="collectionFactory" xsi:type="object">disabledFlatStateProductCollectionFactory</argument>
</arguments>
Fabian Schmengler
fuente
¡La sustitución es lo más poderoso que le brinda la implementación DI de Magento! ¡Buena solución, voto personal de mi parte!
Ivan Chepurnyi
Esto no funciona para mi. :( Si tengo mi clase personalizada: public function __construct (\ Magento \ Catalog \ Model \ ResourceModel \ Product \ CollectionFactory $ collectionFactory) {$ this -> _ collectionFactory = $ collectionFactory;} Con el di.xml como explicaste, no lo hago 't ver que Magento está utilizando tipo virtual en lugar de recogida periódica producto.
mstojanov
6

Cuando se carga una colección de productos, este resultado determina el hecho de que use EAV o tablas planas \Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat().
Puede escribir un complemento aroundo after, que se devuelve falsesi se encuentra en el contexto de una determinada vista de la tienda.

O incluso mejor, los valores para el indicador plano se almacenan (en caché) en el miembro _flatEnabledde la misma clase.

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

Puede escribir lo mismo aroundo el aftercomplemento para el método \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable().
De esta manera, su complemento se ejecuta solo una vez. Podría ser útil si tiene una lógica pesada detrás o si se usa en otros lugares.

Esto se ve más elegante que cambiar un valor de configuración sobre la marcha.

Marius
fuente
Encontré una solución diferente sin ningún código personalizado, usando tipos virtuales. Pero como el tuyo se acerca y da una pista importante, ten un <del> kitkat </del> <ins> recompensa </ins>
Fabian Schmengler
¿Cómo escribir un plugin after para \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()?
Liam Mitchell el
1

La forma más elegante sería usar el mismo código que el código que habilita el modo plano al guardar la configuración. Se puede encontrar en 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);
        }
    }
}

Así que estoy bastante seguro de que podrías hacer algo así:

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

¿Dónde $this->_productFlatIndexerProcessorestá una instancia de \Magento\Catalog\Model\Indexer\Product\Flat\Processor.

Alternativa posible

Sin embargo, ese método no guarda la configuración, por lo que cuando el sistema verifica si Flat está habilitado a través de la configuración, aún devuelve verdadero.

Una posible alternativa (para ser probado) sería usar un complemento en el isFlatEnabledmétodo deMagento\Catalog\Model\Indexer\Product\Flat\State (el método está realmente definido en la Magento\Catalog\Model\Indexer\AbstractFlatStateclase).

Según lo que desee lograr, puede configurar un complemento posterior para forzar que el método devuelva falso bajo ciertas condiciones.

Raphael en Digital Pianism
fuente
Estoy bastante seguro, llamar setScheduled(false)al indexador no funciona porque solo deshabilita la indexación programada y no tendrá impacto en las colecciones. Pero independientemente, también guarda el modo, que definitivamente no es lo que quiero.
Fabian Schmengler
@fschmengler tiene toda la razón, especialmente porque el código que verifica si la tabla plana está habilitada usa la configuración directamente. Sin embargo, la solución alternativa lo superará;)
Raphael en Digital Pianism