Answers:
要将条件字段添加到默认模型(并进一步用于验证目的),您将需要创建一个包含这些字段的新模型(或修改现有模型)。
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();
}
}
现在,我们有了一个包含模型描述的表格,我们需要完成模型本身,并在其中包含适当的资源模型和集合。
该模型将称为“规则”:
应用/代码/供应商/规则/模型/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
)模块中的默认条件模型。如果需要扩展条件,则可以添加自己的clase和/或完全重写它们或从可用的基本类继承。当您要添加默认条件中未包含的特殊条件时,In很有用。例如,带折扣的小计。
....
接下来,让我们切换到管理面板中的界面。我们需要控制器具有一组动作(例如,保存,添加,编辑,网格显示,重新加载条件)和带有块的布局。
让我们从Controller本身开始。首先,声明公共控制器:
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()
方法检查当前管理员是否有权访问Controller。
在下一步,我们将添加默认操作:
....
编辑:
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'));
}
}
我们将有两个标签:常规模型的信息和条件。
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();
}
}
要查看更多详细信息,请点击此链接。
将UI组件用于Magento2.1
<fieldset name =“ conditions”> <argument name =“数据” xsi:type =“ array”> <item name =“ config” xsi:type =“ array”> <item name =“ label” xsi:type =“ string” translation =“ true”>条件</ item> <item name =“ collapsible” xsi:type =“ boolean”> true </ item> <item name =“ sortOrder” xsi:type =“ number”> 20 </ item> </ item> </ argument> <container name =“ conditions_apply_to”> <argument name =“数据” xsi:type =“ array”> <item name =“ config” xsi:type =“ array”> <item name =“ sortOrder” xsi:type =“ number”> 10 </ item> </ item> </ argument> <htmlContent name =“ html_content”> <argument name =“ block” xsi:type =“ object”> Magento \ SalesRule \ Block \ Adminhtml \ Promo \ Quote \ Edit \ Tab \ Conditions </ argument> </ htmlContent> </ container> </ fieldset>