1
votes

We just upgraded our site from Magento 1.9.1.1 to Magento 1.9.3.3.

Unfortunately, our site is broken, so I have investigated the issue. The error notification are as follow.


Fatal error: Uncaught Error: Call to undefined method 

Mage_ConfigurableSwatches_Helper_Mediafallback::attachProductChildrenAttributeMapping() in /var/www/html/source/app/code/core/Mage/ConfigurableSwatches/Model/Observer.php:59 Stack trace: #0 /var/www/html/source/app/code/core/Mage/Core/Model/App.php(1358): Mage_ConfigurableSwatches_Model_Observer-productListCollectionLoadAfter(Object(Varien_Event_Observer)) #1 /var/www/html/source/app/code/core/Mage/Core/Model/App.php(1337): Mage_Core_Model_App-_callObserverMethod(Object(Mage_ConfigurableSwatches_Model_Observer), 'productListColl...', Object(Varien_Event_Observer)) #2 /var/www/html/source/app/Mage.php(448): Mage_Core_Model_App-dispatchEvent('catalog_block_p...', Array) #3 /var/www/html/source/app/code/core/Mage/Catalog/Block/Product/List.php(160): Mage::dispatchEvent('catalog_block_p...', Array) #4 /var/www/html/source/app/code/core/Mage/Core/Block/Abstract.php(922): Mage_Catalog_Block_Product_Li in /var/www/html/source/app/code/core/Mage/ConfigurableSwatches/Model/Observer.php on line 59


That code block is as follow.

public function productListCollectionLoadAfter(Varien_Event_Observer $observer)
{
    if (!Mage::helper('configurableswatches')->isEnabled()) { // check if functionality disabled
        return; // exit without loading swatch functionality
    }

    /* @var $mediaHelper Mage_ConfigurableSwatches_Helper_Mediafallback */
    $mediaHelper = Mage::helper('configurableswatches/mediafallback');

    /** @var $priceHelper Mage_ConfigurableSwatches_Helper_List_Price */
    $priceHelper = Mage::helper('configurableswatches/list_price');

    /* @var $collection Mage_Catalog_Model_Resource_Product_Collection */
    $collection = $observer->getCollection();

    if ($collection
        instanceof Mage_ConfigurableSwatches_Model_Resource_Catalog_Product_Type_Configurable_Product_Collection) {
        // avoid recursion
        return;
    }

    $products = $collection->getItems();

    $mediaHelper->attachChildrenProducts($products, $collection->getStoreId());

    $mediaHelper->attachProductChildrenAttributeMapping($products, $collection->getStoreId());

    if ($priceHelper->isEnabled()) {
        $priceHelper->attachConfigurableProductChildrenPricesMapping($products, $collection->getStoreId());
    }

    $mediaHelper->attachGallerySetToCollection($products, $collection->getStoreId());

    /* @var $product Mage_Catalog_Model_Product */
    foreach ($products as $product) {
        $mediaHelper->groupMediaGalleryImages($product);
        Mage::helper('configurableswatches/productimg')
            ->indexProductImages($product, $product->getListSwatchAttrValues());
    }

}

The old block (Magento1.9.1.0) is follow.

public function productListCollectionLoadAfter(Varien_Event_Observer $observer)
{
    if (!Mage::helper('configurableswatches')->isEnabled()) { // check if functionality disabled
        return; // exit without loading swatch functionality
    }

    /* @var $helper Mage_ConfigurableSwatches_Helper_Mediafallback */
    $helper = Mage::helper('configurableswatches/mediafallback');

    /* @var $collection Mage_Catalog_Model_Resource_Product_Collection */
    $collection = $observer->getCollection();

    if ($collection
        instanceof Mage_ConfigurableSwatches_Model_Resource_Catalog_Product_Type_Configurable_Product_Collection) {
        // avoid recursion
        return;
    }

    $products = $collection->getItems();

    $helper->attachChildrenProducts($products, $collection->getStoreId());

    $helper->attachConfigurableProductChildrenAttributeMapping($products, $collection->getStoreId());

    $helper->attachGallerySetToCollection($products, $collection->getStoreId());

    /* @var $product Mage_Catalog_Model_Product */
    foreach ($products as $product) {
        $helper->groupMediaGalleryImages($product);
        Mage::helper('configurableswatches/productimg')
            ->indexProductImages($product, $product->getListSwatchAttrValues());
    }

}

To fix the site broken issue, I disabled the color swatch setting on System/Catalog/Configurable Swatches/General Settings.

Then, our site was retrieved. But, of course, color swatch functions didn't work anymore.

To ensure whether this issue is core bug or not, I installed raw Magento 1.9.3.3 on local server. But, the same issue.

Is there any solution?

2

2 Answers

3
votes

To solve this issue, we checked the whole custom modules.

app\code\local\Mage\ConfigurableSwatches\Helper\Mediafallback.php

The old developer created this custom module so that new Magento version's Mediafallback.php didn't work. This is the correct original core php file.

app\code\core\Mage\ConfigurableSwatches\Helper\Mediafallback.php

public function attachProductChildrenAttributeMapping(array $parentProducts, $storeId, $onlyListAttributes = false)
{
    /** @var  $listSwatchAttr Mage_Eav_Model_Attribute */
    $listSwatchAttr = Mage::helper('configurableswatches/productlist')->getSwatchAttribute();
    $swatchAttributeIds = array();
    if (!$onlyListAttributes) {
        $swatchAttributeIds = Mage::helper('configurableswatches')->getSwatchAttributeIds();
    }
    if ($listSwatchAttr->getId()) {
        $swatchAttributeIds[] = $listSwatchAttr->getId();
    }
    if (empty($swatchAttributeIds)) {
        return;
    }

    $parentProductIds = array();
    /* @var $parentProduct Mage_Catalog_Model_Product */
    foreach ($parentProducts as $parentProduct) {
        $parentProductIds[] = $parentProduct->getId();
    }

    $configAttributes = Mage::getResourceModel('configurableswatches/catalog_product_attribute_super_collection')
        ->addParentProductsFilter($parentProductIds)
        ->attachEavAttributes()
        ->addFieldToFilter('eav_attributes.attribute_id', array('in' => $swatchAttributeIds))
        ->setStoreId($storeId)
    ;

    $optionLabels = array();
    foreach ($configAttributes as $attribute) {
        $optionLabels += $attribute->getOptionLabels();
    }

    // normalize to all lower case before we start using them
    $optionLabels = array_map(function ($value) {
        return array_map('Mage_ConfigurableSwatches_Helper_Data::normalizeKey', $value);
    }, $optionLabels);

    foreach ($parentProducts as $parentProduct) {
        $mapping = array();
        $listSwatchValues = array();
        $listSwatchStockValues = array();

        /* @var $attribute Mage_Catalog_Model_Product_Type_Configurable_Attribute */
        foreach ($configAttributes as $attribute) {
            /* @var $childProduct Mage_Catalog_Model_Product */
            if (!is_array($parentProduct->getChildrenProducts())) {
                continue;
            }

            foreach ($parentProduct->getChildrenProducts() as $childProduct) {

                // product has no value for attribute or not available, we can't process it
                $isInStock = $childProduct->getStockItem()->getIsInStock();
                if (!$childProduct->hasData($attribute->getAttributeCode())
                    || (!$isInStock && !Mage::helper('cataloginventory')->isShowOutOfStock())) {
                    continue;
                }
                $optionId = $childProduct->getData($attribute->getAttributeCode());

                // if we don't have a default label, skip it
                if (!isset($optionLabels[$optionId][0])) {
                    continue;
                }

                // using default value as key unless store-specific label is present
                $optionLabel = $optionLabels[$optionId][0];
                if (isset($optionLabels[$optionId][$storeId])) {
                    $optionLabel = $optionLabels[$optionId][$storeId];
                }

                // initialize arrays if not present
                if (!isset($mapping[$optionLabel])) {
                    $mapping[$optionLabel] = array(
                        'product_ids' => array(),
                    );
                }
                $mapping[$optionLabel]['product_ids'][] = $childProduct->getId();
                $mapping[$optionLabel]['label'] = $optionLabel;
                $mapping[$optionLabel]['default_label'] = $optionLabels[$optionId][0];
                $mapping[$optionLabel]['labels'] = $optionLabels[$optionId];

                if ($attribute->getAttributeId() == $listSwatchAttr->getAttributeId()
                    && !in_array($mapping[$optionLabel]['label'], $listSwatchValues)
                ) {
                    $listSwatchValues[$optionId]      = $mapping[$optionLabel]['label'];
                    $listSwatchStockValues[$optionId] = $isInStock;
                }
            } // end looping child products
        } // end looping attributes


        foreach ($mapping as $key => $value) {
            $mapping[$key]['product_ids'] = array_unique($mapping[$key]['product_ids']);
        }

        if (count($listSwatchValues)) {
            $listSwatchValues = array_replace(array_intersect_key($optionLabels, $listSwatchValues),
                $listSwatchValues);
        }
        $parentProduct->setChildAttributeLabelMapping($mapping)
            ->setListSwatchAttrValues($listSwatchValues)
            ->setListSwatchAttrStockValues($listSwatchStockValues);
    } // end looping parent products
}

Also, these articles maybe help our solution.

https://magento.stackexchange.com/questions/45948/how-to-use-magento-1-9-1-0-configurable-swatches-in-default-package-theme-or-a https://magento.stackexchange.com/questions/142404/configurable-swatches-not-working-after-1-9-3-upgrade

2
votes

Add js in catalog.xml file on catalog_product_view section

<action method="addJs"><script>varien/product_options.js</script></action>