Force products collection to use EAV instead of flat table
The object which is responsible to determine if flat index is available (class Magento\Catalog\Model\Indexer\Product\Flat\State
) is an immutable shared instance. But it is possible to use our own instance, using virtual types.
This is my 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>
Now, I have a virtual product collection factory type, where my own "State" instance with $isAvailable = false
is used eventually:
disabledFlatStateProductCollectionFactory
|
+ disabledFlatStateProductCollection
|
+ disabledFlatState
And for the classes where I need a collection factory with disabled flat index, I specify the virtual type disabledFlatStateProductCollectionFactory
for the corresponding constructor parameter:
<arguments>
<argument name="collectionFactory" xsi:type="object">disabledFlatStateProductCollectionFactory</argument>
</arguments>
When a product collection is loaded, the fact that it uses EAV or flat tables is determined by this result \Magento\Catalog\Model\ResourceModel\Product\Collection::isEnabledFlat()
.
You can write an around
or after
plugin, that returns false
if you are in the context of a certain store view.
Or even better, the values for flat flag are stored (cached) in the member _flatEnabled
from the same class.
public function isEnabledFlat()
{
if (!isset($this->_flatEnabled[$this->getStoreId()])) {
$this->_flatEnabled[$this->getStoreId()] = $this->getFlatState()->isAvailable();
}
return $this->_flatEnabled[$this->getStoreId()];
}
You can write the same around
or after
plugin for the method \Magento\Catalog\Model\Indexer\Product\Flat\State::isAvailable()
.
This way your plugin is executed only once. It could be helpful if you have heavy logic behind it or if it is used in other places.
This looks more elegant that changing a config value on the fly.