回答:
条件付きフィールドをデフォルトのモデルに追加するには(さらに検証の目的で使用するには)、これらのフィールドを含む新しいモデルを作成する(または既存のモデルを変更する)必要があります。
app / code / Vendor / Rules / Setup / InstallSchema.php
<?php
namespace Vendor\Rules\Setup;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
class InstallSchema implements InstallSchemaInterface
{
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$installer->startSetup();
$table = $installer->getConnection()->newTable(
$installer->getTable('vendor_rules')
)->addColumn(
'rule_id',
Table::TYPE_INTEGER,
null,
['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true],
'Rule Id'
)->addColumn(
'name',
Table::TYPE_TEXT,
255,
[],
'Name'
)->addColumn(
'description',
Table::TYPE_TEXT,
'64k',
[],
'Description'
)->addColumn(
'from_date',
Table::TYPE_DATE,
null,
['nullable' => true, 'default' => null],
'From'
)->addColumn(
'to_date',
Table::TYPE_DATE,
null,
['nullable' => true, 'default' => null],
'To'
)->addColumn(
'is_active',
Table::TYPE_SMALLINT,
null,
['nullable' => false, 'default' => '0'],
'Is Active'
)->addColumn(
'conditions_serialized',
Table::TYPE_TEXT,
'2M',
[],
'Conditions Serialized'
)->addColumn(
'sort_order',
Table::TYPE_INTEGER,
null,
['unsigned' => true, 'nullable' => false, 'default' => '0'],
'Sort Order (Priority)'
)->addIndex(
$installer->getIdxName('vendor_rules', ['sort_order', 'is_active', 'to_date', 'from_date']),
['sort_order', 'is_active', 'to_date', 'from_date']
)->setComment(
'Own Rules'
);
$installer->getConnection()->createTable($table);
$installer->endSetup();
}
}
これで、モデルの説明を含むテーブルができました。モデル自体を完成させ、適切なリソースモデルとコレクションを含める必要があります。
モデルは「ルール」と呼ばれます:
app / code / Vendor / Rules / Model / Rule.php
<?php
namespace Vendor\Rules\Model;
use Magento\Quote\Model\Quote\Address;
use Magento\Rule\Model\AbstractModel;
/**
* Class Rule
* @package Vendor\Rules\Model
*
* @method int|null getRuleId()
* @method Rule setRuleId(int $id)
*/
class Rule extends AbstractModel
{
/**
* Prefix of model events names
*
* @var string
*/
protected $_eventPrefix = 'vendor_rules';
/**
* Parameter name in event
*
* In observe method you can use $observer->getEvent()->getRule() in this case
*
* @var string
*/
protected $_eventObject = 'rule';
/** @var \Magento\SalesRule\Model\Rule\Condition\CombineFactory */
protected $condCombineFactory;
/** @var \Magento\SalesRule\Model\Rule\Condition\Product\CombineFactory */
protected $condProdCombineF;
/**
* Store already validated addresses and validation results
*
* @var array
*/
protected $validatedAddresses = [];
/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Data\FormFactory $formFactory
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
* @param \Magento\SalesRule\Model\Rule\Condition\CombineFactory $condCombineFactory
* @param \Magento\SalesRule\Model\Rule\Condition\Product\CombineFactory $condProdCombineF
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
\Magento\SalesRule\Model\Rule\Condition\CombineFactory $condCombineFactory,
\Magento\SalesRule\Model\Rule\Condition\Product\CombineFactory $condProdCombineF,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
) {
$this->condCombineFactory = $condCombineFactory;
$this->condProdCombineF = $condProdCombineF;
parent::__construct($context, $registry, $formFactory, $localeDate, $resource, $resourceCollection, $data);
}
/**
* Set resource model and Id field name
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->_init('Vendor\Rules\Model\ResourceModel\Rule');
$this->setIdFieldName('rule_id');
}
/**
* Get rule condition combine model instance
*
* @return \Magento\SalesRule\Model\Rule\Condition\Combine
*/
public function getConditionsInstance()
{
return $this->condCombineFactory->create();
}
/**
* Get rule condition product combine model instance
*
* @return \Magento\SalesRule\Model\Rule\Condition\Product\Combine
*/
public function getActionsInstance()
{
return $this->condProdCombineF->create();
}
/**
* Check cached validation result for specific address
*
* @param Address $address
* @return bool
*/
public function hasIsValidForAddress($address)
{
$addressId = $this->_getAddressId($address);
return isset($this->validatedAddresses[$addressId]) ? true : false;
}
/**
* Set validation result for specific address to results cache
*
* @param Address $address
* @param bool $validationResult
* @return $this
*/
public function setIsValidForAddress($address, $validationResult)
{
$addressId = $this->_getAddressId($address);
$this->validatedAddresses[$addressId] = $validationResult;
return $this;
}
/**
* Get cached validation result for specific address
*
* @param Address $address
* @return bool
* @SuppressWarnings(PHPMD.BooleanGetMethodName)
*/
public function getIsValidForAddress($address)
{
$addressId = $this->_getAddressId($address);
return isset($this->validatedAddresses[$addressId]) ? $this->validatedAddresses[$addressId] : false;
}
/**
* Return id for address
*
* @param Address $address
* @return string
*/
private function _getAddressId($address)
{
if ($address instanceof Address) {
return $address->getId();
}
return $address;
}
}
ご覧のとおり、このモデルMagento\Rule\Model\AbstractModel
は、必要なすべてのメソッドがすでに含まれているモデルを継承しています。
コンストラクタに直接、条件ファクトリを追加して、それらを操作して複数のメソッドを作成できるようにします。これにより、モデルがどのように機能するかを理解できます。
Magento SalesRule(\Magento\SalesRule\Model\Rule\Condition
)モジュールのデフォルトの条件モデルを使用していることに注意してください。条件を拡張する必要がある場合は、独自のクラスを追加したり、完全に書き直したり、使用可能な基本クラスから継承したりできます。デフォルトの条件に含まれていない特別な条件を追加する場合に便利です。たとえば、「割引のある小計」などです。
....
次に、管理パネルのインターフェースに切り替えましょう。一連のアクション(保存、追加、編集、グリッド表示、条件の再読み込みなど)を備えたコントローラーと、ブロックを備えたレイアウトが必要です。
コントローラー自体から始めましょう。まず、共通のコントローラーを宣言します。
app / code / Vendor / Rules / Controller / Adminhtml / Example / Rule.php
<?php
namespace Vendor\Rules\Controller\Adminhtml\Example;
abstract class Rule extends \Magento\Backend\App\Action
{
/**
* Core registry
*
* @var \Magento\Framework\Registry
*/
protected $coreRegistry = null;
/**
* @var \Magento\Framework\App\Response\Http\FileFactory
*/
protected $fileFactory;
/**
* @var \Magento\Framework\Stdlib\DateTime\Filter\Date
*/
protected $dateFilter;
/**
* @var \Vendor\Rules\Model\RuleFactory
*/
protected $ruleFactory;
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Framework\Registry $coreRegistry
* @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory
* @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter
* @param \Vendor\Rules\Model\RuleFactory $ruleFactory
* @param \Psr\Log\LoggerInterface $logger
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\Registry $coreRegistry,
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
\Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter,
\Vendor\Rules\Model\RuleFactory $ruleFactory,
\Psr\Log\LoggerInterface $logger
) {
parent::__construct($context);
$this->coreRegistry = $coreRegistry;
$this->fileFactory = $fileFactory;
$this->dateFilter = $dateFilter;
$this->ruleFactory = $ruleFactory;
$this->logger = $logger;
}
/**
* Initiate rule
*
* @return void
*/
protected function _initRule()
{
$rule = $this->ruleFactory->create();
$this->coreRegistry->register(
'current_rule',
$rule
);
$id = (int)$this->getRequest()->getParam('id');
if (!$id && $this->getRequest()->getParam('rule_id')) {
$id = (int)$this->getRequest()->getParam('rule_id');
}
if ($id) {
$this->coreRegistry->registry('current_rule')->load($id);
}
}
/**
* Initiate action
*
* @return Rule
*/
protected function _initAction()
{
$this->_view->loadLayout();
$this->_setActiveMenu('Vendor_Rules::vendor_rules')
->_addBreadcrumb(__('Example Rules'), __('Example Rules'));
return $this;
}
/**
* Returns result of current user permission check on resource and privilege
*
* @return bool
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed('Vendor_Rules::rules');
}
}
ここでは、コンストラクターでモデルのファクトリーを呼び出す必要があります。これは、それら(およびレジスターやロガーなどのいくつかの補助クラス)を公開するために行われます。
この_initRule
メソッドは、現在のルールの初期化または新しい空のルールの作成を担当し、それをレジスタに追加する機能を備えています。この_initAction()
メソッドはレイアウトをロードし、モジュールのメニューをアクションで使用できるようにします(また、パンくずを追加します)。この_isAllowed()
メソッドは、現在の管理者がコントローラーにアクセスできるかどうかを確認します。
次のステップでは、デフォルトのアクションを追加します。
....
編集:
app / code / Vendor / Rules / Controller / Adminhtml / Example / Rule / Edit.php
<?php
namespace Vendor\Rules\Controller\Adminhtml\Example\Rule;
class Edit extends \Vendor\Rules\Controller\Adminhtml\Example\Rule
{
/**
* Rule edit action
*
* @return void
*/
public function execute()
{
$id = $this->getRequest()->getParam('id');
/** @var \Vendor\Rules\Model\Rule $model */
$model = $this->ruleFactory->create();
if ($id) {
$model->load($id);
if (!$model->getRuleId()) {
$this->messageManager->addErrorMessage(__('This rule no longer exists.'));
$this->_redirect('vendor_rules/*');
return;
}
}
// set entered data if was error when we do save
$data = $this->_session->getPageData(true);
if (!empty($data)) {
$model->addData($data);
}
$model->getConditions()->setJsFormObject('rule_conditions_fieldset');
$this->coreRegistry->register('current_rule', $model);
$this->_initAction();
$this->_view->getLayout()
->getBlock('example_rule_edit')
->setData('action', $this->getUrl('vendor_rules/*/save'));
$this->_addBreadcrumb($id ? __('Edit Rule') : __('New Rule'), $id ? __('Edit Rule') : __('New Rule'));
$this->_view->getPage()->getConfig()->getTitle()->prepend(
$model->getRuleId() ? $model->getName() : __('New Rule')
);
$this->_view->renderLayout();
}
}
これは、新しい条件を追加する方法です。
app / code / Vendor / Rules / Controller / Adminhtml / Example / Rule / NewConditionHtml.php
<?php
namespace Vendor\Rules\Controller\Adminhtml\Example\Rule;
class NewConditionHtml extends \Vendor\Rules\Controller\Adminhtml\Example\Rule
{
/**
* New condition html action
*
* @return void
*/
public function execute()
{
$id = $this->getRequest()->getParam('id');
$typeArr = explode('|', str_replace('-', '/', $this->getRequest()->getParam('type')));
$type = $typeArr[0];
$model = $this->_objectManager->create(
$type
)->setId(
$id
)->setType(
$type
)->setRule(
$this->ruleFactory->create()
)->setPrefix(
'conditions'
);
if (!empty($typeArr[1])) {
$model->setAttribute($typeArr[1]);
}
if ($model instanceof \Magento\Rule\Model\Condition\AbstractCondition) {
$model->setJsFormObject($this->getRequest()->getParam('form'));
$html = $model->asHtmlRecursive();
} else {
$html = '';
}
$this->getResponse()->setBody($html);
}
}
このクラスは、インターフェースで選択された条件のロードを担当します(すべての条件を一度にロードすることはできません)。
....
次に、必要なすべてのブロックとレイアウトを作成する必要があります。
それでは、新しいルールの作成と編集に取り掛かりましょう。編集用のメインコンテナーブロックを作成します。
app / code / Vendor / Rules / Block / Adminhtml / Example / Rule / Edit.php
<?php
namespace Vendor\Rules\Block\Adminhtml\Example\Rule;
class Edit extends \Magento\Backend\Block\Widget\Form\Container
{
/**
* Core registry
*
* @var \Magento\Framework\Registry
*/
protected $coreRegistry = null;
/**
* @param \Magento\Backend\Block\Widget\Context $context
* @param \Magento\Framework\Registry $registry
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Widget\Context $context,
\Magento\Framework\Registry $registry,
array $data = []
) {
$this->coreRegistry = $registry;
parent::__construct($context, $data);
}
/**
* Initialize form
* Add standard buttons
* Add "Save and Continue" button
*
* @return void
*/
protected function _construct()
{
$this->_objectId = 'id';
$this->_controller = 'adminhtml_example_rule';
$this->_blockGroup = 'Vendor_Rules';
parent::_construct();
$this->buttonList->add(
'save_and_continue_edit',
[
'class' => 'save',
'label' => __('Save and Continue Edit'),
'data_attribute' => [
'mage-init' => ['button' => ['event' => 'saveAndContinueEdit', 'target' => '#edit_form']],
]
],
10
);
}
/**
* Getter for form header text
*
* @return \Magento\Framework\Phrase
*/
public function getHeaderText()
{
$rule = $this->coreRegistry->registry('current_rule');
if ($rule->getRuleId()) {
return __("Edit Rule '%1'", $this->escapeHtml($rule->getName()));
} else {
return __('New Rule');
}
}
}
完了したら、コントローラのタイトルsave
とedit current model
ボタンをコンストラクタに追加する必要があります。また、ここにブロックのメインテキストを追加する必要があります。
これはフォームそのものです:
app / code / Vendor / Rules / Block / Adminhtml / Example / Rule / Edit / Form.php
<?php
namespace Vendor\Rules\Block\Adminhtml\Example\Rule\Edit;
class Form extends \Magento\Backend\Block\Widget\Form\Generic
{
/**
* Constructor
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setId('example_rule_form');
$this->setTitle(__('Rule Information'));
}
/**
* Prepare form before rendering HTML
*
* @return \Magento\Backend\Block\Widget\Form\Generic
*/
protected function _prepareForm()
{
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create(
[
'data' => [
'id' => 'edit_form',
'action' => $this->getUrl('vendor_rules/example_rule/save'),
'method' => 'post',
],
]
);
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
およびタブ:
app / code / Vendor / Rules / Block / Adminhtml / Example / Rule / Edit / Tabs.php
<?php
namespace Vendor\Rules\Block\Adminhtml\Example\Rule\Edit;
class Tabs extends \Magento\Backend\Block\Widget\Tabs
{
/**
* Constructor
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setId('rules_edit_tabs');
$this->setDestElementId('edit_form');
$this->setTitle(__('Rules'));
}
}
Ceneralモデルの情報と条件の2つのタブがあります。
app / code / Vendor / Rules / Block / Adminhtml / Example / Rule / Edit / Tab / Main.php
<?php
namespace Vendor\Rules\Block\Adminhtml\Example\Rule\Edit\Tab;
use Magento\Backend\Block\Template\Context;
use Magento\Backend\Block\Widget\Form\Generic;
use Magento\Backend\Block\Widget\Tab\TabInterface;
use Magento\Framework\Data\FormFactory;
use Magento\Framework\Registry;
class Main extends Generic implements TabInterface
{
/**
* Constructor
*
* @param Context $context
* @param Registry $registry
* @param FormFactory $formFactory
* @param array $data
*/
public function __construct(
Context $context,
Registry $registry,
FormFactory $formFactory,
array $data = []
) {
parent::__construct($context, $registry, $formFactory, $data);
}
/**
* {@inheritdoc}
*/
public function getTabLabel()
{
return __('Rule Information');
}
/**
* {@inheritdoc}
*/
public function getTabTitle()
{
return __('Rule Information');
}
/**
* {@inheritdoc}
*/
public function canShowTab()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isHidden()
{
return false;
}
/**
* Prepare form before rendering HTML
*
* @return Generic
*/
protected function _prepareForm()
{
$model = $this->_coreRegistry->registry('current_rule');
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('rule_');
$fieldset = $form->addFieldset('base_fieldset', ['legend' => __('General Information')]);
if ($model->getId()) {
$fieldset->addField('rule_id', 'hidden', ['name' => 'rule_id']);
}
$fieldset->addField(
'name',
'text',
['name' => 'name', 'label' => __('Rule Name'), 'title' => __('Rule Name'), 'required' => true]
);
$fieldset->addField(
'description',
'textarea',
[
'name' => 'description',
'label' => __('Description'),
'title' => __('Description'),
'style' => 'height: 100px;'
]
);
$fieldset->addField(
'is_active',
'select',
[
'label' => __('Status'),
'title' => __('Status'),
'name' => 'is_active',
'required' => true,
'options' => ['1' => __('Active'), '0' => __('Inactive')]
]
);
if (!$model->getId()) {
$model->setData('is_active', '1');
}
$fieldset->addField('sort_order', 'text', ['name' => 'sort_order', 'label' => __('Priority')]);
$dateFormat = $this->_localeDate->getDateFormat(\IntlDateFormatter::SHORT);
$fieldset->addField(
'from_date',
'date',
[
'name' => 'from_date',
'label' => __('From'),
'title' => __('From'),
'input_format' => \Magento\Framework\Stdlib\DateTime::DATE_INTERNAL_FORMAT,
'date_format' => $dateFormat
]
);
$fieldset->addField(
'to_date',
'date',
[
'name' => 'to_date',
'label' => __('To'),
'title' => __('To'),
'input_format' => \Magento\Framework\Stdlib\DateTime::DATE_INTERNAL_FORMAT,
'date_format' => $dateFormat
]
);
$form->setValues($model->getData());
if ($model->isReadonly()) {
foreach ($fieldset->getElements() as $element) {
$element->setReadonly(true, true);
}
}
$this->setForm($form);
$this->_eventManager->dispatch('adminhtml_example_rule_edit_tab_main_prepare_form', ['form' => $form]);
return parent::_prepareForm();
}
}
条件:
app / code / Vendor / Rules / Block / Adminhtml / Example / Rule / Edit / Tab / Conditions.php
<?php
namespace Vendor\Rules\Block\Adminhtml\Example\Rule\Edit\Tab;
use Magento\Backend\Block\Widget\Form\Generic;
use Magento\Backend\Block\Widget\Tab\TabInterface;
class Conditions extends Generic implements TabInterface
{
/**
* Core registry
*
* @var \Magento\Backend\Block\Widget\Form\Renderer\Fieldset
*/
protected $rendererFieldset;
/**
* @var \Magento\Rule\Block\Conditions
*/
protected $conditions;
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Data\FormFactory $formFactory
* @param \Magento\Rule\Block\Conditions $conditions
* @param \Magento\Backend\Block\Widget\Form\Renderer\Fieldset $rendererFieldset
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Rule\Block\Conditions $conditions,
\Magento\Backend\Block\Widget\Form\Renderer\Fieldset $rendererFieldset,
array $data = []
) {
$this->rendererFieldset = $rendererFieldset;
$this->conditions = $conditions;
parent::__construct($context, $registry, $formFactory, $data);
}
/**
* {@inheritdoc}
*/
public function getTabLabel()
{
return __('Conditions');
}
/**
* {@inheritdoc}
*/
public function getTabTitle()
{
return __('Conditions');
}
/**
* {@inheritdoc}
*/
public function canShowTab()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isHidden()
{
return false;
}
/**
* Prepare form before rendering HTML
*
* @return Generic
*/
protected function _prepareForm()
{
$model = $this->_coreRegistry->registry('current_rule');
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('rule_');
$renderer = $this->rendererFieldset->setTemplate(
'Magento_CatalogRule::promo/fieldset.phtml'
)->setNewChildUrl(
$this->getUrl('vendor_rules/example_rule/newConditionHtml/form/rule_conditions_fieldset')
);
$fieldset = $form->addFieldset(
'conditions_fieldset',
[
'legend' => __(
'Apply the rule only if the following conditions are met (leave blank for all products).'
)
]
)->setRenderer(
$renderer
);
$fieldset->addField(
'conditions',
'text',
['name' => 'conditions', 'label' => __('Conditions'), 'title' => __('Conditions')]
)->setRule(
$model
)->setRenderer(
$this->conditions
);
$form->setValues($model->getData());
$this->setForm($form);
return parent::_prepareForm();
}
}
詳細を表示するには、このリンクをクリックしてください。
Magento2.1のUIコンポーネントの使用
<fieldset name = "conditions"> <引数名= "data" xsi:type = "array"> <item name = "config" xsi:type = "array"> <item name = "label" xsi:type = "string" translate = "true">条件</ item> <item name = "collapsible" xsi:type = "boolean"> true </ item> <item name = "sortOrder" xsi:type = "number"> 20 </ item> </ item> </引数> <コンテナ名= "conditions_apply_to"> <引数名= "data" xsi:type = "array"> <item name = "config" xsi:type = "array"> <item name = "sortOrder" xsi:type = "number"> 10 </ item> </ item> </引数> <htmlContent name = "html_content"> <argument name = "block" xsi:type = "object"> Magento \ SalesRule \ Block \ Adminhtml \ Promo \ Quote \ Edit \ Tab \ Conditions </ argument> </ htmlコンテンツ> </コンテナ> </ fieldset>