Magento2 - เพิ่มตัวเลือกคุณลักษณะของผลิตภัณฑ์โดยทางโปรแกรม


32

วิธีที่ถูกต้อง (เป็นทางการ) ในการเพิ่มตัวเลือกคุณลักษณะของผลิตภัณฑ์ใน M2 คืออะไร เช่นสำหรับmanufacturerคุณสมบัติของผลิตภัณฑ์ ตัวเลือกที่มีอยู่ชัดเจนจะถูกจับคู่โดยค่าชื่อ "ผู้ดูแลระบบ"

คำตอบ:


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

createOrGetId($attributeCode, $label)จากนั้นทั้งในระดับเดียวกันหรือรวมทั้งผ่านทางฉีดพึ่งพาคุณสามารถเพิ่มหรือได้รับรหัสตัวเลือกของคุณโดยการเรียก

ตัวอย่างเช่นถ้าคุณฉีดMy\Module\Helper\Dataเป็น$this->moduleHelperแล้วคุณสามารถโทร:

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

หาก 'ABC Corp' เป็นผู้ผลิตที่มีอยู่ก็จะดึง ID ถ้าไม่มันจะเพิ่ม

ปรับปรุง 2016-09-09:ต่อ Ruud N. โซลูชันดั้งเดิมใช้ CatalogSetup ซึ่งทำให้เกิดข้อผิดพลาดใน Magento 2.1 โซลูชันที่แก้ไขนี้จะข้ามโมเดลนั้นโดยสร้างตัวเลือกและติดป้ายกำกับอย่างชัดเจน ควรใช้กับ 2.0+


3
มันเป็นทางการอย่างที่คุณจะได้รับ การค้นหาและการเพิ่มตัวเลือกทั้งหมดจะทำผ่านแกนหลักของวีโอไอพี ชั้นเรียนของฉันเป็นเพียงเสื้อคลุมสำหรับวิธีหลักที่ทำให้ง่ายต่อการใช้งาน
Ryan Hoerr

1
สวัสดี Ryan คุณไม่ควรตั้งค่าตัวเลือกนี่คือการใช้ magento id ภายในและฉันพบวิธีที่ยากที่ถ้าคุณตั้งค่าเป็นค่าสตริงที่มีหมายเลขนำหน้าเช่น '123 abc corp' Magento\Eav\Model\ResourceModel\Entity\Attribute::_processAttributeOptionsปัญหาบางอย่างเกิดจากการดำเนินงานของ ดูด้วยตัวคุณเองถ้าคุณลบ$option->setValue($label);คำสั่งจากรหัสของคุณมันจะบันทึกตัวเลือกจากนั้นเมื่อคุณดึงออกมาวีโอไอพีจะคืนค่าจากการเพิ่มขึ้นอัตโนมัติในeav_attribute_optionตาราง
quickshiftin

2
ถ้าฉันเพิ่มสิ่งนี้ในฟังก์ชั่น foreach ในการวนซ้ำครั้งที่สองฉันจะได้รับข้อผิดพลาด "Magento \ Eav \ Model \ Entity \ คุณสมบัติ \ OptionManagement :: setOptionValue () ต้องเป็นสตริงประเภทวัตถุที่กำหนด"
JELLEJ

1
ใช่รหัสนี้ไม่ทำงาน
Sourav

2
@JELLEJ หากคุณได้รับปัญหา Uncaught TypeError: อาร์กิวเมนต์ 3 ผ่านไปยังวีโอไอพี \ Eav \ Model \ Entity \ Attribute \ OptionManagement :: setOptionValue () ต้องเป็นสตริงประเภทวัตถุที่กำหนดในฟังก์ชั่น 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_idattribute_code

ในกรณีนั้นเราต้องรับattribute_idและส่งไปยังฟังก์ชันการสร้างแอททริบิวต์

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

จากนั้นเราต้องสร้างอาร์เรย์ตัวเลือกในแบบที่วีโอไอพีคาดหวัง:

$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 สามารถใช้พารามิเตอร์อาร์เรย์ ['ตัวเลือก']
DWils

10

การใช้วีโอไอพี \ Eav \ Setup \ EavSetupFactory หรือแม้กระทั่ง \ วีโอไอพี \ ระดับแคตตาล็อก \ 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และ$optionเป็นคลาส ORM; คุณไม่ควรฉีดยาโดยตรง วิธีที่เหมาะสมคือการฉีดคลาสโรงงานจากนั้นสร้างอินสแตนซ์ตามต้องการ นอกจากนี้โปรดทราบว่าคุณไม่ได้ใช้อินเทอร์เฟซข้อมูล API อย่างสม่ำเสมอ
Ryan Hoerr

3
สวัสดี @ รัดด์ดูความเห็นของฉันในคำตอบของไรอัน คุณไม่ต้องการที่จะโทร$option->setValue()ตามที่มีไว้สำหรับเขตoption_idข้อมูลวีโอไอพีภายในบนeav_attribute_optionโต๊ะ
quickshiftin

ขอขอบคุณ. นั่นคือสิ่งที่ฉันรู้ด้วย จะแก้ไขคำตอบของฉันตาม
Ruud N.

0

สำหรับ Magento 2.3.3 ฉันพบว่าคุณสามารถใช้ Magento DevTeam ได้

  • เพิ่ม Patch
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 .. )

ไปที่คอนโซลเบราว์เซอร์ (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);
});

- ทดสอบบน Magento 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.