The example of Magento 2 Module with Conditions Model and Fieldset (Part 1)

While browsing Magento forums we often bump to the threads where developers are asking how to create an extension with custom rules and fieldset. Hence, we’ve decided to illustrate that on the example of a sample module that can be also used for further validating and other development purposes.

Let’s roll in!

To add a conditional field to the default model (and further utilize it for validating purposes), you will need to create a separate model (or modify the existing one) that contains the corresponding fields.

Below, you’ll find a description of how to add the condition to both the model and interface without using Magento UI.

First, let’s create a new and simple module for that (or make some changes in the module you already have):

As you can see, our model inherits from the Magento\Rule\Model\AbstractModel model that already has all the required methods.

Right in the Constructor, we’ll add condition factories that allow us to work with them and create multiple methods. This should give us the understanding of how the model works.

Note that we are using the default condition models from the Magento SalesRule (\Magento\SalesRule\Model\Rule\Condition) module. If you need to expand the conditions, you can add your own classes and/or rewrite them completely or inherit from the base available classes. In can be useful when you want to add a special condition that is not included in the default conditions. For example, **Subtotal With Discount**.

There are also some collection filter methods that can help you cut off the inactive or mismatching the current date rules while validating. For example, these will help us decrease server overloads: setValidationFilter и addDateFilter.

Now, we’ve finished with the structure declaration and are halfway through with this task!

Next, let’s switch to the interface in the admin panel. We need the Controller with a set of actions (such as Save, Add, Edit, Grid Display, Conditions reload) and a layout with blocks.

Let’s start with the Controller itself. First, declare the common Controller:

* Returns result of current user permission check on resource and privilege

*

* @return bool

*/

protectedfunction_isAllowed()

{

return$this->_authorization->isAllowed('Vendor_Rules::rules');

}

}

Here, we need to call out our models’ factory in the Constructor. That is done to make them (and some auxiliary classes, like a register and a logger) publicly available.

The _initRule method is responsible for the current rule initialization or creating of a new and empty one with the ability of adding it to the register.
The _initAction() method loads a layout and makes the modules’ menu available for actions (also, it adds breadcumbs).
The _isAllowed() method checks if the current admin has an access to the Controller.

In this case, you should pay attention to the field where the conditions come. The prepareData method allows us to correctly tranfer conditons to the model before saving. This is how to add new conditions:

Next, we need to create all the required blocks and layout. First, let’s add a container for the Grid:

app/code/Vendor/Rules/Block/Adminhtml/Example/Rule.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<?php

namespaceVendor\Rules\Block\Adminhtml\Example;

classRuleextends\Magento\Backend\Block\Widget\Grid\Container

{

/**

* Constructor

*

* @return void

*/

protectedfunction_construct()

{

$this->_controller='example_rule';

$this->_headerText=__('Example Rules');

$this->_addButtonLabel=__('Add New Rule');

parent::_construct();

}

}

Note that when doing this, you’ll be able to add only the Controller’s name (it will be used when forming Grid and Lable). In case you need to add something else to the Grid page, you can do that via your block-container or directly via the Layout.

We are using our Vendor\Rules\Model\ResourceModel\Rule\Collection collection as a source and define the sorting order.

The <block class="Magento\Backend\Block\Widget\Grid\ColumnSet" as="grid.columnSet" name="adminhtml.example.rule.grid.columnSet">...</block> block contains a number of columns. If you want to add your own columns, they should be added to the database and the Grid (if you want to see them):

Now, let’s get down to creating and editing new rules. Let’s create the main container block for editing:

Also, let me draw your attention to the template that are used to render a fieldset: Magento_CatalogRule::promo/fieldset.phtml and an address to recieve a new descendant: vendor_rules/example_rule/newConditionHtml/form/rule_conditions_fieldset that links to the app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/NewConditionHtml.php action we created earlier. In other words, all new descendants will derive from it.

If you can’t add conditions, start the debug from this fieldset and condition.

The correct answer for choosing another attribute in the conditions looks like this:

You can understand that the controller works incorrectly if the window is not responding when choosing a new attribute in the conditions:

In this case you should reload the page first and then open your browser’s console to find a mistake in respone for the ajax request.

I am a huge coffee fan. If I’m not drinking it, I’m likely to be busy with getting MageWorx projects done. Fond of reading sci-fi books (especially those about dwarfs, ogres and the post-apocalyptical world). My biggest dream is to find a huge chest of gold and buy my own uninhabited island. Happy husband. Proud father. Ah... and also I'm a certified Magento developer. ;)