Bagaimana Magento2 menambahkan opsi atribut secara terprogram (tidak dalam pengaturan)

15

Saya mencoba menambahkan opsi untuk atribut ukuran dan warna dalam modul importir saya, tetapi saya tidak tahu caranya ...:

private function addOption($attributeCode, $value)
{
    $ob = $this->_objectManager;      
    /* @var $m \Magento\Eav\Model\Entity\Attribute\OptionManagement */
    $m = $this->optionManagement;
    /* @var $option \Magento\Eav\Model\Entity\Attribute\Option */
    $option = $this->attributeOption;

    $option->setLabel($value);      
    $option->setValue($value);

    $m->add(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE,
            $attributeCode,
            $option);

Ini melaporkan kesalahan (Saya memodifikasi pengecualian melaporkan OptionMaganger.phpke pesan Pengecualian-> )

Tidak dapat menyimpan ukuran atribut Pemberitahuan: Indeks tidak terdefinisi: hapus di /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php on line 177

  • Manajemen dan Opsi Option berasal _contstructor
  • Dengan OptionManagement, saya dapat mengambil item yang ada, jadi seharusnya ok ..

setLabel()dan setValue()default, tetapi saya mencoba setData , memuat contoh opsi dan lewat OptionManagement->getItemsuntuk menambahkan (...) "lagi", tetapi kesalahan masih ada ...

Ada ide, bagaimana saya bisa menambahkan Opsi EAV (swatch?) Selama proses impor? (tidak dalam pengaturan modul)


Perbarui:

Cara lain saya dapat menambahkan opsi:

$attributeCode = 137; /* on size, 90 on color ... */

$languageValues[0]='Admin Label'; 

$languageValues[1]='Default Store Label - XXXXL';
$ob = $this->_objectManager;

private function addOption($attributeCode,$languageValues){
$ob = $this->_objectManager;
/* @var $attr \Magento\Eav\Model\Entity\Attribute */
$attr = $ob->create('\Magento\Eav\Model\Entity\Attribute'); 
$attr->load($attributeCode); 
$option = []; 
$option['value'][$languageValues[0]] = $languageValues; 
$attr->addData(array('option' => $option));
$attr->save();
}

Dengan cara ini Magento2 dapat menyimpan opsi untuk atribut, tapi saya tidak tahu apa itu cara "resmi" :)

Interpigeon
sumber
Opsi menambahkan nilai apa pun sebagai string yang tidak didukung untuk integer
Ajay Patel

Jawaban:

2
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Store\Model\StoreManagerInterface;

menyatakan:

protected $_eavSetupFactory;

konstruktor:

public function __construct(
    \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory,
    \Magento\Store\Model\StoreManagerInterface $storeManager,
    \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attributeFactory,
    \Magento\Framework\ObjectManagerInterface $objectmanager,
    ModuleDataSetupInterface $setup,
    \Magento\Catalog\Model\ProductFactory $productloader
) {
    $this->_eavSetupFactory = $eavSetupFactory;
    $this->_storeManager = $storeManager;
    $this->_attributeFactory = $attributeFactory;
    $this->_objectManager = $objectmanager;
    $this->setup = $setup;
    $this->_productloader = $productloader;
}

jalankan metode:

public function execute(EventObserver $observer)
{
    /** @var $brand \Ktpl\Brand\Model\Brand */
    $brand = $observer->getEvent()->getBrand();
    $option_id = "";

    $data = [];
    $attribute_arr = [$brand['brand_id'] => $brand['brand_title']];
    $optionTable = $this->setup->getTable('eav_attribute_option');
    $attributeInfo=$this->_attributeFactory->getCollection()
           ->addFieldToFilter('attribute_code',['eq'=>"shop_by_brand"])
           ->getFirstItem();

    $attribute_id = $attributeInfo->getAttributeId();

    $eavAttribute = $this->_objectManager->create('Magento\Eav\Model\Config');

    $option=array();
    $option['attribute_id'] = $attributeInfo->getAttributeId();
    $option['value'] = array(0=>array()); // 0 means "new option_id", other values like "14" means "update option_id=14" - this array index is casted to integer

    $storeManager = $this->_objectManager->get('Magento\Store\Model\StoreManagerInterface');
    $stores = $storeManager->getStores();
    $storeArray[0] = "All Store Views";       

    foreach ($stores  as $store) {
        $storeArray[$store->getId()] = $store->getName();
    }


    if (empty($brand['optionId'])) {
        foreach($attribute_arr as $key => $value){
            $option['value'][0][0]=$value;
                foreach($storeArray as $storeKey => $store){
                    $option['value'][0][$storeKey] = $value;
                }                
        }
    }
    else
    {
        foreach($attribute_arr as $key => $value){
                foreach($storeArray as $storeKey => $store){
                    $option['value'][$brand['optionId']][$storeKey] = $value;
                }                
        }
    }

    $eavSetup = $this->_eavSetupFactory->create();
    $eavSetup->addAttributeOption($option)

}
Ronak Chauhan
sumber
Anda memiliki kesalahan serius dalam kode Anda: $ option ['value'] [$ value] [0] - seharusnya bukan $ value tetapi "option_id" - integer, untuk opsi baru yang disetel 0. Yang ini dilemparkan ke integer, jadi jika Anda memiliki string tanpa angka, mis. "hitam" itu akan 0 dengan benar. Tetapi jika $ value Anda adalah sesuatu seperti "10 Black" itu akan dilemparkan ke 10 dan memperbarui entitas database dengan option_id = 10 bukannya membuat yang baru. Ini dapat menyebabkan kekacauan serius dalam database toko Anda.
A.Maksymiuk
terima kasih untuk memberi tahu saudara. Jika Anda menemukan kesalahan apa pun selain Anda dapat memperbarui jawaban saya @ A.Maksymiuk
Ronak Chauhan
Melakukannya. Harap terima, maka saya akan mengembalikan downvote saya.
A.Maksymiuk
Disetujui, tetapi memberi suara rendah jawaban apa pun bukan cara yang tepat, bro. Jika Anda berpikir jawaban itu tidak terkait atau tidak sesuai yang diminta, maka Anda bisa tidak memilih suara siapa pun. @ A.Maksymiuk
Ronak Chauhan
Saya melakukannya untuk memperingatkan siapa pun untuk menggunakan kode ini, karena itu akan menyebabkan kerusakan serius pada integritas data. Misalnya alih-alih menambahkan opsi baru bernama "42" (ukuran) skrip Anda diperbarui option_id = 42 (yang merupakan opsi atribut yang sama sekali berbeda). Untungnya itu terjadi pada saya di server uji dan database baru.
A.Maksymiuk
2

Cara lain saya dapat menambahkan opsi:

$attributeCode = 137; /* on size, 90 on color ... */

$languageValues[0]='Admin Label'; 

$languageValues[1]='Default Store Label - XXXXL';
$ob = $this->_objectManager;



private function addOption($attributeCode,$languageValues){
$ob = $this->_objectManager;
/* @var $attr \Magento\Eav\Model\Entity\Attribute */
$attr = $ob->create('\Magento\Eav\Model\Entity\Attribute'); 
$attr->load($attributeCode); 
$option = []; 
$option['value'][$languageValues[0]] = $languageValues; 
$attr->addData(array('option' => $option));
$attr->save();
}

Dengan cara ini Magento2 dapat menyimpan opsi untuk atribut, tapi saya tidak tahu apa itu cara "resmi".

Interpigeon
sumber
Lihat jalan saya. Saya yakin ini 'resmi'
CarComp
solusi Anda bekerja tetapi hanya ketika opsi opsi tidak bekerja untuk bilangan bulat
Ajay Patel
mengapa itu tidak bekerja untuk nilai integer?
Vincent Teyssier
0

Tampaknya menjadi masalah validasi. Kunci hapus dalam data berasal dari formulir di backend, jadi cobalah menambahkan kunci hapus kosong dengan cara itu:

$option->setData('delete','');

Itu bisa bekerja.

MauroNigrele
sumber
Sayangnya tidak. OptionManager add (..) mem-reparsing parameter $ option dan membiarkan kunci 'delete' kosong, saya tidak tahu kenapa ... Tapi saya menemukan cara lain ....
Interpigeon
Hebat, silakan tambahkan solusi Anda sebagai jawaban untuk menyelesaikan pertanyaan.
MauroNigrele
Saya tidak bisa menjawab pertanyaan saya sendiri, tetapi saya memperbarui pertanyaan itu. Saya pikir solusi saya adalah solusi ...
Interpigeon
Hei, Anda dapat menjawab pertanyaan Anda cukup umum.
MauroNigrele
0

Saya akhirnya menulis ulang seluruh jawaban ini menggunakan metode ObjectFactory yang disarankan oleh Ryan H.

Akhirnya menjadi Kelas Penolong yang memanfaatkan beberapa atribut yang saya buat pada objek pelanggan, tetapi idenya ada pada bagaimana memanfaatkan EAV + ObjectFactories untuk memanipulasi opsi atribut

<?php


namespace Stti\Healthday\Helper {
    use Magento\Eav\Model\Entity\AttributeFactory;
    use Magento\Eav\Model\Entity\Attribute\OptionFactory;
    use Magento\Eav\Model\Entity\Attribute\OptionManagementFactory;
    use Magento\Framework\App\Helper\AbstractHelper;
    use Magento\Framework\App\Helper\Context;
    use Magento\Eav\Model\Entity\Attribute;
    use Stti\Healthday\Model\RelationFactory;


    /**
     * Eav data helper
     */
    class Data extends AbstractHelper {

        protected $optionFactory;

        protected $attributeFactory;

        protected $relationFactory;

        protected $optionManagementFactory;

        public function __construct(Context $context, AttributeFactory $attributeFactory, OptionFactory $optionFactory,
            RelationFactory $relationFactory,
            OptionManagementFactory $optionManagementFactory) {
            $this->optionFactory = $optionFactory;
            $this->attributeFactory = $attributeFactory;
            $this->optionFactory = $optionFactory;
            $this->relationFactory = $relationFactory;
            $this->optionManagementFactory = $optionManagementFactory;
            parent::__construct($context);
        }

        public function addRelationsHelper($answerJson, $attributeCode) {
            // IMPORTANT: READ THIS OR THE CODE BELOW WONT MAKE SENSE!!!!
            // Since magento's attribute option model was never meant to
            // hold guids, we'll be saving the guid as the label. An option_id will
            // get created, which can then be saved to the relationship table.  Then
            // the label in the attribute_option table can be changed to the actual 'word'
            // by looking up all of the options, matching on the guid, and doing a replace.
            // At that point, there will be a 1:1 relation between guid, option_id, and the 'word'



            // Get the attribute requested
            $attribute = $this->attributeFactory->create();
            $attribute  = $attribute->loadByCode("customer", $attributeCode);

            $answers = json_decode($answerJson, true);

            // Prepare vars
            //$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
            $prekeys = array();
            $prevalues = array();

            foreach ($answers as $answer) {
                $prekeys[] = $answer['Key'];
                $prevalues[] = $answer['Value'];
            }

            // load up all relations
            // generate an array of matching indexes so we can remove
            // them from the array to process
            $collection = $this->relationFactory->create()->getCollection();

            $removalIds = array();
            foreach ($collection as $relation) {
                // if the item is already in the magento relations,
                // don't attempt to add it to the attribute options
                for($cnt = 0; $cnt < sizeof($answers); $cnt++) {
                    if ($relation['stti_guid'] == $prekeys[$cnt]) {
                        $removalIds[] = $cnt;
                    }
                }
            }

            // Remove the values from the arrays we are going to process
            foreach($removalIds as $removalId) {
                unset($prekeys[$removalId]);
                unset($prevalues[$removalId]);
            }

            // "reindex" the arrays
            $keys = array_values($prekeys);
            $values = array_values($prevalues);

            // prepare the array that will be sent into the attribute model to
            // update its option values
            $updates = array();
            $updates['attribute_id'] = $attribute->getId();

            // This section utilizes the DI generated OptionFactory and OptionManagementFactory
            // to add the options to the customer attribute specified in the parameters.
            for($cnt = 0; $cnt < sizeof($keys); $cnt++) {
                $option = $this->optionFactory->create();
                $option->setLabel($keys[$cnt]);
                $this->optionManagementFactory->create()->add("customer", $attributeCode, $option);
            }

            // After save, pull all attribute options, compare to the 'keys' array
            // and create healthday/relation models if needed
            $relationIds = $attribute->getOptions();
            $updatedAttributeCount = 0;
            $options = array();
            $options['value'] = array();

            for($cnt = 0; $cnt < sizeof($keys); $cnt++) {

                $option_id = 0;
                foreach($relationIds as $relationId) {
                    if ($relationId->getLabel() == $keys[$cnt]) {
                        $option_id = $relationId['value'];
                        break;
                    }
                }
                if ($option_id > 0) {
                    // Create the healthday relation utilizing our custom models DI generated ObjectFactories
                    $relation = $this->relationFactory->create();
                    $relation->setAttributeId($attribute->getId());
                    $relation->setOptionId($option_id);
                    $relation->setSttiGuid($keys[$cnt]);
                    $relation->save();

                    // Rename the attribute option value to the 'word'
                    $options['value'][$option_id][] = $values[$cnt];
                    $updatedAttributeCount++;
                }
            }

            if ($updatedAttributeCount > 0) {
                $attribute->setData('option', $options);
                $attribute->save();
            }

            // Save the relationship to the guid
            return $updatedAttributeCount;
        }
    }
}
CarComp
sumber
1
Anda harus menyuntikkan ObjectFactory dan membuat instance Object dari itu, bukan menyuntikkan Object itu sendiri. Objek ORM tidak dapat disuntikkan secara langsung.
Ryan Hoerr
ObjectFactory yang mana? Ada seperti 50. Saya sedang melihat \ Magento \ Framework \ Api \ ObjectFactory tetapi itu hanya terlihat seperti pembungkus untuk ObjectManager. Saya tidak yakin mengapa saya tidak hanya mengimplementasikan objectmanager itu sendiri. Ada begitu banyak pembungkus untuk pembungkus hal-hal dalam versi baru ini.
CarComp
1
Saya berbicara secara abstrak. Suntikkan Factory untuk objek yang Anda berikan, bukan 'ObjectFactory' secara harfiah. Anda harus menyuntikkan pabrik untuk setiap jenis spesifik yang Anda gunakan, dan membuatnya sesuai kebutuhan. Ya, pada awalnya tampak berantakan ... tetapi ada alasan yang sangat bagus untuk itu. Selain itu, standar kode EKG semuanya kecuali melarang penggunaan langsung ObjectManager. Lihat artikel Alan Storm yang menjelaskan keseluruhan topik: alanstorm.com/magento_2_object_manager_instance_objects
Ryan Hoerr
Apa yang harus saya lakukan ketika benda yang ingin saya gunakan tidak memiliki pabrik? Sebagai contoh, saya tidak dapat menemukan cara untuk 'pabrik' hal-hal manajemen opsi. Magento \ Eav \ Model \ AttributeFactory juga menggunakan aneh -> createAttribute (vars) bukan hanya -> create (). Saya hanya mengatakan, ketika Anda tidak bekerja dengan suatu produk, atau suatu kategori yang dibangun di atas barang, segalanya menjadi sedikit aneh.
CarComp
1
Tidak semua benda membutuhkan pabrik. Untuk yang melakukannya, pabrik mungkin tidak ada di luar kotak - pabrik yang tidak ada akan dibuat saat runtime (dengan pembuatan DI), atau selama kompilasi. Baca artikel yang saya tautkan. Bagaimanapun, Anda perlu belajar untuk bekerja dengan Magento2, bukan menentangnya. Ya, ada kurva belajar. Jika Anda belum melakukannya, saya sangat menyarankan untuk mengambil PhpStorm atau IDE serupa.
Ryan Hoerr
0

UPDATE 2016-09-11: Seperti yang ditunjukkan quickshiftin, solusi ini tidak berfungsi untuk M2.1 +. Mencoba ketergantungan-menyuntikkan CategorySetupkelas di luar pengaturan akan memberi Anda kesalahan fatal. Lihat di sini untuk solusi yang lebih kuat: /magento//a/103951/1905


Gunakan \Magento\Catalog\Setup\CategorySetupkelas untuk ini. Ini termasuk addAttributeOption()metode, yang bekerja dengan cara yang persis sama seperti eav/entity_setup::addAttributeOption()pada 1.x. Ada beberapa metode atribut lain di sana yang mungkin bisa membantu juga.

Anda dapat menggunakan injeksi dependensi untuk mendapatkan kelas ini kapan saja, bahkan di luar proses pengaturan.

Secara khusus:

/**
 * Constructor.
 *
 * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
 * @param \Magento\Catalog\Setup\CategorySetupFactory $categorySetupFactory
 */
public function __construct(
    \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
    \Magento\Catalog\Setup\CategorySetupFactory $categorySetupFactory
) {
    $this->attributeRepository = $attributeRepository;
    $this->categorySetupFactory = $categorySetupFactory;
}

/**
 * Create a matching attribute option
 *
 * @param string $attributeCode Attribute the option should exist in
 * @param string $label Label to add
 * @return void
 */
public function addOption($attributeCode, $label) {
    $attribute = $this->attributeRepository->get($attributeCode);

    $categorySetup = $this->categorySetupFactory->create();
    $categorySetup->addAttributeOption(
        [
            'attribute_id'  => $attribute->getAttributeId(),
            'order'         => [0],
            'value'         => [
                [
                    0 => $label, // store_id => label
                ],
            ],
        ]
    );
}

Jika diinginkan, Anda bisa menghilangkan attributeRepositorykelas dan menggunakannya getAttribute()langsung categorySetup. Anda hanya perlu memasukkan ID jenis entitas setiap kali.

Ryan Hoerr
sumber
Hai Ryan, saya mencoba menggunakan CategorySetupFactoryinstantiate CategorySetupdari Console\Command, namun ketika saya sebut $factory->setup()kesalahan fatal terjadi:PHP Fatal error: Uncaught TypeError: Argument 1 passed to Magento\Setup\Module\DataSetup::__construct() must be an instance of Magento\Framework\Module\Setup\Context, instance of Magento\Framework\ObjectManager\ObjectManager given
quickshiftin
Ahh, sekarang saya menemukan thread ini di mana Anda menyatakan ini berhenti bekerja di Magento 2.1 (yang saya gunakan). Merevisi kode saya sekarang, tetapi lebih baik untuk mencatat pada jawaban untuk efek ini juga ...
quickshiftin
0

Magento 2 menambahkan opsi atribut khusus, Nilai secara terprogram.

Jalankan Script ini di direktori root magento setelah url.

$objectManager = \Magento\Framework\App\ObjectManager::getInstance(); // instance of object manager
try{
      $entityType = 'catalog_product';
      $attributeCode = 'manufacturer';
      $attributeInfo = $objectManager->get(\Magento\Eav\Model\Entity\Attribute::class)
                                 ->loadByCode($entityType, $attributeCode);


      $attributeFactory = $objectManager->get('\Magento\Catalog\Model\ResourceModel\Eav\Attribute');

      $attributeId = $attributeInfo->getAttributeId();
      //$manufacturer = $item->{'Manufacturer'};
      $attribute_arr = ['aaa','bbb','ccc','ddd'];

      $option = array();
      $option['attribute_id'] = $attributeId;
      foreach($attribute_arr as $key=>$value){
          $option['value'][$value][0]=$value;
          foreach($storeManager as $store){
              $option['value'][$value][$store->getId()] = $value;
          }
      }
      if ($option) {
        $eavSetupFactory = $objectManager->create('\Magento\Eav\Setup\EavSetup');
        print_r($eavSetupFactory->getAttributeOption());
        die();
        $eavSetupFactory->addAttributeOption($option);
      }
    }catch(Exception $e){
      echo $e->getMessage();
    }
Baharuni Asif
sumber