Magento 2.3 - Swatches Helper override
-
28-03-2021 - |
Question
I'm trying to override a function in the Helper of the Swatches module of Magento 2. The function resides in the Data.php file. As some of you may know in specific versions of Magento 2 the text swatch values fall back to the default Admin value due to a bug.
A fix was issued here: https://github.com/magento/magento2/pull/15960
I am trying to implement this fix by overriding the function in Data.php using preference.
Since the Porto theme that I'm using is already overriding some other functions I decided to add my override there.
app/code/Smartwave/Porto/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
<type name="Smartwave\Porto\Block\Template">
<arguments>
<argument name="customTemplate" xsi:type="array">
<item name="context" xsi:type="string">\Magento\Framework\View\Element\Template\Context</item>
<item name="registry" xsi:type="string">\Magento\Framework\Registry</item>
</argument>
</arguments>
</type>
<type name="Smartwave\Porto\Block\CategoryCollection">
<arguments>
<argument name="categoryCollection" xsi:type="array">
<item name="context" xsi:type="string">\Magento\Framework\View\Element\Template\Context</item>
<item name="helper" xsi:type="string">\Magento\Catalog\Helper\Category</item>
<item name="flatstate" xsi:type="string">\Magento\Catalog\Model\Indexer\Category\Flat\State</item>
<item name="menu" xsi:type="string">\Magento\Theme\Block\Html\Topmenu</item>
</argument>
</arguments>
</type>
<preference for="Magento\Catalog\Controller\Category\View" type="Smartwave\Porto\Controller\Category\View" />
<preference for="Magento\CatalogSearch\Controller\Result\Index" type="Smartwave\Porto\Controller\CatalogSearch\Result\Index" />
<preference for="Magento\Catalog\Helper\Product\View" type="Smartwave\Porto\Helper\Product\View" />
<preference for="Magento\Swatches\Helper\Data" type="Smartwave\Porto\Helper\Swatches\Data" />
As you can see I added the preference on the last line.
app/code/Smartwave/Porto/Helper/Swatches/Data.php
namespace Smartwave\Porto\Helper\Swatches;
class Data extends \Magento\Swatches\Helper\Data
{
/**
* @param array $fallbackValues
* @param array $swatches
* @return array
*/
private function addFallbackOptions(array $fallbackValues, array $swatches)
{
$currentStoreId = $this->storeManager->getStore()->getId();
foreach ($fallbackValues as $optionId => $optionsArray) {
if (isset($optionsArray[$currentStoreId]['type'], $swatches[$optionId]['type'])
&& $swatches[$optionId]['type'] === $optionsArray[$currentStoreId]['type']
) {
$swatches[$optionId] = $optionsArray[$currentStoreId];
} elseif (isset($optionsArray[$currentStoreId])) {
$swatches[$optionId] = $optionsArray[$currentStoreId];
} elseif (isset($optionsArray[self::DEFAULT_STORE_ID])) {
$swatches[$optionId] = $optionsArray[self::DEFAULT_STORE_ID];
}
}
return $swatches;
}
}
However this doesn't seem to work. Is there anyone that can tell me why this is the case.
La solution
Your class should be:
use Magento\Swatches\Model\Swatch;
class Data extends \Magento\Swatches\Helper\Data
{
/**
* @var array
*/
private $swatchesCache = [];
/**
* @inheritDoc
*/
public function getSwatchesByOptionsId(array $optionIds)
{
$swatches = $this->getCachedSwatches($optionIds);
if (count($swatches) !== count($optionIds)) {
$swatchOptionIds = array_diff($optionIds, array_keys($swatches));
/** @var \Magento\Swatches\Model\ResourceModel\Swatch\Collection $swatchCollection */
$swatchCollection = $this->swatchCollectionFactory->create();
$swatchCollection->addFilterByOptionsIds($swatchOptionIds);
$swatches = [];
$fallbackValues = [];
$currentStoreId = $this->storeManager->getStore()->getId();
foreach ($swatchCollection as $item) {
if ($item['type'] != Swatch::SWATCH_TYPE_TEXTUAL) {
$swatches[$item['option_id']] = $item->getData();
} elseif ($item['store_id'] == $currentStoreId && $item['value'] != '') {
$fallbackValues[$item['option_id']][$currentStoreId] = $item->getData();
} elseif ($item['store_id'] == self::DEFAULT_STORE_ID) {
$fallbackValues[$item['option_id']][self::DEFAULT_STORE_ID] = $item->getData();
}
}
if (!empty($fallbackValues)) {
$swatches = $this->addFallbackOptions($fallbackValues, $swatches);
}
$this->setCachedSwatches($swatchOptionIds, $swatches);
}
return array_filter($this->getCachedSwatches($optionIds));
}
/**
* @inheritDoc
*/
private function addFallbackOptions(array $fallbackValues, array $swatches)
{
$currentStoreId = $this->storeManager->getStore()->getId();
foreach ($fallbackValues as $optionId => $optionsArray) {
if (isset($optionsArray[$currentStoreId]['type'], $swatches[$optionId]['type'])
&& $swatches[$optionId]['type'] === $optionsArray[$currentStoreId]['type']
) {
$swatches[$optionId] = $optionsArray[$currentStoreId];
} elseif (isset($optionsArray[$currentStoreId])) {
$swatches[$optionId] = $optionsArray[$currentStoreId];
} elseif (isset($optionsArray[self::DEFAULT_STORE_ID])) {
$swatches[$optionId] = $optionsArray[self::DEFAULT_STORE_ID];
}
}
return $swatches;
}
/**
* @inheritDoc
*/
private function getCachedSwatches(array $optionIds)
{
return array_intersect_key($this->swatchesCache, array_combine($optionIds, $optionIds));
}
/**
* @inheritDoc
*/
private function setCachedSwatches(array $optionIds, array $swatches)
{
foreach ($optionIds as $optionId) {
$this->swatchesCache[$optionId] = isset($swatches[$optionId]) ? $swatches[$optionId] : null;
}
}
}