Wie Magento2 Attributoption programmgesteuert hinzufügt (nicht im Setup)

15

Ich versuche, Optionen für Größen- und Farbattribute in meinem Importmodul hinzuzufügen, aber ich weiß nicht, wie ...:

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

Dieser Bericht enthält einen Fehler. (Ich habe die Ausnahmeberichterstattung OptionMaganger.phpunter Ausnahme-> Nachricht geändert. )

Attributgröße kann nicht gespeichert werden Hinweis: Nicht definierter Index: Löschen in /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php in Zeile 177

  • Das OptionManagement und die Option stammen von _contstructor
  • Mit OptionManagement kann ich die vorhandenen Elemente abrufen, sollte also in Ordnung sein.

setLabel()und setValue()sind voreingestellt, aber ich habe versucht, setData , load option instance und pass by OptionManagement->getItemszu add (...) "again", aber der Fehler besteht immer noch ...

Irgendeine Idee, wie kann ich EAV-Optionen (Farbfelder?) Während des Importvorgangs anhängen? (nicht im Modul-Setup)


Update:

Auf andere Weise kann ich Option hinzufügen:

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

Auf diese Weise kann Magento2 eine Option zum Attributieren speichern, aber ich weiß nicht, was der "offizielle" Weg ist :)

Interpigeon
quelle
Die Option fügte einen beliebigen Wert als Zeichenfolge hinzu, der für eine Ganzzahl nicht unterstützt wird
Ajay Patel

Antworten:

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

erklären:

protected $_eavSetupFactory;

Konstrukteur :

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

Methode ausführen:

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
quelle
Sie haben einen schwerwiegenden Fehler in Ihrem Code: $ option ['value'] [$ value] [0] - es sollte nicht $ value, sondern "option_id" - integer sein, für eine neue Option set 0. Diese wird in integer umgewandelt, Wenn Sie also eine Zeichenfolge ohne Zahl haben, z. B. "schwarz", ist diese korrekt 0. Wenn Ihr $ -Wert jedoch so etwas wie "10 Black" ist, wird er in 10 umgewandelt und die Datenbankentität mit option_id = 10 aktualisiert, anstatt eine neue zu erstellen. Dies kann zu ernsthaften Problemen in Ihrer Shop-Datenbank führen.
A.Maksymiuk
danke Bruder zu informieren. Wenn Sie einen Fehler gefunden haben, können Sie meine Antwort @ A.Maksymiuk
Ronak Chauhan
Geschafft. Bitte akzeptiere, dann kehre ich meine Ablehnung zurück.
A.Maksymiuk
Genehmigt, aber keine Antwort abzustimmen ist nicht der richtige Weg, Bruder. Wenn Sie der Meinung sind, dass diese Antwort nicht verwandt ist oder nicht den gestellten Fragen entspricht, können Sie ansonsten die Antwort von niemandem abstimmen. @ A.Maksymiuk
Ronak Chauhan
Ich habe es getan, um jeden zu warnen, diesen Code zu verwenden, da dies die Datenintegrität ernsthaft beeinträchtigen würde. ZB statt Hinzufügen einer neuen Option mit dem Namen "42" (Größe) aktualisiert Ihr Skript option_id = 42 (die vorhandene Option mit einem vollständig anderen Attribut). Zum Glück geschah es mir auf Testserver und neuer Datenbank.
A.Maksymiuk
2

Auf andere Weise kann ich Option hinzufügen:

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

Auf diese Weise kann Magento2 eine Option zum Attributieren speichern, aber ich weiß nicht, was der "offizielle" Weg ist.

Interpigeon
quelle
Seht meinen Weg. Ich glaube, es ist 'offiziell'
CarComp
Ihre Lösung ist Arbeit, aber nur, wenn Option Option nicht für Integer arbeiten
Ajay Patel
Warum funktioniert es nicht für ganzzahlige Werte?
Vincent Teyssier
0

Scheint ein Validierungsproblem zu sein. Der Löschschlüssel für Daten stammt aus dem Formular im Backend. Fügen Sie also auf diese Weise einen leeren Löschschlüssel hinzu:

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

Es könnte funktionieren.

MauroNigrele
quelle
Traurigerweise Nein. Der OptionManager add (..) analysiert den $ option-Parameter und lässt den 'delete'-Schlüssel leer, ich weiß nicht warum ... Aber ich habe einen anderen Weg gefunden ...
Interpigeon
Gut, bitte fügen Sie Ihre Lösung als Antwort hinzu, um die Frage zu lösen.
MauroNigrele
Ich kann meine eigene Frage nicht beantworten, aber ich habe die Frage aktualisiert. Ich denke, meine Lösung ist eine
Problemumgehung
Hey, du kannst deine Frage beantworten, das kommt ziemlich häufig vor.
MauroNigrele
0

Am Ende habe ich die gesamte Antwort mit den von Ryan H. vorgeschlagenen ObjectFactory-Methoden umgeschrieben.

Am Ende war es eine Helper-Klasse, die einige Attribute verwendete, die ich für das Kundenobjekt erstellt hatte. Die Idee ist jedoch, wie EAV + ObjectFactories zum Bearbeiten von Attributoptionen verwendet werden kann

<?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
quelle
1
Sie sollten ObjectFactory injizieren und Instanzen von Object daraus erstellen, ohne Object selbst zu injizieren. ORM-Objekte dürfen nicht direkt injiziert werden.
Ryan Hoerr
Welche ObjectFactory? Theres wie 50. Ich betrachte \ Magento \ Framework \ Api \ ObjectFactory, aber es sieht aus wie ein Wrapper für ObjectManager. Ich bin mir nicht sicher, warum ich den Objektmanager nicht einfach selbst implementieren würde. Theres so viele Wrapper für Wrapper der Dinge in dieser neuen Version.
CarComp
1
Ich habe abstrakt gesprochen. Injizieren Sie die Factory für Ihr gegebenes Objekt, nicht wörtlich "ObjectFactory". Sie sollten die Fabrik für jeden spezifischen Typ, den Sie verwenden, injizieren und sie nach Bedarf erstellen. Ja, es scheint auf den ersten Blick chaotisch ... aber es gibt sehr gute Gründe dafür. Außerdem verbieten die EKG-Code-Standards die direkte Verwendung von ObjectManager. Lesen Sie
Ryan Hoerr
Was soll ich tun, wenn die Objekte, die ich verwenden möchte, keine Fabrik haben? Zum Beispiel kann ich keinen Weg finden, das Optionsmanagement-Zeug zu "fabrizieren". Magento \ Eav \ Model \ AttributeFactory verwendet statt nur -> create () auch ein seltsames -> createAttribute (vars). Ich sage nur, wenn Sie nicht mit einem Produkt oder einer Kategorie arbeiten, die in Sachen gebaut ist, werden die Dinge etwas seltsam.
CarComp
1
Nicht für alle Objekte ist eine Fabrik erforderlich. In diesem Fall ist die Factory möglicherweise nicht sofort einsatzbereit. Nicht vorhandene Factorys werden zur Laufzeit (mit DI-Generierung) oder während der Kompilierung erstellt. Lesen Sie den Artikel, den ich verlinkt habe. Wie auch immer, Sie müssen lernen, mit Magento2 zu arbeiten, nicht dagegen. Ja, es gibt eine Lernkurve. Wenn Sie es noch nicht getan haben, empfehle ich dringend, PhpStorm oder eine ähnliche IDE zu erwerben.
Ryan Hoerr
0

UPDATE 2016-09-11: Wie Quickshiftin betonte, funktioniert diese Lösung nicht für M2.1 +. Der Versuch, die CategorySetupKlasse außerhalb von Setup in Abhängigkeit zu injizieren , führt zu einem schwerwiegenden Fehler. Eine robustere Lösung finden Sie hier: /magento//a/103951/1905


Verwenden Sie dazu die \Magento\Catalog\Setup\CategorySetupKlasse. Es enthält eine addAttributeOption()Methode, die genauso funktioniert wie eav/entity_setup::addAttributeOption()in 1.x. Es gibt noch einige andere Attributmethoden, die ebenfalls hilfreich sein könnten.

Sie können die Abhängigkeitsinjektion verwenden, um diese Klasse jederzeit abzurufen, auch außerhalb eines Installationsprozesses.

Speziell:

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

Falls gewünscht, können Sie die attributeRepositoryKlasse entfernen und getAttribute()direkt weiter verwenden categorySetup. Sie müssten nur jedes Mal die Entitätstyp-ID angeben.

Ryan Hoerr
quelle
Hallo Ryan, ich versuche das zu benutzen CategorySetupFactory, um ein CategorySetupvon einem zu instanziieren Console\Command, aber wenn ich $factory->setup()einen fatalen Fehler 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
aufrufe,
Ahh, ich bin jetzt auf diesen Thread gestoßen, in dem Sie angeben, dass dies in Magento 2.1 (das ich verwende) nicht mehr funktioniert. Ich überarbeite jetzt meinen Code, aber am besten schreibe ich auch eine Notiz zu dieser Antwort ...
quickshiftin
0

Magento 2 Spezifische Attributoption hinzufügen Programmgesteuerter Wert.

Führen Sie dieses Skript im Stammverzeichnis von Magento nach der URL aus.

$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
quelle