Как Magento2 добавить параметр атрибута программно (не в настройке)

15

Я пытаюсь добавить параметры для атрибутов размера и цвета в моём модуле импортера, но не знаю как:

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

Этот отчет об ошибке (я изменил исключение отчетов о OptionMaganger.phpк Exception-> сообщение )

Невозможно сохранить размер атрибута. Примечание: неопределенный индекс: удалить в /var/www/html/magento2/vendor/magento/module-swatches/Model/Plugin/EavAttribute.php в строке 177.

  • OptionManagement и Option происходят из _contstructor
  • С OptionManagement я могу получить существующие элементы, так что должно быть в порядке ..

setLabel()и setValue()по умолчанию, но я попробовал setData , загрузить экземпляр опции и пройти, OptionManagement->getItemsчтобы добавить (...) "снова", но ошибка все еще существует ...

Любая идея, как я могу добавить параметры EAV (образцы?) В процессе импорта? (не в модульной настройке)


Обновить :

Другой способ я могу добавить вариант:

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

Таким образом, Magento2 может сохранить опцию для атрибута, но я не знаю, что такое «официальный» способ :)

Interpigeon
источник
опция добавила любое значение, так как строка не поддерживается для целого числа
Ajay Patel

Ответы:

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

заявляет:

protected $_eavSetupFactory;

конструктор:

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

выполнить метод:

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)

}
Ронак Чаухан
источник
В вашем коде есть серьезная ошибка: $ option ['value'] [$ value] [0] - это должно быть не $ value, а "option_id" - целое число, для новой опции установлено значение 0. Это приведено к целому числу, так что если у вас есть строка без нумерации, например, «черный», это будет 0 правильно. Но если ваше значение $ равно «10 Black», оно преобразуется в 10 и обновляет сущность базы данных с параметром option_id = 10 вместо создания нового. Это может привести к серьезному беспорядку в базе данных вашего магазина.
А.Максымюк
спасибо сообщить брату. Если вы нашли какую-либо ошибку, чем можете обновить мой ответ @ A.Maksymiuk
Ronak Chauhan
Сделал это. Пожалуйста, примите, тогда я вернусь вниз.
А.Максимюк
Одобрено, но недооценка любого ответа не является правильным способом, братан. Если вы считаете, что ответ не связан или не соответствует предложенному, то вы не можете переоценить чей-либо ответ. @ A.Maksymiuk
Ронак Чаухан
Я сделал это, чтобы предупредить всех, кто использует этот код, потому что это может привести к серьезным нарушениям целостности данных. Например, вместо добавления новой опции с именем «42» (размер) ваш скрипт обновил option_id = 42 (который был существующей опцией совершенно другого атрибута). К счастью, это случилось со мной на тестовом сервере и новой новой базе данных.
А.Максимюк
2

Другой способ я могу добавить вариант:

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

Таким образом, Magento2 может сохранить опцию для атрибута, но я не знаю, что такое «официальный» способ.

Interpigeon
источник
Смотри мой путь. Я считаю, что это «официально»
CarComp
ваше решение работает, но только когда опция не работает для целых чисел
Ajay Patel
почему бы не работать для целочисленных значений?
Винсент
0

Кажется, проблема с проверкой. Ключ удаления данных поступает из формы в бэкэнде, поэтому попробуйте добавить пустой ключ удаления следующим образом:

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

Это может работать.

MauroNigrele
источник
К сожалению нет. OptionManager add (..) повторно анализирует параметр $ option и оставляет ключ 'delete' пустым, я не знаю почему ... Но я нашел другой способ ....
Interpigeon
Отлично, пожалуйста, добавьте свое решение в качестве ответа для решения вопроса.
MauroNigrele
Я не могу ответить на свой вопрос, но я обновил вопрос. Я думаю, что мое решение - это обходной путь ...
Interpigeon
Эй, вы можете ответить на ваш вопрос довольно часто.
MauroNigrele
0

В итоге я переписал весь ответ, используя методы ObjectFactory, предложенные Райаном Х.

В итоге он стал вспомогательным классом, который использовал некоторые атрибуты, которые я создал для объекта customer, но идея заключается в том, как использовать EAV + ObjectFactories для управления параметрами атрибута.

<?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
источник
1
Вы должны вводить ObjectFactory и создавать из него экземпляры Object, а не сам Object. Объекты ORM не должны вводиться напрямую.
Райан Херр
Какой ObjectFactory? Theres как 50. Я смотрю на \ Magento \ Framework \ Api \ ObjectFactory, но это просто выглядит как обертка для ObjectManager. Я не уверен, почему бы не реализовать сам менеджер объектов. В этой новой версии так много обёрток для обёрток вещей.
CarComp
1
Я говорил абстрактно. Введите Фабрику для данного объекта, а не буквально «ObjectFactory». Вы должны ввести фабрику для каждого конкретного типа, который вы используете, и создавать их по мере необходимости. Да, сначала это кажется грязным ... но для этого есть очень веские причины. Кроме того, стандарты кода ЭКГ почти запрещают прямое использование ObjectManager. См. Статью Алана Шторма, объясняющую всю тему: alanstorm.com/magento_2_object_manager_instance_objects
Райан Херр,
Что делать, если объекты, которые я хочу использовать, не имеют фабрики? Например, я не могу найти способ «фабрикировать» вещи управления опциями. Magento \ Eav \ Model \ AttributeFactory также использует странный -> createAttribute (vars) вместо просто -> create (). Я просто говорю, что когда вы не работаете с продуктом или категорией, встроенной в вещи, вещи становятся немного странными.
CarComp
1
Не все объекты потребуют фабрики. Для тех, кто это делает, фабрика может не существовать вне коробки - любая несуществующая будет создана во время выполнения (с генерацией DI) или во время компиляции. Прочитайте статью, которую я связал. В любом случае, вам нужно научиться работать с Magento2, а не против него. Да, есть кривая обучения. Если вы этого еще не сделали, я настоятельно рекомендую выбрать PhpStorm или аналогичную IDE.
Райан Херр
0

ОБНОВЛЕНИЕ 2016-09-11: Как указал quickshiftin, это решение не работает для M2.1 +. Попытка внедрить CategorySetupкласс с зависимостями вне установки приведет к фатальной ошибке. Смотрите здесь для более надежного решения: /magento//a/103951/1905


Используйте \Magento\Catalog\Setup\CategorySetupкласс для этого. Он включает addAttributeOption()метод, который работает точно так же, как eav/entity_setup::addAttributeOption()в 1.x. Там также могут быть полезны некоторые другие методы атрибутов.

Вы можете использовать внедрение зависимостей, чтобы получить этот класс в любое время, даже вне процесса установки.

В частности:

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

При желании вы можете исключить attributeRepositoryкласс и использовать getAttribute()напрямую categorySetup. Вам просто нужно будет каждый раз включать идентификатор типа объекта.

Райан Херр
источник
Привет Райан, я пытаюсь использовать CategorySetupFactoryдля создания экземпляра CategorySetupиз a Console\Command, однако, когда я звоню, $factory->setup()происходит фатальная ошибка: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
Ааа, теперь я наткнулся на этот поток, в котором вы заявляете, что это перестало работать в Magento 2.1 (который я использую). Сейчас я пересматриваю мой код, но, вероятно, лучше всего также добавить примечание к этому ответу ...
quickshiftin
0

Magento 2 добавить параметр Определенный атрибут Значение программно.

Запустите этот скрипт в корневом каталоге magento после 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();
    }
Бахаруни Асиф
источник