Magento2 - programlı olarak ürün özelliği seçeneklerini ekleyin


32

M2'deki ürün özellik seçeneğini programlı olarak eklemek için doğru (resmi) yol nedir? İçin örneğin manufacturerbir ürün özelliğinin. Açıkçası, mevcut seçenek "Yönetici" başlık değeriyle eşleşirdi.

Yanıtlar:


55

İşte özellik seçeneklerini işlemek için geldiğim yaklaşım. Yardımcı sınıf:

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

Ardından, aynı sınıfta veya bağımlılık enjeksiyonuna dahil ederek, seçenek kimliğinizi arayarak ekleyebilir veya alabilirsiniz createOrGetId($attributeCode, $label).

Örneğin, enjekte eğer My\Module\Helper\Dataolarak $this->moduleHelper, o zaman arayabilirsiniz:

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

'ABC Corp' mevcut bir üreticiyse, kimliği çeker. Değilse, onu ekleyecektir.

GÜNCELLEME 2016-09-09: Orjinal çözüm olan Ruud Per N., Magento 2.1'de başlayan bir hatayla sonuçlanan CatalogSetup'ı kullandı. Bu gözden geçirilmiş çözüm, seçeneği ve etiketi açıkça yaratarak bu modeli atlar. 2.0 + 'da çalışması gerekir.


3
Bu alacağın kadar resmi. Tüm aramalar ve seçenek ekleme, çekirdek Magento'dan geçer. Sınıfım, kullanımlarını kolaylaştıran bu temel yöntemler için yalnızca bir sarıcıdır.
Ryan Hoerr,

1
Merhaba Ryan, seçeneğin değerini belirlememelisin, bu magento'nun kullandığı dahili kimliği ve değeri zor bir şekilde buldum, eğer değeri '123 abc corp' gibi önde gelen bir sayıya sahip bir dize değerine ayarlarsanız uygulanması nedeniyle bazı ciddi sorunlar Magento\Eav\Model\ResourceModel\Entity\Attribute::_processAttributeOptions. Kendinize bakın, $option->setValue($label);ifadeyi kodunuzdan çıkarırsanız , seçeneği kaydeder, ardından getirdiğinizde Magento değeri eav_attribute_optiontablodaki bir otomatik artıştan döndürür .
vites,

2
Bunu bir foreach işlevine eklersem, ikinci yinelemede "Magento \ Eav \ Model \ Varlık \ Öznitelik \ Öznitelik \ SeçenekAlan \ SeçenekAmanlığı :: setOptionValue () türünde bir nesne olmalı, verilen nesne"
JELLEJ

1
Evet bu kod çalışmıyor
Sourav

2
@JELLEJ Eğer sorun yaşıyorsanız Uncaught TypeError: Argüman 3 Magento \ Eav \ Model \ Varlık \ Öznitelik \ Öznitelik \ SeçenekAlması \ OptionManagement :: setOptionValue () 'a iletilen tip dizgisi olmalı, foreach işlevinde verilen nesne sonra $ option-> setLabel ( $ optionLabel); $ seçenek-> setLabel ($ label); satırda 102
Nadeem0035

11

Magento 2.1.3 üzerinde test edilmiştir.

Aynı anda seçeneklere sahip bir öznitelik oluşturmanın uygulanabilir bir yolunu bulamadım. Bu yüzden başlangıçta bir öznitelik oluşturmamız ve sonra bunun için seçenekler eklememiz gerekir.

\ Magento \ Eav \ Setup \ EavSetupFactory sınıfını takip edin

 $setup->startSetup();

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

Yeni özellik oluştur:

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

Özel seçenekler ekleyin.

İşlev addAttribute, gelecekte kullanılabilecek yararlı bir şey döndürmez. Bu yüzden nitelik yarattıktan sonra nitelik nesnesini kendimiz almamız gerekiyor. !!! Önemli İhtiyacımız var çünkü işlev yalnızca bekliyor attribute_id, ancak çalışmak istemiyor attribute_code.

Bu durumda attribute_idonu yaratma fonksiyonunu nitelemek için alıp geçmemiz gerekir.

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

O zaman magento'nun beklediği şekilde options array yapmamız gerekiyor:

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

Örnek olarak:

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

Ve işlevine geçin:

$eavSetup->addAttributeOption($options);

AddAttribute'in 3. parametresi ['option'] array parametresini alabilir
DWils

10

Magento \ Eav \ Setup \ EavSetupFactory veya hatta \ Magento \ Catalogue \ Setup \ CategorySetupFactory sınıfını kullanmak şu soruna yol açabilir: https://github.com/magento/magento2/issues/4896 .

Kullanmanız gereken sınıflar:

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

Sonra işlevinde böyle bir şey yapın:

 $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
Teşekkürler haklısın Buna göre cevabımı güncelledim. $attributeOptionLabelVe $optionORM sınıfları olduğuna dikkat edin ; Onları doğrudan enjekte etmemelisin. Doğru yaklaşım, fabrika sınıflarına enjekte etmek ve ardından gerektiği gibi bir örnek oluşturmaktır. Ayrıca, API veri arayüzlerini tutarlı bir şekilde kullanmadığınızı unutmayın.
Ryan Hoerr

3
Merhaba @ Rudd, Ryan'ın cevabı üzerine yorumuma bakın. Masada $option->setValue()dahili bir magento option_idalanı için olduğu gibi aramak istemezsiniz eav_attribute_option.
QuickTift

Teşekkür ederim. Ben de öyle öğrendim. Cevabımı buna göre düzenleyecektir.
Ruud N.

0

Magento 2.3.3 için Magento DevTeam yaklaşımını kullanabileceğinizi öğrendim.

  • Yama ekle
bin/magento setup:db-declaration:generate-patch Vendor_Module PatchName
  • Oluşturucuya CategorySetupFactory ekle
public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        Factory $configFactory
        CategorySetupFactory $categorySetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->configFactory = $configFactory;
        $this->categorySetupFactory = $categorySetupFactory;
}
  • Application () işlevinde özellik ekle

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

Sadece bu cevabı farklı soruya eklemek istediğimi öğrendim. Sadece burada yaşayacağım ve oradaki cevaba referans ekleyeceğim. Umarım iyidir. Bu, partiaclly bu sorunun cevabı da :)
embed0

-4

Bu bir cevap değil. Sadece bir geçici çözüm.

Tarayıcıyı kullanarak Magento Backend'e erişiminiz olduğunu ve nitelik düzenleme sayfasında olduğunuzu varsayar (URL, admin / catalog / product_attribute / edit / attribute_id / XXX / key ..)

Tarayıcı konsoluna gidin ( kromda CTRL + ÜST KRKT + J) ve dizi mimim'ini değiştirdikten sonra aşağıdaki kodu yapıştırın .

$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'de test edildi

Ayrıntılı makale - https://tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/


1
Bu korkunç uzun vadeli bir çözüm. Bu seçicilerin aynı kalmasını güvenilir şekilde bekleyemezsiniz. Beklendiği gibi çalışıyorsa, bu en iyi çözümdür.
domdambrogia

@ domdambrogia katılıyorum. Bu bir geçici çözümdür.
th3pirat3
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.