سؤال

I am trying to add multiple attribute options to an already existing attribute. During the loop, it will create the first option, and then throw an error.

Fatal error: Uncaught TypeError: Argument 3 passed to Magento\Eav\Model\Entity\Attribute\OptionManagement::setOptionValue() must be of the type string, object given, called in /var/www/src/vendor/magento/module-eav/Model/Entity/Attribute/OptionManagement.php on line 72 and defined in /var/www/src/vendor/magento/module-eav/Model/Entity/Attribute/OptionManagement.php:165

Below is my code that will call the function

    foreach($attributeData as $softtouchAttribute) {
            echo $attribute->id . " - " . $attribute->description . PHP_EOL;
            $optionId = $this->attributeHelper->createOrUpdate($magentoAttribute, $attribute->id, $attribute->description);
            echo "OptionId: " . $optionId . PHP_EOL;
        }

The helper class

<?php
namespace Singto\API\Helper\Attributes;

class Option extends \Magento\Framework\App\Helper\AbstractHelper
{
    /**
     * @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
     */
    protected $attributeRepository;

    /**
     * @var array
     */
    protected $attributeValues;

    /**
     * @var \Magento\Eav\Model\Entity\Attribute\Source\TableFactory
     */
    protected $tableFactory;

    /**
     * @var \Magento\Eav\Api\AttributeOptionManagementInterface
     */
    protected $attributeOptionManagement;

    /**
     * @var \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory
     */
    protected $optionLabelFactory;

    /**
     * @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory
     */
    protected $optionFactory;

    /**
     * Data constructor.
     *
     * @param \Magento\Framework\App\Helper\Context $context
     * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
     * @param \Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory
     * @param \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement
     * @param \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory
     * @param \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
        \Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory,
        \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement,
        \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory,
        \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory,
        \Psr\Log\LoggerInterface $logger
    ) {
        $this->attributeRepository = $attributeRepository;
        $this->tableFactory = $tableFactory;
        $this->attributeOptionManagement = $attributeOptionManagement;
        $this->optionLabelFactory = $optionLabelFactory;
        $this->optionFactory = $optionFactory;
        $this->logger = $logger;
    }

    /**
     * Get attribute by code.
     *
     * @param string $attributeCode
     * @return \Magento\Catalog\Api\Data\ProductAttributeInterface
     */
    public function getAttribute($attributeCode)
    {
        return $this->attributeRepository->get($attributeCode);
    }

    /**
     * Find or create a matching attribute option
     *
     * @param string $attributeCode Attribute the option should exist in
     * @param string $label Label to find or add
     * @return int
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function createOrGetId($attributeCode, $optionCode, $label)
    {
        if (strlen($label) < 1) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('Label for %1 must not be empty.', $attributeCode)
            );
        }

        // Does it already exist?
        $optionId = $this->getOptionId($attributeCode, $label);

        if (!$optionId) {
            // If no, add it.

            /** @var \Magento\Eav\Model\Entity\Attribute\OptionLabel $optionLabel */
            /** @var \Magento\Eav\Model\Entity\Attribute\OptionLabel $optionLabel2 */
            try {
                $optionLabel = $this->optionLabelFactory->create();
                $optionLabel->setStoreId(0);
                $optionLabel->setLabel($optionCode);

                $optionLabel2 = $this->optionLabelFactory->create();
                $optionLabel2->setStoreId(1);
                $optionLabel2->setLabel($label);

                $option = $this->optionFactory->create();
                $option->setLabel($optionLabel);
                $option->setStoreLabels([$optionLabel, $optionLabel2]);
                $option->setSortOrder(0);
                $option->setIsDefault(false);

                $this->attributeOptionManagement->add(
                    \Magento\Catalog\Model\Product::ENTITY,
                    $this->getAttribute($attributeCode)->getAttributeId(),
                    $option
                );


                // Get the inserted ID. Should be returned from the installer, but it isn't.
                $optionId = $this->getOptionId($attributeCode, $label, true);
            } catch (\Exception $e) {
                $this->logger->critical($e->getMessage());
            }

        }

        return $optionId;
    }

    /**
     * Find the ID of an option matching $label, if any.
     *
     * @param string $attributeCode Attribute code
     * @param string $label Label to find
     * @param bool $force If true, will fetch the options even if they're already cached.
     * @return int|false
     */
    public function getOptionId($attributeCode, $label, $force = false)
    {
        /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
        $attribute = $this->getAttribute($attributeCode);

        // Build option array if necessary
        if ($force === true || !isset($this->attributeValues[ $attribute->getAttributeId() ])) {
            $this->attributeValues[ $attribute->getAttributeId() ] = [];

            // We have to generate a new sourceModel instance each time through to prevent it from
            // referencing its _options cache. No other way to get it to pick up newly-added values.

            /** @var \Magento\Eav\Model\Entity\Attribute\Source\Table $sourceModel */
            $sourceModel = $this->tableFactory->create();
            $sourceModel->setAttribute($attribute);

            foreach ($sourceModel->getAllOptions() as $option) {
                $this->attributeValues[ $attribute->getAttributeId() ][ $option['label'] ] = $option['value'];
            }
        }

        // Return option ID if exists
        if (isset($this->attributeValues[ $attribute->getAttributeId() ][ $label ])) {
            return $this->attributeValues[ $attribute->getAttributeId() ][ $label ];
        }

        // Return false if does not exist
        return false;
    }
}

I used this post for reference: https://magento.stackexchange.com/a/205178/18931

هل كانت مفيدة؟

المحلول 2

The issue here seems to be in the line with

$option->setLabel($optionLabel);

Given the fact that it needs to be an actual label, we're providing an object.

vendor/magento/module-eav/Api/Data/AttributeOptionInterface.php says that

* @param string $label

نصائح أخرى

I also face this issue and i found the solution about this type of error.

In Magento 2.2.X and Magento 2.3.X big different in this file - vendor/magento/module-eav/Model/Entity/Attribute/OptionManagement.php

In Magento 2.2.X, $option->setLabel($optionLabel) function passing the optionLabel object.

In Magento 2.3.X, $option->setLabel() function passing the string value. So you can add just option text like - $option->setLabel($label)

Thank You

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى magento.stackexchange
scroll top