백엔드에서 제품을 편집하는 동안 사용자 정의 데이터베이스 테이블에 사용자 정의 필드를 저장하는 방법은 무엇입니까?


11

백엔드의 제품 양식에 사용자 정의 탭을 표시하는 사용자 정의 모듈을 작성했습니다. 솔루션을 사용 했습니다 .

이제 탭에서 사용자 정의 데이터베이스 테이블에 저장할 사용자 정의 필드를 추가하고 있습니다. 말하다<input type="text" name="my_new_field" value="123">

또한 아래와 같이 관리자 제품 저장을위한 사용자 정의 컨트롤러를 만들었습니다.

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>

그리고 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됩니다. 그러나 나는 그것을 얻지 못한다. 그것을 얻은 후에 사용자 정의 쿼리를 사용하여 사용자 정의 테이블에 데이터를 저장합니다.

내가 뭘 잘못하고 있거나 다른 방법을 사용해야합니까?

업데이트 : 8 월 26 일

시간 제한이 있으므로 제품 탭에서 데이터를 저장하기 위해 Ajax 양식을 사용했습니다. @ william-oakley의 답변을 수락했습니다. 이제 @mageworx가 자신의 답변에 이것이 표준 방법이 아니라고 덧붙였습니다.

추가 개발에서 UI 양식 표준 사용법을 사용하고 싶습니다. 그래서 제 질문은 UI 양식 표준을 사용하여 제품 편집에 사용자 정의 탭을 추가하고 사용자 정의 테이블을 다른 방법으로 사용자 정의 테이블에 저장하는 방법입니다.


1
이 사용자 정의 저장 파일에 Observer에서 CatalogProductSaveBefore.php 파일을 사용할 수 있습니다.
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 요소로 추가하고 제품 양식은 고유 한 특성을 가진 UI 양식입니다. 특수 클래스 ( vendor/magento/module-ui/view/base/web/js/form/form.js)는 양식을 보낼 때 필드 수집 및 유효성 검사를 담당합니다. 또한이 클래스는이 UI 양식과 관련이 없거나 additional fields모든 필드와 같지 않은 필드를 놓쳐 야 합니다. 필드가 컨트롤러로 전송되도록하려면 다음 이름을 사용해야합니다.

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

그러나 올바른 솔루션이 UI 양식 사용 표준에서 벗어나고 기본 요소 및 구성 요소를 활용하지 않기 때문에 이는 완전히 올바르지 않습니다. 이 경우 모든 것이 자동으로 처리되므로 이러한 문제에 대해 걱정할 필요가 없습니다.

프로세스를 이해하기 위해 UI 양식 데이터를 저장하는 기본 방법을 확인할 수 있습니다.

/**
 * 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.sourcethis.additionalFields전송되지만를 잘못 선언 때문에 요소는 그 안에 포함되어 있지 않습니다.

08.23.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
    }
}

관찰자의 데이터 :

시사

이제 옵저버에서 자신의 모델을 호출하고 데이터를 저장하거나 원하는대로 수정할 수 있습니다.

조심해! 모델 저장이 제품 저장과 연결되면 재귀로 이어질 수 있습니다.


UI 양식 필드를 추가하는 방법을 제안 할 수 있습니까?
HungryDB

1
@HungryDB 우리는 위의 답변을 업데이트하고 블로그의 기사에 대한 링크를 추가했습니다. 거기에서 fieldset을 만드는 방법을 읽을 수 있습니다.
MageWorx

3
답변 @ mageworx에 감사드립니다. 시간 제한이 있지만 데이터를 저장하기 위해 ajax 양식 방법을 사용하기로 결정했습니다. 나는 시간이되면 분명히 당신의 방법을 시도합니다.
HungryDB

이 데이터를 데이터베이스에 어떻게 저장합니까?
Chi

답변 해주셔서 감사합니다. 이 방법은 효과가 있습니다. 사용자 정의 선택 필드를 추가했으며 옵저버를 사용하여 값을 테이블에 저장했지만 동일한 제품을 편집 할 때 선택한 값이 표시되지 않습니다. 도와주세요 .
Vindhuja

2

사용자 정의 테이블에 제품 필드를 저장하기 위해 계층 가격의 논리를 따를 수 있습니다. Magento는 백엔드 맞춤형 티어 가격 모델을 통해 티어 가격을 절약 할 수 있습니다. 우리는 커스텀 필드 / 첨단에 동일한 논리를 따를 수 있습니다. 사용자 정의 테이블에 속성을 저장하려면 사용자 정의 속성을 작성하고 백엔드 모델을 제공해야합니다. 백엔드 모델은 속성을 확인하고 저장하고 검색합니다. 아래 단계를 수행 할 수 있습니다.

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;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.