як зберегти спеціальне поле у ​​спеціальній таблиці баз даних під час редагування продукту з бек-енду?


11

Я створив спеціальний модуль для відображення спеціальної вкладки у формі продукту в бек-енді. Я використовував це рішення.

Тепер на вкладці я додаю спеціальні поля для збереження у спеціальній таблиці баз даних. казати<input type="text" name="my_new_field" value="123">

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

В тощо / di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Controller\Adminhtml\Product\Save" type="Namespace\Module\Controller\Adminhtml\Rewrite\Product\Save" />
</config>

І в Controller / Adminhtml / Rewrite / Product / Save.php

<?php

    namespace Namespace\Module\Controller\Adminhtml\Rewrite\Product;

    class Save extends \Magento\Catalog\Controller\Adminhtml\Product\save
    {

        public function execute()
        {
            echo "hello"; print_r($_POST); die;

            return parent::execute();
        }
    }

Тепер у executeфункції я очікую значення POST my_new_field. Але я не отримую цього. Після цього я скористаюся спеціальними запитами для збереження даних у спеціальній таблиці.

Що я роблю неправильно чи потрібно використовувати якийсь інший метод?

Оновлення: 26 серп.

Я використовував форму Ajax для збереження даних із вкладки продукту, оскільки у мене були обмеження в часі. Я прийняв відповідь @ william-oakley. Тепер, як @mageworx додав у своїй відповіді, що це не стандартний спосіб зробити це.

Я хочу використовувати стандартне використання форми інтерфейсу користувача у подальшому розвитку. Отже, моє запитання полягає в тому, як додати спеціальну вкладку до редагування продукту за допомогою стандартної форми інтерфейсу та зберегти власні поля у спеціальній таблиці чи іншим способом.


1
Гей, ви можете використовувати файл CataProductSaveBefore.php в Observer для цього спеціального файлу збереження.
Payal Patel

Відповіді:


14

Ви можете просто скористатися "голим" полем для введення, вам просто потрібно додати такий атрибут:

data-form-part="product_form"

так:

<input data-form-part="product_form" type="text" name="my_new_field" value="123">

Тоді ви зможете отримати дані POST для вашого введення.


7

Наведене вище рішення не є повністю правильним. Ви додаєте поле як "голий" html-елемент, а форма продукту - це форма інтерфейсу користувача зі своїми особливостями. Спеціальний клас ( vendor/magento/module-ui/view/base/web/js/form/form.js) відповідає за збір полів та їх валідацію при надсиланні форми. Крім того, цей клас повинен пропускати поля, які не пов'язані з цією формою інтерфейсу або не так, additional fieldsяк усі ваші поля. Ви повинні використовувати наступні імена для того, щоб переконатися, що ваше поле буде надіслане контролеру:

input type="text" name="product[my_new_field]" value="123"

Але це не зовсім коректно, тому що правильне рішення - не відступати від стандартів використання форми користувальницького інтерфейсу та використовувати його рідні елементи та компоненти. У цьому випадку ви не повинні турбуватися про таке, тому що все буде оброблено автоматично.

Ви можете перевірити основний спосіб зберігання даних форм інтерфейсу користувача, щоб зрозуміти процес:

/**
 * Submits form
 *
 * @param {String} redirect
 */
submit: function (redirect) {
    var additional = collectData(this.additionalFields),
        source = this.source;

    _.each(additional, function (value, name) {
        source.set('data.' + name, value);
    });

    source.save({
        redirect: redirect,
        ajaxSave: this.ajaxSave,
        ajaxSaveType: this.ajaxSaveType,
        response: {
            data: this.responseData,
            status: this.responseStatus
        },
        attributes: {
            id: this.namespace
        }
    });
},

Як видно з цього коду, форма HTML з усіма її полями не надсилається. Однак this.sourceі this.additionalFieldsпересилаються, але ваш елемент не включений до нього, оскільки він оголошений неправильно.

ОНОВЛЕННЯ З 23.08.2016

Ось приклад того, як додати польовий набір із нашого блогу. Ви можете прочитати повну статтю за посиланням нижче:

Джерело: Простий спосіб додати набір полів із полями до UI-форми :

Додайте вміст: метадані у формі UI та віртуальний тип для їх додавання.

Створіть файл app/code/Vendor/Product/etc/adminhtml/di.xml. Ми розмістимо модифікатор всередині:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="custom-fieldset" xsi:type="array">
                    <item name="class" xsi:type="string">Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>

Тепер створіть файл модифікатора ( app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php) зі спеціальним набором полів для сторінки редагування продукту та заповніть його полями:

<?php
namespace Vendor\Product\Ui\DataProvider\Product\Form\Modifier;

use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Framework\Stdlib\ArrayManager;
use Magento\Framework\UrlInterface;
use Magento\Ui\Component\Container;
use Magento\Ui\Component\Form\Fieldset;
use Magento\Ui\Component\Form\Element\DataType\Number;
use Magento\Ui\Component\Form\Element\DataType\Text;
use Magento\Ui\Component\Form\Element\Input;
use Magento\Ui\Component\Form\Element\Select;
use Magento\Ui\Component\Form\Element\MultiSelect;
use Magento\Ui\Component\Form\Field;

class CustomFieldset extends AbstractModifier
{

    // Components indexes
    const CUSTOM_FIELDSET_INDEX = 'custom_fieldset';
    const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
    const CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';

    // Fields names
    const FIELD_NAME_TEXT = 'example_text_field';
    const FIELD_NAME_SELECT = 'example_select_field';
    const FIELD_NAME_MULTISELECT = 'example_multiselect_field';

    /**
     * @var \Magento\Catalog\Model\Locator\LocatorInterface
     */
    protected $locator;

    /**
     * @var ArrayManager
     */
    protected $arrayManager;

    /**
     * @var UrlInterface
     */
    protected $urlBuilder;

    /**
     * @var array
     */
    protected $meta = [];

    /**
     * @param LocatorInterface $locator
     * @param ArrayManager $arrayManager
     * @param UrlInterface $urlBuilder
     */
    public function __construct(
        LocatorInterface $locator,
        ArrayManager $arrayManager,
        UrlInterface $urlBuilder
    ) {
        $this->locator = $locator;
        $this->arrayManager = $arrayManager;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * Data modifier, does nothing in our example.
     *
     * @param array $data
     * @return array
     */
    public function modifyData(array $data)
    {
        return $data;
    }

    /**
     * Meta-data modifier: adds ours fieldset
     *
     * @param array $meta
     * @return array
     */
    public function modifyMeta(array $meta)
    {
        $this->meta = $meta;
        $this->addCustomFieldset();

        return $this->meta;
    }

    /**
     * Merge existing meta-data with our meta-data (do not overwrite it!)
     *
     * @return void
     */
    protected function addCustomFieldset()
    {
        $this->meta = array_merge_recursive(
            $this->meta,
            [
                static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
            ]
        );
    }

    /**
     * Declare ours fieldset config
     *
     * @return array
     */
    protected function getFieldsetConfig()
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'label' => __('Fieldset Title'),
                        'componentType' => Fieldset::NAME,
                        'dataScope' => static::DATA_SCOPE_PRODUCT, // save data in the product data
                        'provider' => static::DATA_SCOPE_PRODUCT . '_data_source',
                        'ns' => static::FORM_NAME,
                        'collapsible' => true,
                        'sortOrder' => 10,
                        'opened' => true,
                    ],
                ],
            ],
            'children' => [
                static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
                static::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
                static::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
                static::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
            ],
        ];
    }

    /**
     * Get config for header container
     *
     * @param int $sortOrder
     * @return array
     */
    protected function getHeaderContainerConfig($sortOrder)
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'label' => null,
                        'formElement' => Container::NAME,
                        'componentType' => Container::NAME,
                        'template' => 'ui/form/components/complex',
                        'sortOrder' => $sortOrder,
                        'content' => __('You can write any text here'),
                    ],
                ],
            ],
            'children' => [],
        ];
    }

    /**
     * Example text field config
     *
     * @param $sortOrder
     * @return array
     */
    protected function getTextFieldConfig($sortOrder)
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'label' => __('Example Text Field'),
                        'formElement' => Field::NAME,
                        'componentType' => Input::NAME,
                        'dataScope' => static::FIELD_NAME_TEXT,
                        'dataType' => Number::NAME,
                        'sortOrder' => $sortOrder,
                    ],
                ],
            ],
        ];
    }

    /**
     * Example select field config
     *
     * @param $sortOrder
     * @return array
     */
    protected function getSelectFieldConfig($sortOrder)
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'label' => __('Options Select'),
                        'componentType' => Field::NAME,
                        'formElement' => Select::NAME,
                        'dataScope' => static::FIELD_NAME_SELECT,
                        'dataType' => Text::NAME,
                        'sortOrder' => $sortOrder,
                        'options' => $this->_getOptions(),
                        'visible' => true,
                        'disabled' => false,
                    ],
                ],
            ],
        ];
    }

    /**
     * Example multi-select field config
     *
     * @param $sortOrder
     * @return array
     */
    protected function getMultiSelectFieldConfig($sortOrder)
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'label' => __('Options Multiselect'),
                        'componentType' => Field::NAME,
                        'formElement' => MultiSelect::NAME,
                        'dataScope' => static::FIELD_NAME_MULTISELECT,
                        'dataType' => Text::NAME,
                        'sortOrder' => $sortOrder,
                        'options' => $this->_getOptions(),
                        'visible' => true,
                        'disabled' => false,
                    ],
                ],
            ],
        ];
    }

    /**
     * Get example options as an option array:
     *      [
     *          label => string,
     *          value => option_id
     *      ]
     *
     * @return array
     */
    protected function _getOptions()
    {
        $options = [
            1 => [
                'label' => __('Option 1'),
                'value' => 1
            ],
            2 => [
                'label' => __('Option 2'),
                'value' => 2
            ],
            3 => [
                'label' => __('Option 3'),
                'value' => 3
            ],
        ];

        return $options;
    }
}

попередній перегляд

Збереження даних відбувається всередині файлу контролера продукту vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php в основному методі виконання. Якщо все зроблено правильно, наші дані будуть відображатися правильно у вхідних даних цього методу:

попередній перегляд

Зауважте, якщо ваш продукт не має цих атрибутів з самого початку, їх слід зберегти вручну. Це можна зробити у спостерігача.

По-перше, app/code/Vendor/Product/etc/adminhtml/events.xmlзаявіть про це у файлі (ми використовуємо область adminhtml, оскільки форма не існує на передній частині):

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_save_after">
        <observer name="save_example_data" instance="Vendor\Product\Observer\ProductSaveAfter" />
    </event>
</config>

Потім створіть клас спостерігача, який ми вказали в атрибуті екземпляр - app/code/Vendor/Product/Observer/ProductSaveAfter.php:

<?php
namespace Vendor\Product\Observer;

use \Magento\Framework\Event\ObserverInterface;
use \Magento\Framework\Event\Observer as EventObserver;
use Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset;

class ProductSaveAfter implements ObserverInterface
{

    /**
     * @param EventObserver $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        /** @var \Magento\Catalog\Model\Product $product */
        $product = $observer->getEvent()->getProduct();
        if (!$product) {
            return;
        }

        $exampleTextField = $product->getData(CustomFieldset::FIELD_NAME_TEXT);
        $exampleSelectField = $product->getData(CustomFieldset::FIELD_NAME_SELECT);
        $exampleMultiSelectField = $product->getData(CustomFieldset::FIELD_NAME_MULTISELECT);

        // Manipulate data here
    }
}

Дані спостерігача:

попередній перегляд

Тепер ви можете зателефонувати власній моделі від спостерігача і зберегти в ній дані або змінити їх за своїм бажанням.

Будь обережний! Якщо збереження вашої моделі пов'язане із збереженням продукту, то це може призвести до рекурсії.


Ви можете запропонувати, як я можу додати поля форми інтерфейсу?
HungryDB

1
@HungryDB ми оновили відповідь вище та додали посилання на статтю з нашого блогу. Ви можете прочитати, як створити набір полів там.
MageWorx

3
Дякуємо за відповідь @mageworx. Я вирішив використовувати метод форми ajax для збереження даних, хоча у мене є обмеження у часі. Я обов'язково спробую ваш метод, коли я знайду час.
HungryDB

тож як я можу зберегти ці дані в базі даних?
Чи

Дякую за відповідь. Цей метод працює. Я додав поле для вибору, і значення зберігається в моїй таблиці за допомогою спостерігача. Але під час редагування того ж продукту мої значення не відображаються як вибрані. Будь ласка, допоможіть .
Vindhuja

2

Щоб зберегти поле продукту у спеціальній таблиці, ви можете слідувати логіці рівня рівня. Magento збереже ціну рівня за допомогою допоміжної спеціальної моделі цінового рівня. Ми можемо керуватися такою ж логікою для нашого користувальницького поля / аттибуту. Для збереження attibute у користувальницькій таблиці вам потрібно створити спеціальний атрибут та надати його допоміжну модель. Модель бекенда буде оцінювати та зберігати та витягувати аттибут. Ви можете виконати наведені нижче кроки.

Крок 1. Створіть атрибут продукту

<?php 
namespace Magentoins\TestAttribute\Setup; 
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;


class InstallData implements InstallDataInterface

{    
    private $eavSetupFactory; 
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

        /**
         * Add attributes to the eav/attribute
         */

        $eavSetup->addAttribute(
            \Magento\Catalog\Model\Product::ENTITY,
            'test_attribute',
            [
                'type' => 'int',
                'backend' => 'Magentoins\TestAttribute\Model\Product\Attribute\Backend\TestAttribute',
                'frontend' => '',
                'label' => 'Test Attribute',
                'input' => '',
                'class' => '',
                'source' => '',
                'global' => \Magento\Catalog\Model\Resource\Eav\Attribute::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => false,
                'default' => 0,
                'searchable' => false,
                'filterable' => false,
                'comparable' => false,
                'visible_on_front' => false,
                'used_in_product_listing' => true,
                'unique' => false,
                'apply_to' => ''
            ]
        );
    }
}

Крок 2. Створіть модель допоміжного продукту для спеціального атрибута продукту, який допоможе перевірити, зберегти та отримати значення атрибута

<?php
namespace Magentoins\TestAttribute\Model\Product\Attribute\Backend;

class TestAttribute extends \Magento\Catalog\Model\Product\Attribute\Backend\Tierprice
{
  protected $_productAttributeBackendTestAttribute;
  /**
   * Website currency codes and rates
   *
   * @var array
   */
  protected $_rates;

  protected $_helper;

  protected $eavConfig;

  public function __construct(
      \Magento\Directory\Model\CurrencyFactory $currencyFactory,
      \Magento\Store\Model\StoreManagerInterface $storeManager,
      \Magento\Catalog\Helper\Data $catalogData,
      \Magento\Framework\App\Config\ScopeConfigInterface $config,
      \Magento\Framework\Locale\FormatInterface $localeFormat,
      \Magento\Catalog\Model\Product\Type $catalogProductType,
      \Magento\Customer\Api\GroupManagementInterface $groupManagement,
      \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice $productAttributeTierprice,
      \Magentoins\TestAttribute\Model\ResourceModel\Product\Attribute\Backend\TestAttribute $productAttributeBackendFixedprices,
      \Magentoins\TestAttribute\Helper\Data $helperData,
      \Magento\Eav\Model\Config $eavConfig
  ) {
    parent::__construct(
        $currencyFactory,
        $storeManager,
        $catalogData,
        $config,
        $localeFormat,
        $catalogProductType,
        $groupManagement,
        $productAttributeTierprice
    );
    $this->_productAttributeBackendTestAttribute = $productAttributeBackendTestAttribute;    

  }

  /**
   * Retrieve resource instance
   *
   */
  protected function _getResource()
  {
    return $this->_productAttributeBackendTestAttribute;
  }

  public function getAttribute()
  {
    $attribute = $this->eavConfig->getAttribute('catalog_product', 'test_attribute');
    return $attribute;
  }
  /**
   * Validate test_attribute data
   *
   */
  public function validate ($object)
  {
    $attribute = $this->getAttribute();
    $attr = $object->getData($attribute->getName());
    if (empty($attr)) {
      return true;
    }    

    return true;
  }

  /**
   * Assign test_attribute to product data   
   */
  public function afterLoad ($object)
  {
    /*$data is from your custom table*/
    $data = $this->_getResource()->loadTestAttributeData($object->getId(), $websiteId);
    $object->setData($this->getAttribute()->getName(), $data);
    $object->setOrigData($this->getAttribute()->getName(), $data);

    $valueChangedKey = $this->getAttribute()->getName() . '_changed';
    $object->setOrigData($valueChangedKey, 0);
    $object->setData($valueChangedKey, 0);

    return $this;
  }

  /**
   * After Save Attribute manipulation 
   */
  public function afterSave ($object)
  {
    $websiteId = $this->_storeManager->getStore($object->getStoreId())->getWebsiteId();
    $isGlobal = $this->getAttribute()->isScopeGlobal() || $websiteId == 0;

    $testAttribute = $object->getData($this->getAttribute()->getName());

    /*Save attribute value in custom table with the help of resource model*/

    $this->_getResource()->saveTestAttributeData($testAttribute);

    return $this;
  }

  public function beforeSave ($object)
  {
    parent::beforeSave($object);        
  }

}

Крок 2. Модель ресурсу для збереження та отримання значення атрибутів із спеціальної таблиці

<?php
namespace Magentoins\TestAttribute\Model\ResourceModel\Product\Attribute\Backend;

use Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice;

/**
 * @author
 */
class TestAttribute extends Tierprice
{
    /**
     * Initialize connection and define main table
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('magentoins_product_entity_testAttribute', 'value_id');
    }

    /**
     * Load Fixed Prices for product
     *
     * @param int $productId
     * @return Designnbuy_Fixedprices_Model_Mysql4_fixedprices
     */
    public function loadTestAttributeData($productId, $websiteId = null)
    {
        $connection = $this->getConnection();
        $columns = array (
            'test_attribute' => $this->getIdFieldName()            
        );
        $select = $connection->select()
            ->from($this->getMainTable(), $columns)
            ->where('entity_id=?', $productId)
            ->order('order');

        if (!is_null($websiteId)) {
            if ($websiteId == '0') {
                $select->where('website_id=?', $websiteId);
            } else {
                $select->where('website_id IN(?)', array ('0', $websiteId
                ));
            }
        }

        return $connection->fetchAll($select);
    }

    public function saveTestAttributeData(\Magento\Framework\DataObject $attributeObject)
    {
        $connection = $this->getConnection();
        $data = $this->_prepareDataForTable($attributeObject, $this->getMainTable());

        if (!empty($data[$this->getIdFieldName()])) {
            $where = $connection->quoteInto($this->getIdFieldName() . ' = ?', $data[$this->getIdFieldName()]);
            unset($data[$this->getIdFieldName()]);
            $connection->update($this->getMainTable(), $data, $where);
        } else {
            $connection->insert($this->getMainTable(), $data);
        }
        return $this;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.