Magento2-프로그래밍 방식으로 제품 속성 옵션 추가


32

M2에서 제품 속성 옵션을 프로그래밍 방식으로 추가하는 올바른 방법은 무엇입니까? 예를 들어 manufacturer제품 속성. 기존 옵션은 "Admin"제목 값과 일치합니다.

답변:


55

다음은 속성 옵션을 처리하기 위해 제시 한 접근법입니다. 헬퍼 클래스 :

<?php
namespace My\Module\Helper;

class Data 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
    ) {
        parent::__construct($context);

        $this->attributeRepository = $attributeRepository;
        $this->tableFactory = $tableFactory;
        $this->attributeOptionManagement = $attributeOptionManagement;
        $this->optionLabelFactory = $optionLabelFactory;
        $this->optionFactory = $optionFactory;
    }

    /**
     * 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, $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;
    }
}

그런 다음 동일한 클래스에서 또는 종속성 삽입을 통해 포함하는 경우을 호출하여 옵션 ID를 추가하거나 가져올 수 있습니다 createOrGetId($attributeCode, $label).

예를 들어, My\Module\Helper\Dataas 를 주입 $this->moduleHelper하면 다음을 호출 할 수 있습니다.

$manufacturerId = $this->moduleHelper->createOrGetId('manufacturer', 'ABC Corp');

'ABC Corp'이 기존 제조업체 인 경우 ID를 가져옵니다. 그렇지 않은 경우 추가됩니다.

2016-09-09 업데이트 : Ruud N.에 따르면 원래 솔루션은 CatalogSetup을 사용하여 Magento 2.1에서 버그가 시작되었습니다. 이 수정 된 솔루션은 해당 모델을 무시하고 옵션과 레이블을 명시 적으로 만듭니다. 2.0 이상에서 작동합니다.


3
당신이 얻을만큼 공식입니다. 모든 조회 및 옵션 추가는 핵심 Magento를 거칩니다. 내 수업은 사용하기 쉬운 핵심 메소드의 래퍼 일뿐입니다.
Ryan Hoerr

1
안녕 라이언, 당신은 옵션에 값을 설정해서는 안됩니다, 이것은 magento가 사용하는 내부 id이며 값을 '123 abc corp'와 같은 선행 숫자가있는 문자열 값으로 설정하면 어려운 원인을 발견했습니다. 의 구현으로 인한 몇 가지 심각한 문제 Magento\Eav\Model\ResourceModel\Entity\Attribute::_processAttributeOptions. $option->setValue($label);코드 에서 명령문 을 제거하면 옵션이 저장되고, 가져올 때 Magento는 eav_attribute_option테이블 의 자동 증가 값을 반환 합니다.
quickshiftin

2
foreach 함수에 이것을 추가하면, 두 번째 반복에서 "Magento \ Eav \ Model \ Entity \ Attribute \ OptionManagement :: setOptionValue ()는 주어진 문자열 유형의 객체 여야합니다"
JELLEJ

1
예,이 코드는 작동하지 않습니다
Sourav

2
@JELLEJ 문제가 발생하면 Uncaught TypeError : Magento \ Eav \ Model \ Entity \ Attribute \ OptionManagement :: setOptionValue ()로 전달 된 인수 3은 형식 문자열이어야합니다. foreach 함수에 제공된 객체는 $ option-> setLabel ( $ optionLabel); $ option-> setLabel ($ label); 102 행
Nadeem0035

11

Magento 2.1.3에서 테스트되었습니다.

옵션으로 속성을 한 번에 생성하는 방법을 찾을 수 없었습니다. 따라서 처음에는 속성을 만든 다음 옵션을 추가해야합니다.

다음 클래스 \ Magento \ Eav \ Setup \ EavSetupFactory를 주입하십시오.

 $setup->startSetup();

 /** @var \Magento\Eav\Setup\EavSetup $eavSetup */
 $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

새 속성을 작성하십시오.

$eavSetup->addAttribute(
    'catalog_product',
    $attributeCode,
    [
        'type' => 'varchar',
        'input' => 'select',
        'required' => false,
        ...
    ],
);

사용자 정의 옵션을 추가하십시오.

함수 addAttribute는 나중에 사용할 수있는 유용한 것을 반환하지 않습니다. 따라서 속성을 만든 후에는 속성 개체를 직접 검색해야합니다. !!! 중요 함 함수는 단지 기대하기 때문에 필요 attribute_id하지만 작업하고 싶지는 않습니다 attribute_code.

이 경우 attribute_id속성 생성 함수 로 가져와 전달해야합니다.

$attributeId = $eavSetup->getAttributeId('catalog_product', 'attribute_code');

그런 다음 magento가 기대하는 방식으로 옵션 배열을 생성해야합니다.

$options = [
        'values' => [
        'sort_order1' => 'title1',
        'sort_order2' => 'title2',
        'sort_order3' => 'title3',
    ],
    'attribute_id' => 'some_id',
];

예를 들어 :

$options = [
        'values' => [
        '1' => 'Red',
        '2' => 'Yellow',
        '3' => 'Green',
    ],
    'attribute_id' => '32',
];

그리고 함수에 전달하십시오.

$eavSetup->addAttributeOption($options);

addAttribute의 3 번째 매개 변수는 배열 매개 변수 [ 'option']을 사용할 수 있습니다.
DWils

10

Magento \ Eav \ Setup \ EavSetupFactory 또는 \ Magento \ Catalog \ Setup \ CategorySetupFactory 클래스를 사용하면 다음과 같은 문제가 발생할 수 있습니다. https://github.com/magento/magento2/issues/4896 .

사용해야 할 수업 :

protected $_logger;

protected $_attributeRepository;

protected $_attributeOptionManagement;

protected $_option;

protected $_attributeOptionLabel;

 public function __construct(
    \Psr\Log\LoggerInterface $logger,
    \Magento\Eav\Model\AttributeRepository $attributeRepository,
    \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement,
    \Magento\Eav\Api\Data\AttributeOptionLabelInterface $attributeOptionLabel,
    \Magento\Eav\Model\Entity\Attribute\Option $option
  ){
    $this->_logger = $logger;
    $this->_attributeRepository = $attributeRepository;
    $this->_attributeOptionManagement = $attributeOptionManagement;
    $this->_option = $option;
    $this->_attributeOptionLabel = $attributeOptionLabel;
 }

그런 다음 함수에서 다음과 같이하십시오.

 $attribute_id = $this->_attributeRepository->get('catalog_product', 'your_attribute')->getAttributeId();
$options = $this->_attributeOptionManagement->getItems('catalog_product', $attribute_id);
/* if attribute option already exists, remove it */
foreach($options as $option) {
  if ($option->getLabel() == $oldname) {
    $this->_attributeOptionManagement->delete('catalog_product', $attribute_id, $option->getValue());
  }
}

/* new attribute option */
  $this->_option->setValue($name);
  $this->_attributeOptionLabel->setStoreId(0);
  $this->_attributeOptionLabel->setLabel($name);
  $this->_option->setLabel($this->_attributeOptionLabel);
  $this->_option->setStoreLabels([$this->_attributeOptionLabel]);
  $this->_option->setSortOrder(0);
  $this->_option->setIsDefault(false);
  $this->_attributeOptionManagement->add('catalog_product', $attribute_id, $this->_option);

1
고마워요 이에 따라 답변을 업데이트했습니다. 참고 것을 $attributeOptionLabel$optionORM 클래스는; 직접 주사해서는 안됩니다. 올바른 접근 방식은 팩토리 클래스를 주입 한 다음 필요에 따라 인스턴스를 작성하는 것입니다. 또한 API 데이터 인터페이스를 일관되게 사용하지 않습니다.
Ryan Hoerr

3
안녕하세요 @Rudd, Ryan의 답변에 대한 내 의견을 참조하십시오. 테이블 $option->setValue()의 내부 마 젠토 option_id필드에 대한 것이므로 호출하고 싶지 않습니다 eav_attribute_option.
quickshiftin

고맙습니다. 그게 나도 알아 낸 것입니다. 그에 따라 답변을 편집하겠습니다.
Ruud N.

0

Magento 2.3.3의 경우 Magento DevTeam 접근 방식을 취할 수 있음을 발견했습니다.

  • 패치 추가
bin/magento setup:db-declaration:generate-patch Vendor_Module PatchName
  • 생성자에 CategorySetupFactory 추가
public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        Factory $configFactory
        CategorySetupFactory $categorySetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->configFactory = $configFactory;
        $this->categorySetupFactory = $categorySetupFactory;
}
  • apply () 함수에 속성 ​​추가

    public function apply()
    {
        $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]);
    
        $categorySetup->addAttribute(
            \Magento\Catalog\Model\Product::ENTITY,
            'custom_layout',
            [
                'type' => 'varchar',
                'label' => 'New Layout',
                'input' => 'select',
                'source' => \Magento\Catalog\Model\Product\Attribute\Source\Layout::class,
                'required' => false,
                'sort_order' => 50,
                'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
                'group' => 'Schedule Design Update',
                'is_used_in_grid' => true,
                'is_visible_in_grid' => false,
                'is_filterable_in_grid' => false
            ]
        );
    }

어, 나는 다른 질문 에이 답변을 추가하고 싶었습니다. 나는 그냥 여기에 살고 거기 에이 답변에 대한 참조를 추가 할 것입니다. 나는 그것이 좋기를 바랍니다. 이것은 또한이 질문에 대한 부분적으로 답변입니다 :)
embed0

-4

이것은 대답이 아닙니다. 해결 방법입니다.

브라우저를 사용하여 Magento Backend에 액세스 할 수 있고 속성 편집 페이지에 있다고 가정합니다 (url은 admin / catalog / product_attribute / edit / attribute_id / XXX / key와 유사 함).

브라우저 콘솔 (chrome에서 CTRL + SHIFT + J)로 이동 하여 배열 mimim을 변경 한 후 다음 코드를 붙여 넣 습니다 .

$jq=new jQuery.noConflict();
var mimim=["xxx","yyy","VALUES TO BE ADDED"];
$jq.each(mimim,function(a,b){
$jq("#add_new_option_button").click();
$jq("#manage-options-panel tbody tr:last-child td:nth-child(3) input").val(b);
});

-마 젠토 2.2.2에서 테스트

자세한 기사-https: //tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/


1
이것은 끔찍한 장기 솔루션입니다. 이러한 선택기가 동일하게 유지 될 것으로 기대할 수는 없습니다. 실제로 예상대로 작동하는 경우 최선의 해결 방법입니다.
domdambrogia

@domdambrogia도 동의합니다. 해결 방법입니다.
th3pirat3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.