强制产品收集使用EAV代替平板


9

在Magento 2中,如何临时禁用平面目录?我有一个与前端商店关联的产品集合,并希望通过EAV表加载它。

我查看了集合如何确定是否应使用平面表,但没有找到将设置注入到任何地方的方法。

在Magento 1中,我将更改“平面目录已启用”的已加载配置值:

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

我还需要这样诉诸于全球状态吗?如果是这样,怎么办?还是有一种更优雅的方式?

Answers:


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>

替换是Magento的DI实现为您提供的最强大的功能!好的解决方案,请我亲自投票!
伊万·谢普尔尼

这对我不起作用。:(如果我有我的自定义类:公共函数__construct(\ Magento \ Catalog \ Model \ ResourceModel \ Product \ CollectionFactory $ collectionFactory){$ this-> _ collectionFactory = $ collectionFactory;}正如您所解释的,使用di.xml,我不会没有看到Magento使用虚拟类型而不是常规产品集合
。– mstojanov

6

加载产品集合时,其使用EAV或平面表的事实由此结果确定\Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat()
您可以编写一个aroundafter插件,false如果您处于某个商店视图的上下文中则返回。

甚至更好的是,flat标记的值存储(缓存)在_flatEnabled同一类的成员中。

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

您可以为方法编写相同的代码aroundafter插件\Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()
这样,您的插件仅执行一次。如果背后有沉重的逻辑或在其他地方使用它,则可能会有所帮助。

与动态更改配置值相比,这看起来更优雅。


我发现了一个使用虚拟类型的解决方案,没有任何自定义代码。但是,由于您的情况最接近,并给出了重要提示,因此请提供一个<del> kitkat </ del> <ins>赏金</ ins>
Fabian Schmengler 2016年

如何编写一个after插件\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

可能的选择

但是,该方法不会保存配置,因此当系统检查是否通过配置启用了flat时,它仍然返回true。

可能的替代方案(待测试)是isFlatEnabled方法上使用插件Magento\Catalog\Model\Indexer\Product\Flat\State(该方法实际上是在Magento\Catalog\Model\Indexer\AbstractFlatState类中定义的)。

根据您要实现的目标,您可以设置一个after插件来强制该方法在某些情况下返回false。


我很确定,调用setScheduled(false)索引器是行不通的,因为它仅禁用计划的索引编制,并且不会对集合产生影响。但是无论如何,它还保存了模式,这绝对不是我想要的。
Fabian Schmengler '16

@fschmengler完全正确,特别是因为检查平面表是否已启用的代码直接使用了配置。替代解决方案将克服上述问题;)
拉斐尔(Raphael)在Digital Pianism
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.