bagaimana cara menyimpan bidang kustom di tabel database kustom saat mengedit produk dari back-end?

11

Saya telah membuat modul khusus untuk menampilkan tab khusus pada formulir produk di back-end. Saya menggunakan solusi ini .

Sekarang pada tab saya menambahkan bidang khusus untuk disimpan dalam tabel basis data khusus. mengatakan<input type="text" name="my_new_field" value="123">

Juga dibuat pengontrol khusus untuk penyimpanan produk admin seperti di bawah ini.

Di etc / 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>

Dan di Kontroler / Adminhtml / Tulis Ulang / Produk / 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();
        }
    }

Sekarang dalam executefungsi saya mengharapkan nilai POST dari my_new_field. Tapi saya tidak mengerti. Setelah mendapatkan itu saya akan menggunakan permintaan khusus untuk menyimpan data di tabel khusus.

Apa yang saya lakukan salah atau haruskah saya menggunakan metode lain?

Pembaruan: 26 Agustus

Saya telah menggunakan formulir Ajax untuk menyimpan data dari tab produk karena saya punya batasan waktu. Saya telah menerima jawaban @ william-oakley. Sekarang @mageworx menambahkan dalam jawabannya bahwa ini bukan cara standar untuk melakukan ini.

Saya ingin menggunakan bentuk standar penggunaan UI dalam pengembangan lebih lanjut. Jadi pertanyaan saya adalah bagaimana cara menambahkan tab kustom ke produk edit menggunakan standar bentuk UI dan menyimpan bidang kustom di tabel kustom atau dengan cara lain.

HungryDB
sumber
1
Hai, Anda bisa menggunakan file CatalogProductSaveBefore.php di Observer untuk custom save feild ini.
Payal Patel

Jawaban:

14

Anda bisa menggunakan bidang input "telanjang", Anda hanya perlu menambahkan atribut berikut:

data-form-part="product_form"

begitu:

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

Anda kemudian akan bisa mendapatkan data POST untuk input Anda.

William Oakley
sumber
7

Solusi di atas tidak sepenuhnya benar. Anda menambahkan bidang sebagai elemen html "telanjang" dan formulir produk adalah formulir UI dengan kekhasannya sendiri. Kelas khusus ( vendor/magento/module-ui/view/base/web/js/form/form.js) bertanggung jawab untuk pengumpulan bidang dan validasinya ketika suatu formulir dikirimkan. Juga, kelas ini harus melewatkan bidang yang tidak terkait dengan formulir UI ini atau tidak additional fieldsseperti semua bidang Anda. Anda harus menggunakan penamaan berikut untuk memastikan bahwa bidang Anda akan dikirim ke controller:

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

Tetapi ini tidak sepenuhnya benar karena solusi yang tepat adalah tidak menyimpang dari standar penggunaan bentuk UI dan memanfaatkan elemen dan komponen asli. Dalam hal ini Anda tidak perlu khawatir tentang hal seperti itu karena semuanya akan diproses secara otomatis.

Anda dapat memeriksa metode utama penyimpanan data formulir UI untuk memahami proses:

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

Seperti yang Anda lihat dari kode ini, formulir html dengan semua bidangnya tidak terkirim. Namun, this.sourcedan this.additionalFieldssedang dikirim tetapi elemen Anda tidak termasuk di dalamnya karena dinyatakan salah.

PEMBARUAN DARI 08.23.2016

Berikut adalah contoh tentang cara menambahkan fieldset dari blog kami. Anda dapat membaca artikel selengkapnya, menggunakan tautan di bawah ini:

Sumber: Cara mudah untuk menambahkan fieldset dengan bidang ke formulir UI :

Tambahkan konten: meta-data UI-form dan tipe virtual untuk penambahannya.

Buat file app/code/Vendor/Product/etc/adminhtml/di.xml. Kami akan menempatkan pengubah di dalam:

<?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>

Sekarang, buat file pengubah ( app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php) dengan bidang kustom untuk halaman pengeditan produk dan isi dengan bidang:

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

pratinjau

Penghematan data terjadi di dalam file pengontrol produk vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php dalam metode eksekusi utama. Jika semuanya telah dilakukan dengan cara yang benar, maka data kami akan ditampilkan dengan benar dalam data input dari metode ini:

pratinjau

Catatan, jika produk Anda tidak memiliki atribut itu sejak awal, Anda harus menyimpannya secara manual. Anda dapat melakukan ini di pengamat.

Pertama, nyatakan dalam app/code/Vendor/Product/etc/adminhtml/events.xmlfile (kami menggunakan lingkup adminhtml karena formulir tidak ada di front-end):

<?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>

Lalu, buat kelas pengamat yang kami tunjuk dalam atribut instance - 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
    }
}

Data dalam pengamat:

pratinjau

Sekarang, Anda dapat memanggil model Anda sendiri dari pengamat dan menyimpan data di dalamnya atau memodifikasinya sesuai keinginan.

Hati-hati! Jika penghematan model Anda terhubung dengan penghematan produk, maka hal itu dapat menyebabkan rekursi.

MageWorx
sumber
dapatkah Anda menyarankan bagaimana cara menambahkan bidang formulir UI?
HungryDB
1
@HungryDB kami telah memperbarui jawaban di atas dan menambahkan tautan ke artikel dari blog kami. Anda dapat membaca cara membuat fieldset di sana.
MageWorx
3
Terima kasih atas jawaban @mageworx. Saya memutuskan untuk menggunakan metode formulir ajax untuk menyimpan data karena saya punya batasan waktu. Saya pasti akan mencoba metode Anda ketika saya punya waktu.
HungryDB
jadi bagaimana cara menyimpan data ini ke database?
Chi
Terima kasih atas jawabannya. Metode ini berfungsi. Saya telah menambahkan bidang pilih khusus dan nilai disimpan ke meja saya menggunakan pengamat. Tetapi saat mengedit produk yang sama, nilai saya tidak ditampilkan sebagai dipilih. Tolong bantu .
Vindhuja
2

Untuk menyimpan bidang produk dalam tabel khusus, Anda dapat mengikuti logika harga tier. Magento akan menghemat harga lapis dengan bantuan model kustom backend dari harga lapis. Kami dapat mengikuti logika yang sama untuk bidang / attibute khusus kami. Untuk menyimpan attibute di tabel kustom Anda harus membuat atribut kustom dan menyediakannya model backend. Model Backend akan memvaldiate dan menyimpan dan mengambil kembali attibute. Anda dapat mengikuti langkah-langkah di bawah ini.

Langkah 1. Buat atribut produk

<?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' => ''
            ]
        );
    }
}

Langkah 2. Buat model backend untuk atribut khusus produk yang akan membantu untuk validasi dan menyimpan dan mengambil nilai atribut

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

}

Langkah 2. Model sumber daya untuk menyimpan dan mengambil nilai atribut dari tabel khusus

<?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;
    }
}
Ajay
sumber