Erzwingen Sie, dass die Produktsammlung EAV anstelle eines flachen Tisches verwendet

9

Wie kann ich in Magento 2 den Flat-Katalog vorübergehend deaktivieren? Ich habe eine Produktkollektion, die einem Frontend-Store zugeordnet ist, und möchte, dass sie über EAV-Tabellen geladen wird.

Ich habe nachgesehen, wie die Sammlungen bestimmen, ob flache Tische verwendet werden sollen, habe aber keine Möglichkeit gefunden, die Einstellung irgendwo einzufügen.

In Magento 1 hätte ich den geladenen Konfigurationswert für "Flat Catalogable Enabled" geändert:

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

Muss ich immer noch auf einen solchen globalen Staat zurückgreifen? Wenn das so ist, wie? Oder gibt es einen eleganteren Weg?

Fabian Schmengler
quelle

Antworten:

9

Das Objekt, das dafür verantwortlich ist, festzustellen, ob ein flacher Index verfügbar ist (Klasse Magento\Catalog\Model\Indexer\Product\Flat\State), ist eine unveränderliche gemeinsam genutzte Instanz. Es ist jedoch möglich, eine eigene Instanz mit virtuellen Typen zu verwenden.

Das ist mein 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>

Jetzt habe ich einen Factory-Typ für die virtuelle Produktsammlung, in dem schließlich meine eigene "State" -Instanz mit $isAvailable = falseverwendet wird:

disabledFlatStateProductCollectionFactory
 |
 + disabledFlatStateProductCollection
    |
    + disabledFlatState

Und für die Klassen, in denen ich eine Sammlungsfactory mit deaktiviertem Flat-Index benötige, gebe ich den virtuellen Typ disabledFlatStateProductCollectionFactoryfür den entsprechenden Konstruktorparameter an:

<arguments>
  <argument name="collectionFactory" xsi:type="object">disabledFlatStateProductCollectionFactory</argument>
</arguments>
Fabian Schmengler
quelle
Substitution ist die mächtigste Sache, die Ihnen die DI-Implementierung von Magento bietet! Gute Lösung, persönliche Gegenstimme von mir!
Ivan Chepurnyi
Das funktioniert bei mir nicht. :( Wenn ich meine benutzerdefinierte Klasse habe: public function __construct (\ Magento \ Catalog \ Model \ ResourceModel \ Product \ CollectionFactory $ collectionFactory) {$ this -> _ collectionFactory = $ collectionFactory;} Mit der di.xml, wie Sie erklärt haben, habe ich nicht
Ich
6

Wenn eine Produktsammlung geladen wird, wird die Tatsache, dass EAV oder flache Tabellen verwendet werden, durch dieses Ergebnis bestimmt \Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat().
Sie können ein aroundoder ein afterPlugin schreiben , das zurückgegeben wird, falsewenn Sie sich im Kontext einer bestimmten Geschäftsansicht befinden.

Oder noch besser, die Werte für das flache Flag werden im Member _flatEnabledderselben Klasse gespeichert (zwischengespeichert) .

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

Sie können dasselbe aroundoder afterPlugin für die Methode schreiben \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable().
Auf diese Weise wird Ihr Plugin nur einmal ausgeführt. Es kann hilfreich sein, wenn Sie eine starke Logik dahinter haben oder wenn es an anderen Orten verwendet wird.

Dies sieht eleganter aus, als wenn Sie einen Konfigurationswert im laufenden Betrieb ändern.

Marius
quelle
Ich habe eine andere Lösung ohne benutzerdefinierten Code mit virtuellen Typen gefunden. Aber da Ihre am nächsten kommt und einen wichtigen Hinweis gab, haben Sie ein <del> kitkat </ del> <ins> Kopfgeld </ in>
Fabian Schmengler
Wie schreibe ich ein After Plugin für \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()?
Liam Mitchell
1

Der elegantere Weg wäre, denselben Code wie den Code zu verwenden, der den Flat-Modus beim Speichern der Konfiguration aktiviert. Es kann gefunden werden unter 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);
        }
    }
}

Ich bin mir ziemlich sicher, dass Sie so etwas tun können:

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

Wo $this->_productFlatIndexerProcessorist eine Instanz von \Magento\Catalog\Model\Indexer\Product\Flat\Processor.

Mögliche Alternative

Diese Methode speichert die Konfiguration jedoch nicht. Wenn das System prüft, ob flat über die Konfiguration aktiviert ist, wird weiterhin true zurückgegeben.

Eine mögliche Alternative (zu testen) wäre die Verwendung eines Plugins für die isFlatEnabledMethode vonMagento\Catalog\Model\Indexer\Product\Flat\State (die Methode ist tatsächlich in der Magento\Catalog\Model\Indexer\AbstractFlatStateKlasse definiert ).

Basierend auf dem, was Sie erreichen möchten, können Sie ein After-Plugin einrichten, um zu erzwingen, dass diese Methode unter bestimmten Bedingungen false zurückgibt.

Raphael beim digitalen Pianismus
quelle
Ich bin mir ziemlich sicher, dass das Aufrufen setScheduled(false)des Indexers nicht funktioniert, da es nur die geplante Indizierung deaktiviert und keine Auswirkungen auf die Sammlungen hat. Aber unabhängig davon speichert es auch den Modus, was definitiv nicht das ist, was ich will.
Fabian Schmengler
@fschmengler völlig richtig, vor allem, weil der Code, der prüft, ob die flache Tabelle aktiviert ist, die Konfiguration direkt verwendet. Die alternative Lösung wird das allerdings überwinden;)
Raphael beim Digital Pianism