Magento2 - lập trình thêm tùy chọn thuộc tính sản phẩm


32

Cách đúng (chính thức) để lập trình thêm tùy chọn thuộc tính sản phẩm trong M2 là gì? Ví dụ cho manufacturerthuộc tính sản phẩm. Rõ ràng tùy chọn hiện có sẽ được khớp với giá trị tiêu đề "Quản trị viên".

Câu trả lời:


55

Đây là cách tiếp cận tôi đã đưa ra để xử lý các tùy chọn thuộc tính. Lớp người trợ giúp:

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

Sau đó, trong cùng một lớp hoặc bao gồm nó thông qua tiêm phụ thuộc, bạn có thể thêm hoặc nhận ID tùy chọn của mình bằng cách gọi createOrGetId($attributeCode, $label).

Ví dụ: nếu bạn tiêm My\Module\Helper\Datanhư $this->moduleHelper, thì bạn có thể gọi:

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

Nếu 'ABC Corp' là nhà sản xuất hiện có, nó sẽ lấy ID. Nếu không, nó sẽ thêm nó.

CẬP NHẬT 2016-09-09: Per Ruud N., giải pháp ban đầu đã sử dụng Catalogsetup, dẫn đến lỗi bắt đầu trong Magento 2.1. Giải pháp sửa đổi này bỏ qua mô hình đó, tạo ra tùy chọn và nhãn rõ ràng. Nó nên hoạt động trên 2.0+.


3
Đó là chính thức như bạn sẽ nhận được. Tất cả các tra cứu và thêm tùy chọn đều đi qua lõi Magento. Lớp của tôi chỉ là một trình bao bọc cho các phương thức cốt lõi đó giúp chúng dễ sử dụng hơn.
Ryan Hoerr

1
Xin chào Ryan, bạn không nên đặt giá trị trên tùy chọn, đây là id magento nội bộ sử dụng và tôi đã phát hiện ra một cách khó khăn là nếu bạn đặt giá trị thành giá trị chuỗi với số dẫn đầu như '123 abc corp' thì nó gây ra một số vấn đề nghiêm trọng do việc thực hiện Magento\Eav\Model\ResourceModel\Entity\Attribute::_processAttributeOptions. Hãy tự mình xem, nếu bạn xóa $option->setValue($label);câu lệnh khỏi mã của mình, nó sẽ lưu tùy chọn, sau đó khi bạn tìm nạp nó, Magento sẽ trả về giá trị từ mức tăng tự động trên eav_attribute_optionbảng.
quickshiftin

2
nếu tôi thêm cái này vào hàm foreach, trong lần lặp thứ hai, tôi sẽ gặp lỗi "Magento \ Eav \ Model \ Entity \ Attribution \ OptionManloyment :: setOptionValue () phải thuộc chuỗi kiểu, đối tượng đã cho"
JELLEJ

1
Có mã này không hoạt động
Sourav

2
@JELLEJ Nếu bạn đang gặp sự cố Uncaught TypeError: Đối số 3 được chuyển cho Magento \ Eav \ Model \ Entity \ Attribution \ OptionManloyment :: setOptionValue () phải thuộc chuỗi kiểu, đối tượng được cung cấp trong hàm foreach sau đó thay đổi tùy chọn $ $ tùy chọn Nhãn hiệu); đến $ tùy chọn-> setLabel ($ nhãn); tại dòng 102
Nadeem0035

11

đã thử nghiệm trên Magento 2.1.3.

Tôi đã không tìm thấy bất kỳ cách khả thi nào để tạo thuộc tính với các tùy chọn cùng một lúc. Vì vậy, ban đầu chúng ta cần tạo một thuộc tính và sau đó thêm tùy chọn cho nó.

Tiêm theo lớp \ Magento \ Eav \ Setup \ EavSetupFactory

 $setup->startSetup();

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

Tạo thuộc tính mới:

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

Thêm tùy chọn tùy chỉnh.

Hàm addAttributekhông trả về bất cứ thứ gì hữu ích có thể được sử dụng trong tương lai. Vì vậy, sau khi tạo thuộc tính, chúng ta cần lấy chính đối tượng thuộc tính. !!! Quan trọng Chúng tôi cần nó vì chức năng chỉ mong đợi attribute_id, nhưng không muốn làm việc với attribute_code.

Trong trường hợp đó, chúng ta cần lấy attribute_idvà chuyển nó vào hàm tạo thuộc tính.

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

Sau đó, chúng ta cần tạo mảng tùy chọn theo cách magento mong đợi:

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

Ví dụ như:

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

Và chuyển nó vào chức năng:

$eavSetup->addAttributeOption($options);

Thông số thứ 3 của addAttribution có thể lấy tham số mảng ['tùy chọn']
DWils

10

Sử dụng lớp Magento \ Eav \ Setup \ EavSetupFactory hoặc thậm chí lớp \ Magento \ Catalog \ Setup \ CategorySetupFactory có thể dẫn đến sự cố sau: https://github.com/magento/magento2/issues/4896 .

Các lớp bạn nên sử dụng:

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

Sau đó, trong chức năng của bạn làm một cái gì đó như thế này:

 $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
Cảm ơn, bạn đã đúng. Tôi đã cập nhật câu trả lời của mình cho phù hợp. Lưu ý rằng $attributeOptionLabel$optionlà các lớp ORM; bạn không nên tiêm trực tiếp. Cách tiếp cận phù hợp là tiêm lớp nhà máy của họ, sau đó tạo một thể hiện khi cần thiết. Cũng lưu ý rằng bạn không sử dụng giao diện dữ liệu API một cách nhất quán.
Ryan Hoerr

3
Xin chào @Rudd, xem nhận xét của tôi về câu trả lời của Ryan. Bạn không muốn gọi $option->setValue()vì đó là cho một option_idtrường magento nội bộ trên eav_attribute_optionbàn.
quickshiftin

Cảm ơn bạn. Đó cũng là những gì tôi phát hiện ra. Sẽ chỉnh sửa câu trả lời của tôi cho phù hợp.
Ruud N.

0

Đối với Magento 2.3.3 Tôi thấy rằng bạn có thể sử dụng phương pháp Magento DevTeam.

  • Thêm bản vá
bin/magento setup:db-declaration:generate-patch Vendor_Module PatchName
  • Thêm CategoryInupFactory vào hàm tạo
public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        Factory $configFactory
        CategorySetupFactory $categorySetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->configFactory = $configFactory;
        $this->categorySetupFactory = $categorySetupFactory;
}
  • Thêm thuộc tính trong hàm áp dụng ()

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

uhmm tôi chỉ tìm ra rằng tôi muốn thêm câu trả lời này cho câu hỏi khác nhau. Tôi sẽ chỉ sống ở đây và thêm tài liệu tham khảo cho câu trả lời này ở đó. Tôi hy vọng rằng nó là ok. Đây cũng là câu trả lời dành cho câu hỏi này :)
embed0

-4

Đây KHÔNG phải là một câu trả lời. Chỉ là một cách giải quyết.

Nó giả định rằng bạn có quyền truy cập vào Magento Backend bằng trình duyệt và bạn đang ở trang chỉnh sửa thuộc tính (url trông giống như admin / catalog / sản phẩm_attribution / edit / property_id / XXX / key ..)

Chuyển đến Bảng điều khiển trình duyệt (CTRL + SHIFT + J trên chrome) và dán đoạn mã sau sau khi thay đổi mảng bắt chước .

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

- đã thử nghiệm trên Magento 2.2.2

Bài viết chi tiết - https://tutes.in/how-to-manage-magento-2-product-attribution-values-options-USE-console/


1
Đây là một giải pháp dài hạn khủng khiếp. Bạn không thể tin tưởng những bộ chọn đó sẽ giữ nguyên. Đây là một cách giải quyết tốt nhất, nếu nó thực sự hoạt động như mong đợi.
domdambrogia

@domdambrogia đồng ý. Đó là một cách giải quyết.
th3pirat3
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.