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.

Was it helpful?

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;
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top