Comment Magento2 ajoute une option d'attribut par programme (pas dans la configuration)

15

J'essaie d'ajouter des options pour les attributs de taille et de couleur dans mon module d'importateur mais je ne sais pas comment ...:

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

Ce rapport d'erreur (je modifié exception des rapports sur OptionMaganger.phpla exception-> Message )

Impossible d'enregistrer la taille de l'attribut Remarque: index non défini: supprimer dans /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php à la ligne 177

  • L'OptionManagement et l'Option proviennent de _contstructor
  • Avec OptionManagement, je peux récupérer les éléments existants, donc ça devrait aller.

setLabel()et setValue()sont par défaut, mais j'ai essayé setData , charger une instance d'option et passer OptionManagement->getItemspour ajouter (...) "encore", mais l'erreur existe toujours ...

Une idée, comment puis-je ajouter des options EAV (échantillons?) Pendant le processus d'importation? (pas dans la configuration du module)


Mise à jour :

Autre moyen, je peux ajouter une option:

$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 cette façon, Magento2 peut enregistrer une option à attribuer, mais je ne sais pas quelle est la manière "officielle" :)

Interpigeon
la source
option a ajouté une valeur car la chaîne n'est pas prise en charge pour l'entier
Ajay Patel

Réponses:

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

déclarer:

protected $_eavSetupFactory;

constructeur:

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

exécuter la méthode:

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
la source
Vous avez une grave erreur dans votre code: $ option ['value'] [$ value] [0] - il ne doit pas s'agir de $ value mais "option_id" - entier, pour un nouveau jeu d'options 0. Celui-ci est converti en entier, donc si vous avez une chaîne sans chiffre, par exemple "noir", elle sera correctement 0. Mais si votre valeur $ est quelque chose comme "10 Black", elle sera convertie en 10 et mettra à jour l'entité de base de données avec option_id = 10 au lieu d'en créer une nouvelle. Cela peut provoquer de sérieux dégâts dans votre base de données de boutique.
A.Maksymiuk
merci d'informer mon frère. Si vous avez trouvé une erreur, vous pouvez mettre à jour ma réponse @ A.Maksymiuk
Ronak Chauhan
L'a fait. Veuillez accepter, puis je reviendrai sur mon downvote.
A.Maksymiuk
Approuvée, mais voter contre une réponse n'est pas la bonne façon, bro. @ A.Maksymiuk
Ronak Chauhan
Je l'ai fait pour avertir quiconque d'utiliser ce code, car cela causerait de graves dommages à l'intégrité des données. Par exemple, en ajoutant une nouvelle option nommée "42" (taille), votre script a mis à jour option_id = 42 (qui était l'option existante d'un attribut complètement différent). Heureusement, cela m'est arrivé sur le serveur de test et sur une nouvelle base de données.
A.Maksymiuk
2

Autre moyen, je peux ajouter une option:

$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 cette façon, Magento2 peut enregistrer une option à attribuer, mais je ne sais pas quelle est la manière "officielle".

Interpigeon
la source
Voyez mon chemin. Je pense que c'est «officiel»
CarComp
votre solution fonctionne mais uniquement lorsque l'option ne fonctionne pas pour l'entier
Ajay Patel
pourquoi cela ne fonctionnerait-il pas pour les valeurs entières?
Vincent Teyssier
0

Semble être un problème de validation. La clé de suppression dans les données provient du formulaire dans le backend, essayez donc d'ajouter une clé de suppression vide de cette façon:

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

Ça pourrait marcher.

MauroNigrele
la source
Malheureusement non. L'OptionManager add (..) ré-analyse le paramètre $ option et laisse la touche 'delete' vide, je ne sais pas pourquoi ... Mais j'ai trouvé un autre moyen ....
Interpigeon
Très bien, veuillez ajouter votre solution comme réponse pour résoudre la question.
MauroNigrele
Je ne peux pas répondre à ma propre question, mais j'ai mis à jour la question. Je pense que ma solution est une solution de contournement ...
Interpigeon
Hé, vous pouvez répondre à votre question est assez courante.
MauroNigrele
0

J'ai fini par réécrire toute cette réponse en utilisant les méthodes ObjectFactory suggérées par Ryan H.

Cela a fini par être une classe d'assistance qui utilisait certains attributs que j'ai créés sur l'objet client, mais l'idée est là sur la façon d'utiliser EAV + ObjectFactories pour manipuler les options d'attribut

<?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
la source
1
Vous devez injecter ObjectFactory et créer des instances d'Object à partir de cela, pas injecter Object lui-même. Les objets ORM ne doivent pas être injectés directement.
Ryan Hoerr
Quelle ObjectFactory? Il y en a comme 50. Je regarde \ Magento \ Framework \ Api \ ObjectFactory mais cela ressemble à un wrapper pour ObjectManager. Je ne sais pas pourquoi je ne voudrais pas simplement implémenter le gestionnaire d'objets lui-même. Il y a tellement de wrappers pour des wrappers de choses dans cette nouvelle version.
CarComp
1
Je parlais dans l'abstrait. Injectez la Factory pour votre objet donné, pas littéralement «ObjectFactory». Vous devez injecter l'usine pour chaque type spécifique que vous utilisez et les créer au besoin. Oui, cela semble désordonné au début ... mais il y a de très bonnes raisons à cela. En outre, les normes de code ECG interdisent presque toute utilisation directe d'ObjectManager. Voir l'article d'Alan Storm expliquant tout le sujet: alanstorm.com/magento_2_object_manager_instance_objects
Ryan Hoerr
Que dois-je faire lorsque les objets que je souhaite utiliser n'ont pas d'usine? Par exemple, je ne trouve pas de moyen de «fabriquer» les éléments de gestion des options. Magento \ Eav \ Model \ AttributeFactory utilise également un étrange -> createAttribute (vars) au lieu de simplement -> create (). Je dis simplement que lorsque vous ne travaillez pas avec un produit ou une catégorie intégrée, les choses deviennent un peu bizarres.
CarComp
1
Tous les objets ne nécessitent pas d'usine. Pour ceux qui le font, la fabrique peut ne pas exister d'origine - toutes celles qui n'existent pas seront créées au moment de l'exécution (avec génération DI) ou lors de la compilation. Lisez l'article que j'ai lié. Quoi qu'il en soit, vous devez apprendre à travailler avec Magento2, pas contre. Oui, il y a une courbe d'apprentissage. Si vous ne l'avez pas déjà fait, je vous recommande fortement de choisir PhpStorm ou un IDE similaire.
Ryan Hoerr
0

MISE À JOUR 2016-09-11: Comme l'a souligné quickshiftin, cette solution ne fonctionne pas pour M2.1 +. Une tentative d'injection de dépendance de la CategorySetupclasse en dehors de l'installation vous donnera une erreur fatale. Voir ici pour une solution plus robuste: /magento//a/103951/1905


Utilisez la \Magento\Catalog\Setup\CategorySetupclasse pour cela. Il comprend une addAttributeOption()méthode, qui fonctionne exactement de la même manière que eav/entity_setup::addAttributeOption()dans 1.x. Il existe d'autres méthodes d'attribut qui pourraient également être utiles.

Vous pouvez utiliser l'injection de dépendances pour obtenir cette classe à tout moment, même en dehors d'un processus d'installation.

Plus précisément:

/**
 * 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 vous le souhaitez, vous pouvez éliminer la attributeRepositoryclasse et l'utiliser getAttribute()directement categorySetup. Il vous suffirait d'inclure l'ID de type d'entité à chaque fois.

Ryan Hoerr
la source
Salut Ryan, j'essaie d'utiliser le CategorySetupFactorypour instancier un à CategorySetuppartir d'un Console\Command, cependant quand j'appelle $factory->setup()une erreur fatale se produit: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, je suis maintenant tombé sur ce fil dans lequel vous déclarez que cela a cessé de fonctionner dans Magento 2.1 (que j'utilise). Révision de mon code maintenant, mais il est préférable de mettre une note sur cette réponse à cet effet aussi ...
quickshiftin
0

Magento 2 ajoute l'option d'attribut spécifique Valeur par programme.

Exécutez ce script dans le répertoire racine de magento après 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();
    }
Baharuni Asif
la source