Come Magento2 aggiunge l'opzione di attributo a livello di codice (non in configurazione)


15

Cerco di aggiungere opzioni per gli attributi di dimensione e colore nel mio modulo importatore ma non so come ...:

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

Questo rapporto un errore (ho modificato eccezione rendicontazione sul OptionMaganger.phpper eccezione-> messaggio )

Impossibile salvare la dimensione dell'attributo Avviso: indice indefinito: cancellare in /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php sulla riga 177

  • OptionManagement e Option provengono da _contstructor
  • Con OptionManagement posso recuperare gli oggetti esistenti, quindi dovrebbe essere ok ..

setLabel()e setValue()sono predefiniti, ma ho provato setData , carica l'istanza dell'opzione e passa OptionManagement->getItemsper aggiungere (...) "di nuovo", ma l'errore esiste ancora ...

Qualche idea, come posso aggiungere le opzioni EAV (campioni?) Durante il processo di importazione? (non in configurazione modulo)


Aggiornare :

In altro modo posso aggiungere un'opzione:

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

In questo modo Magento2 può salvare un'opzione da attribuire, ma non so quale sia il modo "ufficiale" :)


opzione ha aggiunto qualsiasi valore come stringa non supportata per intero
Ajay Patel

Risposte:


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

dichiarare:

protected $_eavSetupFactory;

costruttore:

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

eseguire il metodo:

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)

}

Hai un errore grave nel tuo codice: $ option ['value'] [$ value] [0] - non dovrebbe essere $ value ma "option_id" - intero, per il nuovo set di opzioni 0. Questo è cast in numero intero, quindi se hai una stringa senza numero, ad es. "nero" sarà 0 correttamente. Ma se il tuo valore $ è simile a "10 Black", verrà trasmesso a 10 e aggiornerà l'entità del database con option_id = 10 invece di crearne uno nuovo. Ciò può causare seri problemi nel database del negozio.
A.Maksymiuk,

grazie di informare fratello. Se hai trovato qualche errore di quello che puoi aggiornare la mia risposta @ A.Maksymiuk
Chauhan

Fatto. Per favore, accetta, quindi ripristinerò il mio voto negativo.
A.Maksymiuk,

Approvata, ma vota verso il basso qualsiasi risposta non è il modo corretto bro, Se pensi che la risposta non sia correlata o meno come richiesto, altrimenti non puoi votare in negativo la risposta di nessuno. @ A.Maksymiuk
Chauhan

L'ho fatto per avvisare chiunque di usare questo codice, perché avrebbe causato gravi danni all'integrità dei dati. Ad esempio, invece, aggiungendo una nuova opzione denominata "42" (dimensione) lo script aggiornato option_id = 42 (che era un'opzione esistente di attributo completamente diverso). Fortunatamente mi è successo sul server di prova e sul nuovo database.
A.Maksymiuk,

2

In altro modo posso aggiungere un'opzione:

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

In questo modo Magento2 può salvare un'opzione da attribuire, ma non so quale sia il modo "ufficiale".


Guarda la mia strada Credo che sia "ufficiale"
CarComp

la tua soluzione funziona, ma solo quando l'opzione non funziona per l'intero
Ajay Patel

perché non dovrebbe funzionare con valori interi?
Vincent Teyssier,

0

Sembra essere un problema di convalida. La chiave di eliminazione nei dati proviene dal modulo nel back-end, quindi prova ad aggiungere una chiave di eliminazione vuota in questo modo:

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

Potrebbe funzionare.


Purtroppo no. OptionManager aggiunge (..) analizza il parametro $ option e lascia vuota la chiave 'delete', non capisco perché ... Ma ho trovato un altro modo ....
Interpigeon,

Bene, per favore aggiungi la tua soluzione come risposta per risolvere la domanda.
MauroNigrele,

Non riesco a rispondere alla mia domanda, ma ho aggiornato la domanda. Penso che la mia soluzione sia una soluzione alternativa ...
Interpigeon

Ehi, puoi rispondere alla tua domanda è abbastanza comune.
MauroNigrele,

0

Ho finito per riscrivere l'intera risposta usando i metodi ObjectFactory suggeriti da Ryan H.

Alla fine è stata una classe di supporto che utilizzava alcuni attributi che ho creato sull'oggetto cliente, ma l'idea è lì su come utilizzare EAV + ObjectFactories per manipolare le opzioni di attributo

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

1
Dovresti iniettare ObjectFactory e creare istanze di Object da quella, non iniettare Object stesso. Gli oggetti ORM non devono essere iniettati direttamente.
Ryan Hoerr,

Quale ObjectFactory? Ci sono 50. Sto guardando \ Magento \ Framework \ Api \ ObjectFactory ma sembra solo un wrapper per ObjectManager. Non sono sicuro del perché non dovrei implementare lo stesso gestore degli oggetti. Ci sono così tanti wrapper per wrapper di cose in questa nuova versione.
CarComp

1
Stavo parlando in astratto. Iniettare la Factory per il tuo oggetto dato, non letteralmente "ObjectFactory". Dovresti iniettare la fabbrica per ogni tipo specifico che usi e crearli secondo necessità. Sì, all'inizio sembra disordinato ... ma ci sono ottime ragioni per farlo. Inoltre, gli standard del codice ECG vietano quasi tutti l'uso diretto di ObjectManager. Vedi l'articolo di Alan Storm che spiega l'intero argomento: alanstorm.com/magento_2_object_manager_instance_objects
Ryan Hoerr

Cosa devo fare quando gli oggetti che voglio usare non hanno una fabbrica? Ad esempio, non riesco a trovare un modo per "fabbricare" le cose di gestione delle opzioni. Magento \ Eav \ Model \ AttributeFactory usa anche uno strano -> createAttribute (vars) invece di solo -> create (). Sto solo dicendo che quando non lavori con un prodotto o una categoria integrata, le cose diventano un po 'strane.
CarComp

1
Non tutti gli oggetti richiedono una fabbrica. Per quelli che lo fanno, la fabbrica potrebbe non esistere out-of-box - quelli che non esistono verranno creati in fase di esecuzione (con generazione DI) o durante la compilazione. Leggi l'articolo che ho collegato. In ogni caso, devi imparare a lavorare con Magento2, non contro di esso. Sì, c'è una curva di apprendimento. Se non lo fai già, ti consiglio vivamente di prendere PhpStorm o un IDE simile.
Ryan Hoerr,

0

AGGIORNAMENTO 2016-09-11: Come sottolineato da quickshift, questa soluzione non funziona con M2.1 +. Tentare di iniettare dipendenza dalla CategorySetupclasse al di fuori dell'installazione ti darà un errore fatale. Vedi qui per una soluzione più solida: /magento//a/103951/1905


Usa la \Magento\Catalog\Setup\CategorySetupclasse per questo. Include un addAttributeOption()metodo, che funziona esattamente allo stesso modo eav/entity_setup::addAttributeOption()di 1.x. Esistono altri metodi di attributo che potrebbero essere utili.

È possibile utilizzare l'iniezione di dipendenza per ottenere questa classe in qualsiasi momento, anche al di fuori di un processo di installazione.

In particolare:

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

Se lo si desidera, è possibile eliminare la attributeRepositoryclasse e utilizzarla getAttribute()direttamente su categorySetup. Dovresti semplicemente includere l'ID del tipo di entità ogni volta.


Ciao Ryan, sto cercando di usare il CategorySetupFactoryper istanziare a CategorySetupda a Console\Command, tuttavia quando chiamo $factory->setup()un errore fatale si verifica: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
cambio rapido

Ahh, ora mi sono imbattuto in questo thread in cui affermi che questo ha smesso di funzionare in Magento 2.1 (che sto usando). Revisionando il mio codice ora, ma probabilmente è meglio mettere una nota su questa risposta anche a questo effetto ...
quickshiftin

0

Magento 2 aggiunge l'opzione Attributo specifico Valore a livello di codice.

Esegui questo script nella directory principale di magento dopo l'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();
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.