1

I'm trying to insert a value for a unique text value attribute programmatically to assign it to a product. All my others attributes have options so I can't use the same functions. If I try to insert them as an option attribute it gives an error that says "Attribute %id% doesn't work with options".

Is there a way to assign a value to this attribute and them assign it to a product?

Here is how I add a new value to an existing attribute. If value already exits, it returns the id.

/**
 * 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, $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 */
        $optionLabel = $this->optionLabelFactory->create();
        $optionLabel->setStoreId(0);
        $optionLabel->setLabel($label);

        $option = $this->optionFactory->create();
        $option->setLabel($optionLabel);
        $option->setStoreLabels([$optionLabel]);
        $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);
    }

    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;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.