Forcer la collecte de produits à utiliser l'EAV au lieu d'une table plate

9

Dans Magento 2, comment puis-je désactiver temporairement le catalogue plat? J'ai une collection de produits associée à un magasin frontal et je souhaite qu'elle soit chargée via des tables EAV.

J'ai regardé comment les collections déterminent si les tables plates doivent être utilisées, mais je n'ai trouvé aucun moyen d'injecter le paramètre n'importe où.

Dans Magento 1, j'aurais changé la valeur de configuration chargée pour "catalogue plat activé":

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

Dois-je encore recourir à un état mondial comme celui-ci? Si c'est le cas, comment? Ou existe-t-il une manière plus élégante?

Fabian Schmengler
la source

Réponses:

9

L'objet chargé de déterminer si un index plat est disponible (classe Magento\Catalog\Model\Indexer\Product\Flat\State) est une instance partagée immuable. Mais il est possible d'utiliser notre propre instance, en utilisant des types virtuels.

C'est mon 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>

Maintenant, j'ai un type d'usine de collection de produits virtuels, où ma propre instance "State" avec $isAvailable = falseest finalement utilisée:

disabledFlatStateProductCollectionFactory
 |
 + disabledFlatStateProductCollection
    |
    + disabledFlatState

Et pour les classes où j'ai besoin d'une fabrique de collection avec un index plat désactivé, je spécifie le type virtuel disabledFlatStateProductCollectionFactorypour le paramètre constructeur correspondant:

<arguments>
  <argument name="collectionFactory" xsi:type="object">disabledFlatStateProductCollectionFactory</argument>
</arguments>
Fabian Schmengler
la source
La substitution est la chose la plus puissante que l'implémentation DI de Magento vous donne! Bonne solution, vote personnel de ma part!
Ivan Chepurnyi
Ça ne marche pas pour moi. :( Si j'ai ma classe personnalisée: fonction publique __construct (\ Magento \ Catalog \ Model \ ResourceModel \ Product \ CollectionFactory $ collectionFactory) {$ this -> _ collectionFactory = $ collectionFactory;} Avec le di.xml comme vous l'avez expliqué, je ne ne vois pas que Magento utilise le type virtuel au lieu de la collection de produits régulière.
mstojanov
6

Lorsqu'une collection de produits est chargée, le fait qu'elle utilise EAV ou des tables plates est déterminé par ce résultat \Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat().
Vous pouvez écrire un plugin aroundou after, qui revient falsesi vous êtes dans le contexte d'une certaine vue de magasin.

Ou encore mieux, les valeurs de l'indicateur plat sont stockées (mises en cache) dans le membre _flatEnabledde la même classe.

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

Vous pouvez écrire le même aroundou afterplugin pour la méthode \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable().
De cette façon, votre plugin n'est exécuté qu'une seule fois. Cela pourrait être utile si vous avez une logique lourde derrière elle ou si elle est utilisée dans d'autres endroits.

Cela semble plus élégant que de changer une valeur de configuration à la volée.

Marius
la source
J'ai trouvé une solution différente sans aucun code personnalisé, en utilisant des types virtuels. Mais puisque le vôtre se rapproche le plus et a donné un indice important, ayez un <del> kitkat </del> <ins> bounty </ins>
Fabian Schmengler
Comment écrire un plugin après \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()?
Liam Mitchell
1

La manière la plus élégante serait d' utiliser le même code que le code qui active le mode plat lors de l'enregistrement de la configuration. Il se trouve sous 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);
        }
    }
}

Je suis donc sûr que vous pourriez faire quelque chose comme ça:

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

$this->_productFlatIndexerProcessorest une instance de \Magento\Catalog\Model\Indexer\Product\Flat\Processor.

Alternative possible

Cependant, cette méthode n'enregistre pas la configuration, donc lorsque le système vérifie si le flat est activé via la configuration, il renvoie toujours true.

Une alternative possible (à tester) serait d' utiliser un plugin sur la isFlatEnabledméthode deMagento\Catalog\Model\Indexer\Product\Flat\State (la méthode est en fait définie dans la Magento\Catalog\Model\Indexer\AbstractFlatStateclasse).

En fonction de ce que vous souhaitez réaliser, vous pouvez configurer un plugin After pour forcer cette méthode à retourner false dans certaines conditions.

Raphael chez Digital Pianism
la source
Je suis à peu près sûr, appeler setScheduled(false)l'indexeur ne fonctionne pas car il ne désactive que l'indexation planifiée et n'aura pas d'impact sur les collections. Mais quoi qu'il en soit, il enregistre également le mode, ce qui n'est certainement pas ce que je veux.
Fabian Schmengler
@fschmengler a parfaitement raison, spécialement parce que le code qui vérifie si la table plate est activée utilise directement la configuration. La solution alternative permettra de surmonter cela cependant;)
Raphael au Digital Pianism