cancel
Showing results for 
Search instead for 
Did you mean: 

Error after upgrading to 2.3.0

Error after upgrading to 2.3.0

Hi I have updated the magento 2 and the website broke after the update the Error I am getting after trying to open the frontend: Screenshot 2019-01-15 at 11.10.26.png

I am using Claue Theme 1.7.8

Cant find anything on the google about this error. the code below is from my Data.php file. 

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\Swatches\Helper;

use Magento\Catalog\Api\Data\ProductInterface as Product;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Helper\Image;
use Magento\Catalog\Model\Product as ModelProduct;
use Magento\Catalog\Model\Product\Image\UrlBuilder;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory as SwatchCollectionFactory;
use Magento\Swatches\Model\Swatch;
use Magento\Swatches\Model\SwatchAttributesProvider;
use Magento\Swatches\Model\SwatchAttributeType;

/**
 * Class Helper Data
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Data
{
    /**
     * When we init media gallery empty image types contain this value.
     */
    const EMPTY_IMAGE_VALUE = 'no_selection';

    /**
     * Default store ID
     */
    const DEFAULT_STORE_ID = 0;

    /**
     * @var CollectionFactory
     */
    protected $productCollectionFactory;

    /**
     * @var ProductRepositoryInterface
     */
    protected $productRepository;

    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @var SwatchCollectionFactory
     */
    protected $swatchCollectionFactory;

    /**
     * Product metadata pool
     *
     * @var \Magento\Framework\EntityManager\MetadataPool
     */
    private $metadataPool;

    /**
     * @var SwatchAttributesProvider
     */
    private $swatchAttributesProvider;

    /**
     * Data key which should populated to Attribute entity from "additional_data" field
     *
     * @var array
     */
    protected $eavAttributeAdditionalDataKeys = [
        Swatch::SWATCH_INPUT_TYPE_KEY,
        'update_product_preview_image',
        'use_product_image_for_swatch'
    ];

    /**
     * Serializer to/from JSON.
     *
     * @var Json
     */
    private $serializer;

    /**
     * @var SwatchAttributeType
     */
    private $swatchTypeChecker;

    /**
     * @var UrlBuilder
     */
    private $imageUrlBuilder;

    /**
     * @param CollectionFactory $productCollectionFactory
     * @param ProductRepositoryInterface $productRepository
     * @param StoreManagerInterface $storeManager
     * @param SwatchCollectionFactory $swatchCollectionFactory
     * @param UrlBuilder $urlBuilder
     * @param Json|null $serializer
     * @param SwatchAttributesProvider $swatchAttributesProvider
     * @param SwatchAttributeType|null $swatchTypeChecker
     */
    public function __construct(
        CollectionFactory $productCollectionFactory,
        ProductRepositoryInterface $productRepository,
        StoreManagerInterface $storeManager,
        SwatchCollectionFactory $swatchCollectionFactory,
        UrlBuilder $urlBuilder,
        Json $serializer = null,
        SwatchAttributesProvider $swatchAttributesProvider = null,
        SwatchAttributeType $swatchTypeChecker = null
    ) {
        $this->productCollectionFactory = $productCollectionFactory;
        $this->productRepository = $productRepository;
        $this->storeManager = $storeManager;
        $this->swatchCollectionFactory = $swatchCollectionFactory;
        $this->serializer = $serializer ?: ObjectManager::getInstance()->create(Json::class);
        $this->swatchAttributesProvider = $swatchAttributesProvider
            ?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class);
        $this->swatchTypeChecker = $swatchTypeChecker
            ?: ObjectManager::getInstance()->create(SwatchAttributeType::class);
        $this->imageUrlBuilder = $urlBuilder;
    }

    /**
     * @param Attribute $attribute
     * @return $this
     */
    public function assembleAdditionalDataEavAttribute(Attribute $attribute)
    {
        $initialAdditionalData = [];
        $additionalData = (string)$attribute->getData('additional_data');
        if (!empty($additionalData)) {
            $additionalData = $this->serializer->unserialize($additionalData);
            if (is_array($additionalData)) {
                $initialAdditionalData = $additionalData;
            }
        }

        $dataToAdd = [];
        foreach ($this->eavAttributeAdditionalDataKeys as $key) {
            $dataValue = $attribute->getData($key);
            if (null !== $dataValue) {
                $dataToAdd[$key] = $dataValue;
            }
        }
        $additionalData = array_merge($initialAdditionalData, $dataToAdd);
        $attribute->setData('additional_data', $this->serializer->serialize($additionalData));
        return $this;
    }

    /**
     * Check is media attribute available
     *
     * @param ModelProduct $product
     * @param string $attributeCode
     * @return bool
     */
    private function isMediaAvailable(ModelProduct $product, string $attributeCode): bool
    {
        $isAvailable = false;

        $mediaGallery = $product->getMediaGalleryEntries();
        foreach ($mediaGallery as $mediaEntry) {
            if (in_array($attributeCode, $mediaEntry->getTypes(), true)) {
                $isAvailable = !$mediaEntry->isDisabled();
                break;
            }
        }

        return $isAvailable;
    }

    /**
     * @param string $attributeCode swatch_image|image
     * @param ModelProduct $configurableProduct
     * @param array $requiredAttributes
     * @return bool|Product
     */
    private function loadFirstVariation($attributeCode, ModelProduct $configurableProduct, array $requiredAttributes)
    {
        if ($this->isProductHasSwatch($configurableProduct)) {
            $usedProducts = $configurableProduct->getTypeInstance()->getUsedProducts($configurableProduct);

            foreach ($usedProducts as $simpleProduct) {
                if (!array_diff_assoc($requiredAttributes, $simpleProduct->getData())
                    && $this->isMediaAvailable($simpleProduct, $attributeCode)
                ) {
                    return $simpleProduct;
                }
            }
        }

        return false;
    }

    /**
     * @param Product $configurableProduct
     * @param array $requiredAttributes
     * @return bool|Product
     */
    public function loadFirstVariationWithSwatchImage(Product $configurableProduct, array $requiredAttributes)
    {
        return $this->loadFirstVariation('swatch_image', $configurableProduct, $requiredAttributes);
    }

    /**
     * @param Product $configurableProduct
     * @param array $requiredAttributes
     * @return bool|Product
     */
    public function loadFirstVariationWithImage(Product $configurableProduct, array $requiredAttributes)
    {
        return $this->loadFirstVariation('image', $configurableProduct, $requiredAttributes);
    }

    /**
     * Load Variation Product using fallback
     *
     * @param Product $parentProduct
     * @param array $attributes
     * @return bool|Product
     */
    public function loadVariationByFallback(Product $parentProduct, array $attributes)
    {
        if (!$this->isProductHasSwatch($parentProduct)) {
            return false;
        }

        $productCollection = $this->productCollectionFactory->create();

        $productLinkedFiled = $this->getMetadataPool()
            ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
            ->getLinkField();
        $parentId = $parentProduct->getData($productLinkedFiled);

        $this->addFilterByParent($productCollection, $parentId);

        $configurableAttributes = $this->getAttributesFromConfigurable($parentProduct);
        $allAttributesArray = [];
        foreach ($configurableAttributes as $attribute) {
            if (!empty($attribute['default_value'])) {
                $allAttributesArray[$attribute['attribute_code']] = $attribute['default_value'];
            }
        }

        $resultAttributesToFilter = array_merge(
            $attributes,
            array_diff_key($allAttributesArray, $attributes)
        );

        $this->addFilterByAttributes($productCollection, $resultAttributesToFilter);

        $variationProduct = $productCollection->getFirstItem();
        if ($variationProduct && $variationProduct->getId()) {
            return $this->productRepository->getById($variationProduct->getId());
        }

        return false;
    }

    /**
     * @param ProductCollection $productCollection
     * @param array $attributes
     * @return void
     */
    private function addFilterByAttributes(ProductCollection $productCollection, array $attributes)
    {
        foreach ($attributes as $code => $option) {
            $productCollection->addAttributeToFilter($code, ['eq' => $option]);
        }
    }

    /**
     * @param ProductCollection $productCollection
     * @param integer $parentId
     * @return void
     */
    private function addFilterByParent(ProductCollection $productCollection, $parentId)
    {
        $tableProductRelation = $productCollection->getTable('catalog_product_relation');
        $productCollection
            ->getSelect()
            ->join(
                ['pr' => $tableProductRelation],
                'e.entity_id = pr.child_id'
            )
            ->where('pr.parent_id = ?', $parentId);
    }

    /**
     * Method getting full media gallery for current Product
     * Array structure: [
     *  ['image'] => 'http://url/pub/media/catalog/product/2/0/blabla.jpg',
     *  ['mediaGallery'] => [
     *      galleryImageId1 => simpleProductImage1.jpg,
     *      galleryImageId2 => simpleProductImage2.jpg,
     *      ...,
     *      ]
     * ]
     * @param ModelProduct $product
     * @return array
     */
    public function getProductMediaGallery(ModelProduct $product)
    {
        $baseImage = null;
        $gallery = [];

        $mediaGallery = $product->getMediaGalleryEntries();
        foreach ($mediaGallery as $mediaEntry) {
            if ($mediaEntry->isDisabled()) {
                continue;
            }

            if (in_array('image', $mediaEntry->getTypes(), true) || !$baseImage) {
                $baseImage = $mediaEntry->getFile();
            }

            $gallery[$mediaEntry->getId()] = $this->getAllSizeImages($mediaEntry->getFile());
        }

        if (!$baseImage) {
            return [];
        }

        $resultGallery = $this->getAllSizeImages($baseImage);
        $resultGallery['gallery'] = $gallery;

        return $resultGallery;
    }

    /**
     * @param string $imageFile
     * @return array
     */
    private function getAllSizeImages($imageFile)
    {
        return [
            'large' => $this->imageUrlBuilder->getUrl($imageFile, 'product_swatch_image_large'),
            'medium' => $this->imageUrlBuilder->getUrl($imageFile, 'product_swatch_image_medium'),
            'small' => $this->imageUrlBuilder->getUrl($imageFile, 'product_swatch_image_small')
        ];
    }

    /**
     * Retrieve collection of Swatch attributes
     *
     * @param Product $product
     * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute[]
     */
    private function getSwatchAttributes(Product $product)
    {
        $swatchAttributes = $this->swatchAttributesProvider->provide($product);
        return $swatchAttributes;
    }

    /**
     * Retrieve collection of Eav Attributes from Configurable product
     *
     * @param Product $product
     * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute[]
     */
    public function getAttributesFromConfigurable(Product $product)
    {
        $result = [];
        $typeInstance = $product->getTypeInstance();
        if ($typeInstance instanceof Configurable) {
            $configurableAttributes = $typeInstance->getConfigurableAttributes($product);
            /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute $configurableAttribute */
            foreach ($configurableAttributes as $configurableAttribute) {
                /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
                $attribute = $configurableAttribute->getProductAttribute();
                $result[] = $attribute;
            }
        }
        return $result;
    }

    /**
     * Retrieve all visible Swatch attributes for current product.
     *
     * @param Product $product
     * @return array
     */
    public function getSwatchAttributesAsArray(Product $product)
    {
        $result = [];
        $swatchAttributes = $this->getSwatchAttributes($product);
        foreach ($swatchAttributes as $swatchAttribute) {
            $swatchAttribute->setStoreId($this->storeManager->getStore()->getId());
            $attributeData = $swatchAttribute->getData();
            foreach ($swatchAttribute->getSource()->getAllOptions(false) as $option) {
                $attributeData['options'][$option['value']] = $option['label'];
            }
            $result[$attributeData['attribute_id']] = $attributeData;
        }

        return $result;
    }

    /**
     * @var array
     */
    private $swatchesCache = [];

    /**
     * Get swatch options by option id's according to fallback logic
     *
     * @param array $optionIds
     * @return array
     */
    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));
    }

    /**
     * Get cached swatches
     *
     * @param array $optionIds
     * @return array
     */
    private function getCachedSwatches(array $optionIds)
    {
        return array_intersect_key($this->swatchesCache, array_combine($optionIds, $optionIds));
    }

    /**
     * Cache swatch. If no swathes found for specific option id - set null for prevent double call
     *
     * @param array $optionIds
     * @param array $swatches
     * @return void
     */
    private function setCachedSwatches(array $optionIds, array $swatches)
    {
        foreach ($optionIds as $optionId) {
            $this->swatchesCache[$optionId] = isset($swatches[$optionId]) ? $swatches[$optionId] : null;
        }
    }

    /**
     * @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[self::DEFAULT_STORE_ID])) {
                $swatches[$optionId] = $optionsArray[self::DEFAULT_STORE_ID];
            }
        }

        return $swatches;
    }

    /**
     * Check if the Product has Swatch attributes
     *
     * @param Product $product
     * @return bool
     */
    public function isProductHasSwatch(Product $product)
    {
        return !empty($this->getSwatchAttributes($product));
    }

    /**
     * Check if an attribute is Swatch
     *
     * @param Attribute $attribute
     * @return bool
     */
    public function isSwatchAttribute(Attribute $attribute)
    {
        return $this->swatchTypeChecker->isSwatchAttribute($attribute);
    }

    /**
     * Is attribute Visual Swatch
     *
     * @param Attribute $attribute
     * @return bool
     */
    public function isVisualSwatch(Attribute $attribute)
    {
        return $this->swatchTypeChecker->isVisualSwatch($attribute);
    }

    /**
     * Is attribute Textual Swatch
     *
     * @param Attribute $attribute
     * @return bool
     */
    public function isTextSwatch(Attribute $attribute)
    {
        return $this->swatchTypeChecker->isTextSwatch($attribute);
    }

    /**
     * Get product metadata pool.
     *
     * @return \Magento\Framework\EntityManager\MetadataPool
     * @deprecared
     */
    protected function getMetadataPool()
    {
        if (!$this->metadataPool) {
            $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
                ->get(\Magento\Framework\EntityManager\MetadataPool::class);
        }
        return $this->metadataPool;
    }
}

 

2 REPLIES 2

Re: Error after upgrading to 2.3.0

I may be have a similar problem. Migrate 1.9.4 site to 2.3.0

php bin/magento indexer:status

[...]

| Catalog Search       | Reindex required | Schedule  idle (835 in backlog)

 [...]

[...]

php bin/magento indexer:reindex

[...]

Catalog Search indexer process unknown error:

Item (Magento\Eav\Model\Entity\Attribute\Option) with the same ID "35" already exists.

 

1.

Where to find "Magento\Eav\Model\Entity\Attribute\Option"

2. 

If database duplicate; - what table?

 

Possible solution?

Is it safe to delete tables after "catalog search_fulltext_cl" ??

catalog search_fulltext_scope1

catalog search_fulltext_scope2

[...]

catalog search_fulltext_scope10

 

Found this in another forum - is this something for me?

ALTER TABLE `xxxx`.`catalogsearch_fulltext_scope1` DROP PRIMARY KEY, ADD PRIMARY KEY (`entity_id`, `attribute_id`) USING BTREE;
ALTER TABLE `xxxx`.`catalogsearch_fulltext_scope1` DROP INDEX `FTI_FULLTEXT_DATA_INDEX`, ADD FULLTEXT `FTI_FULLTEXT_DATA_INDEX` (`data_index`);
ALTER TABLE `xxxx`.`catalog_eav_attribute` DROP PRIMARY KEY, ADD PRIMARY KEY (`attribute_id`) USING BTREE;
ALTER TABLE `xxxx`.`catalog_eav_attribute` DROP INDEX `CATALOG_EAV_ATTRIBUTE_USED_IN_PRODUCT_LISTING`, ADD INDEX `CATALOG_EAV_ATTRIBUTE_USED_IN_PRODUCT_LISTING` (`used_in_product_listing`) USING BTREE;
ALTER TABLE `xxxx`.`catalog_eav_attribute` DROP INDEX `CATALOG_EAV_ATTRIBUTE_USED_FOR_SORT_BY`, ADD INDEX `CATALOG_EAV_ATTRIBUTE_USED_FOR_SORT_BY` (`used_for_sort_by`) USING BTREE;

Re: Error after upgrading to 2.3.0

I too had this problem after installing Claue Theme 1.7.8 at Magento 2.3.x.

Claue Theme has released a Patch for Magento 2.3.x, if you follow readme for this release, it will solve the problem.

But make sure that you have applied patch for Magento 2.2+ before applying patch for Magento 2.3+