Como o Magento2 adiciona opção de atributo programaticamente (não está na instalação)

15

Eu tento adicionar opções para atributos de tamanho e cor no módulo de importação, mas não sei como ...:

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

Isso relata um erro (modifiquei o relatório OptionMaganger.phpde exceção para Exceção-> mensagem )

Não é possível salvar o tamanho do atributo Aviso: Índice indefinido: exclua em /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php na linha 177

  • O OptionManagement e Option vêm de _contstructor
  • Com OptionManagement eu posso recuperar os itens existentes, então tudo bem.

setLabel()e setValue()são padrão, mas tentei setData , carregue a instância da opção e passe OptionManagement->getItemspara adicionar (...) "novamente", mas o erro ainda existe ...

Alguma idéia, como posso acrescentar Opções de EAV (amostras?) Durante o processo de importação? (não na configuração do módulo)


Atualização:

Outra maneira de adicionar a opção:

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

Dessa forma, o Magento2 pode salvar uma opção para atribuir, mas não sei qual é a maneira "oficial" :)

Interpigeon
fonte
opção adicional de qualquer valor como seqüência de caracteres não suportados para inteiro
Ajay Patel

Respostas:

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

declarar:

protected $_eavSetupFactory;

construtor:

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

execute o método:

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
fonte
Você tem um erro grave no seu código: $ option ['value'] [$ value] [0] - não deve ser $ value, mas "option_id" - número inteiro, para o novo conjunto de opções 0. Este é convertido em número inteiro, portanto, se você tiver uma sequência sem numer, por exemplo, "preto" será 0 corretamente. Mas se o seu valor $ for algo como "10 Black", ele será convertido para 10 e atualizará a entidade do banco de dados com option_id = 10, em vez de criar um novo. Isso pode causar sérios problemas no banco de dados da sua loja.
A.Maksymiuk
obrigado a informar irmão. Se você encontrou algum erro que você pode atualizar a minha resposta @ A.Maksymiuk
Ronak Chauhan
Fiz isso. Por favor aceite, então vou reverter meu voto negativo.
A.Maksymiuk
Aprovado, mas o voto negativo de qualquer resposta não é a maneira correta, mano, se você acha que a resposta não está relacionada ou não, conforme solicitado, você pode não votar novamente a resposta de ninguém. @ A.Maksymiuk
Ronak Chauhan
Fiz isso para avisar alguém a usar esse código, pois causaria sérios danos à integridade dos dados. Por exemplo, ao adicionar uma nova opção chamada "42" (tamanho), seu script atualizou option_id = 42 (que era a opção existente de atributo completamente diferente). Felizmente, isso aconteceu comigo no servidor de teste e no novo banco de dados.
A.Maksymiuk
2

Outra maneira de adicionar a opção:

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

Dessa forma, o Magento2 pode salvar uma opção para atribuir, mas não sei qual é a maneira "oficial".

Interpigeon
fonte
Veja o meu caminho. Eu acredito que seja 'oficial'
CarComp 31/03
sua solução é trabalho, mas apenas quando a opção são opção não trabalho para inteiro
Ajay Patel
por que não funcionaria para valores inteiros?
Vincent Teyssier
0

Parece ser um problema de validação. A chave de exclusão nos dados vem do formulário no back-end; portanto, tente adicionar uma chave de exclusão vazia dessa maneira:

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

Poderia funcionar.

MauroNigrele
fonte
Infelizmente não. O add OptionManager (..) reanalisar o parâmetro $ opção e deixar o 'delete' chave vazia, eu não fazer nada por isso ... Mas eu encontrei outra maneira ....
Interpigeon
Ótimo, adicione sua solução como resposta para resolver a pergunta.
MauroNigrele 2/16
Não consigo responder minha própria pergunta, mas atualizei a pergunta. Eu acho que a minha solução é uma solução ...
Interpigeon
Ei, você pode responder à sua pergunta é bastante comum.
MauroNigrele 2/16/16
0

Acabei reescrevendo toda essa resposta usando os métodos ObjectFactory sugeridos por Ryan H.

Acabou sendo uma classe auxiliar que utilizou alguns atributos que eu criei no objeto do cliente, mas a idéia é de como utilizar o EAV + ObjectFactories para manipular opções de atributos

<?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
fonte
11
Você deve injetar o ObjectFactory e criar instâncias do Object a partir dele, não injetando o próprio Object. Objetos ORM não devem ser injetados diretamente.
Ryan Hoerr
Qual ObjectFactory? Há 50. Estou olhando para \ Magento \ Framework \ Api \ ObjectFactory, mas parece um invólucro para o ObjectManager. Não sei por que não implementaria apenas o gerenciador de objetos. Há tantos invólucros para invólucros de coisas nesta nova versão.
CarComp 08/04
11
Eu estava falando em abstrato. Injete o Factory para o seu objeto especificado, não literalmente 'ObjectFactory'. Você deve injetar a fábrica para cada tipo específico usado e criá-los conforme necessário. Sim, parece confuso no começo ... mas há boas razões para isso. Além disso, os padrões de código de ECG praticamente proíbem o uso direto do ObjectManager. Artigo See de Alan Storm explicar todo o assunto: alanstorm.com/magento_2_object_manager_instance_objects
Ryan Hoerr
O que devo fazer quando os objetos que quero usar não têm uma fábrica? Por exemplo, não consigo encontrar uma maneira de 'fabricar' o material de gerenciamento de opções. O Magento \ Eav \ Model \ AttributeFactory também usa um estranho -> createAttribute (vars) em vez de apenas -> create (). Só estou dizendo que, quando você não trabalha com um produto ou com uma categoria incorporada, as coisas ficam um pouco estranhas.
CarComp 08/04
11
Nem todos os objetos exigirão uma fábrica. Para os que existem, a fábrica pode não existir pronta para uso - qualquer que não existir será criado em tempo de execução (com geração DI) ou durante a compilação. Leia o artigo que eu vinculei. De qualquer forma, você precisa aprender a trabalhar com o Magento2, não contra ele. Sim, existe uma curva de aprendizado. Se ainda não o fez, recomendo que você escolha o PhpStorm ou um IDE semelhante.
Ryan Hoerr
0

ATUALIZAÇÃO 11-09-2016: Como o quickshiftin apontou, esta solução não funciona para o M2.1 +. Tentar injetar dependência na CategorySetupclasse fora da instalação resultará em um erro fatal. Veja aqui uma solução mais robusta: /magento//a/103951/1905


Use a \Magento\Catalog\Setup\CategorySetupclasse para isso. Ele inclui um addAttributeOption()método, que funciona exatamente da mesma maneira que eav/entity_setup::addAttributeOption()no 1.x. Existem alguns outros métodos de atributo que também podem ser úteis.

Você pode usar a injeção de dependência para obter essa classe a qualquer momento, mesmo fora de um processo de instalação.

Especificamente:

/**
 * 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 desejar, você pode eliminar a attributeRepositoryclasse e usá-la getAttribute()diretamente categorySetup. Você só precisa incluir o ID do tipo de entidade a cada vez.

Ryan Hoerr
fonte
Oi Ryan, Estou tentando usar o CategorySetupFactorypara instanciar um CategorySetupde um Console\Command, no entanto, quando eu chamo $factory->setup()um erro fatal ocorre: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, agora eu deparei com este tópico no qual você declara que parou de funcionar no Magento 2.1 (que estou usando). Rever meu código agora, mas prov melhor colocar uma nota sobre esta resposta para o efeito, bem ...
quickshiftin
0

Magento 2 add Opção de atributo específico Valor programaticamente.

Execute este script no diretório raiz do magento após o 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
fonte