Cómo Magento2 agrega la opción de atributo mediante programación (no en la configuración)

15

Intento agregar opciones para los atributos de tamaño y color en mi módulo importador pero no sé cómo ...:

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

Esto informa un error (modifiqué la excepción que informa OptionMaganger.phpa Excepción-> mensaje )

No se puede guardar el tamaño del atributo Aviso: Índice no definido: eliminar en /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php en la línea 177

  • OptionManagement y Option provienen de _contstructor
  • Con OptionManagement puedo recuperar los elementos existentes, por lo que debería estar bien.

setLabel()y setValue()son predeterminados, pero intenté setData , cargar la instancia de opción y pasar OptionManagement->getItemspara agregar (...) "nuevamente", pero el error aún existe ...

Alguna idea, ¿cómo puedo agregar opciones EAV (muestras?) Durante el proceso de importación? (no en configuración de módulo)


Actualización:

De otra manera, puedo agregar la opción:

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

De esta manera, Magento2 puede guardar una opción para atribuir, pero no sé cuál es la forma "oficial" :)

Interpigeon
fuente
opción agregó cualquier valor como cadena no compatible para entero
Ajay Patel

Respuestas:

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

declarar:

protected $_eavSetupFactory;

constructor

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

ejecutar 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
fuente
Tiene un error grave en su código: $ option ['value'] [$ value] [0] - no debe ser $ value sino "option_id" - entero, para el nuevo conjunto de opciones 0. Este se convierte en entero, así que si tiene una cadena sin número, por ejemplo, "negro", será 0 correctamente. Pero si su valor de $ es algo así como "10 Black", se convertirá en 10 y actualizará la entidad de la base de datos con option_id = 10 en su lugar, creando uno nuevo. Esto puede causar serios problemas en la base de datos de su tienda.
A.Maksymiuk
Gracias por informar hermano. Si encuentra algún error, puede actualizar mi respuesta @ A.Maksymiuk
Ronak Chauhan
Lo hizo. Acepte, luego revertiré mi voto negativo.
A.Maksymiuk
Aprobado, pero rechazar cualquier respuesta no es la forma correcta hermano, si cree que esa respuesta no está relacionada o no según lo solicitado, entonces no puede rechazar la respuesta de nadie. @ A.Maksymiuk
Ronak Chauhan
Lo hice para advertir a cualquiera que use este código, ya que causaría daños graves en la integridad de los datos. Por ejemplo, al agregar una nueva opción llamada "42" (tamaño), su script actualizó option_id = 42 (que era una opción existente de un atributo completamente diferente). Afortunadamente, me pasó en el servidor de prueba y en una nueva base de datos nueva.
A.Maksymiuk
2

De otra manera, puedo agregar la opción:

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

De esta manera, Magento2 puede guardar una opción para atribuir, pero no sé cuál es la forma "oficial".

Interpigeon
fuente
Mira mi camino Creo que es 'oficial'
CarComp
su solución es el trabajo, pero solo cuando la opción no es la opción para el número entero
Ajay Patel
¿Por qué no funcionaría para valores enteros?
Vincent Teyssier
0

Parece ser un problema de validación. La clave de eliminación en los datos proviene del formulario en el back-end, así que intente agregar una clave de eliminación vacía de esa manera:

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

Podría funcionar

MauroNigrele
fuente
Tristemente no. OptionManager add (..) vuelve a analizar el parámetro $ option y deja la tecla 'eliminar' vacía, no sé por qué ... Pero encontré otra forma ...
Interpigeon
Genial, agregue su solución como respuesta para resolver la pregunta.
MauroNigrele
No puedo responder mi propia pregunta, pero actualicé la pregunta. Creo que mi solución es una solución alternativa ...
Interpigeon
Oye, puedes responder que tu pregunta es bastante común.
MauroNigrele
0

Terminé reescribiendo toda esta respuesta usando métodos ObjectFactory sugeridos por Ryan H.

Terminó siendo una clase auxiliar que utilizaba algunos atributos que creé en el objeto del cliente, pero la idea está ahí sobre cómo utilizar EAV + ObjectFactories para manipular las opciones 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
fuente
1
Debería inyectar ObjectFactory y crear instancias de Object a partir de eso, no inyectando Object en sí. Los objetos ORM no deben inyectarse directamente.
Ryan Hoerr
¿Qué ObjectFactory? Hay como 50. Estoy mirando \ Magento \ Framework \ Api \ ObjectFactory pero parece un contenedor para ObjectManager. No estoy seguro de por qué no solo implementaría el administrador de objetos. Hay tantos envoltorios para envoltorios de cosas en esta nueva versión.
CarComp
1
Estaba hablando en abstracto. Inyecte la Fábrica para su objeto dado, no literalmente 'ObjectFactory'. Debe inyectar la fábrica para cada tipo específico que use y crearlos según sea necesario. Sí, parece desordenado al principio ... pero hay muy buenas razones para ello. Además, los estándares de código de ECG prohíben el uso directo de ObjectManager. Vea el artículo de Alan Storm que explica todo el tema: alanstorm.com/magento_2_object_manager_instance_objects
Ryan Hoerr
¿Qué debo hacer cuando los objetos que quiero usar no tienen fábrica? Por ejemplo, no puedo encontrar una manera de 'fabricar' las cosas de gestión de opciones. Magento \ Eav \ Model \ AttributeFactory también usa un extraño -> createAttribute (vars) en lugar de solo -> create (). Solo digo que cuando no trabajas con un producto o una categoría integrada, las cosas se ponen un poco raras.
CarComp
1
No todos los objetos requerirán una fábrica. Para aquellos que sí, es posible que la fábrica no exista de fábrica; cualquiera que no exista se creará en tiempo de ejecución (con generación DI) o durante la compilación. Lee el artículo que vinculé. De cualquier manera, debe aprender a trabajar con Magento2, no en contra. Sí, hay una curva de aprendizaje. Si aún no lo hace, le recomiendo que elija PhpStorm o un IDE similar.
Ryan Hoerr
0

ACTUALIZACIÓN 2016-09-11: Como señaló quickshiftin, esta solución no funciona para M2.1 +. Intentar inyectar dependencia a la CategorySetupclase fuera de la configuración le dará un error fatal. Consulte aquí para obtener una solución más sólida: /magento//a/103951/1905


Usa la \Magento\Catalog\Setup\CategorySetupclase para esto. Incluye un addAttributeOption()método, que funciona exactamente de la misma manera que eav/entity_setup::addAttributeOption()en 1.x. Existen algunos otros métodos de atributos que también pueden ser útiles.

Puede usar la inyección de dependencia para obtener esta clase en cualquier momento, incluso fuera de un proceso de configuración.

Específicamente:

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

Si lo desea, puede eliminar la attributeRepositoryclase y usarla getAttribute()directamente categorySetup. Solo tendría que incluir el ID de tipo de entidad cada vez.

Ryan Hoerr
fuente
Hola Ryan, estoy tratando de usar el CategorySetupFactorypara crear una instancia CategorySetupde un Console\Command, sin embargo, cuando llamo $factory->setup()ocurre un error fatal: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, ahora me he topado con este hilo en el que dices que esto dejó de funcionar en Magento 2.1 (que estoy usando). Revisando mi código ahora, pero probablemente sea mejor poner una nota en esta respuesta también a ese efecto ...
quickshiftin
0

Magento 2 agrega la opción de atributo específico Valor mediante programación.

Ejecute este script en el directorio raíz de magento después de 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
fuente