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):

app/code/Vendor/Rules/registration.php

app/code/Vendor/Rules/composer.json

app/code/Vendor/Rules/etc/module.xml

These files declare the Rules module in the Vendor namespace.

Next, let’s add the files responsible for the main configuration setup:

app/code/Vendor/Rules/etc/acl.xml

Note, we’ve added acl in order to disable the module for certain administrators.

app/code/Vendor/Rules/etc/adminhtml/routes.xml

Also, we’ve added an admin route with the vendor_rules name and id. Later, we can use it to get an access to the modules’ interface in the admin panel.

app/code/Vendor/Rules/etc/adminhtml/menu.xml

By doing that, we’ve added a menu section for our module in the Marketing tab.

Now, let’s add the tables to the module database. These fields are default, and you can expand them whenever needed.

Let’s name the table according to the module name – vendor_rules.

app/code/Vendor/Rules/Setup/InstallSchema.php

Our conditions will be stored in the conditions_serialized field. The rest of the data just describes the model (example).

Also, don’t forget to add the module uninstall file! That is done to delete the table after installing it via Composer and/or deleting.

app/code/Vendor/Rules/Setup/Uninstall.php

Now, we have a table with the model description and we need to complete the model itself, and include into it the appropriate resource model and collection.

The model will be called ‘Rule‘:

app/code/Vendor/Rules/Model/Rule.php

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**.

Now, it’s time to add a resource model from the Constructor:

app/code/Vendor/Rules/Model/ResourceModel/Rule.php

And a collection:

app/code/Vendor/Rules/Model/ResourceModel/Rule/Collection.php

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:

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

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.

At the next step, we are going to add the default actions:

  • Deleting:

app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/Delete.php

  • Adding (NOTE! Do not use the New word because it is keyword in the PHP):


app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/NewAction.php

  • Editing

app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/Edit.php

  • Saving

app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/Save.php

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:

app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/NewConditionHtml.php

 

This class is responsible for loading the conditions that have been chosen in the interface (all the conditions can’t be loaded at once).

  • And the last one is Grid:

app/code/Vendor/Rules/Controller/Adminhtml/Example/Rule/Index.php

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

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.

This is the Grid’s Layout:

app/code/Vendor/Rules/view/adminhtml/layout/vendor_rules_example_rule_index.xml

Everything is placed inside of the page content.

<block class="Vendor\Rules\Block\Adminhtml\Example\Rule" ...>...</block> is our main container.

Note that the container’s block and grid names are formed from the controller’s name that we mentioned in the Container. If you do this incorrectly, the Grid may fail to display.

The Grid block itself: <block class="Magento\Backend\Block\Widget\Grid" name="adminhtml.block.example.rule.grid" as="grid">. Here, we need to fill in a number of arguments:

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:

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

When done, we should add the controllers title and the save and edit current model buttons in the Constructor. Also, here you should add the main text for of the block.

This is a form itself:

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

and tabs:

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

We’ll have the two tabs: Ceneral model’s information and Conditions.

app/code/Vendor/Rules/Block/Adminhtml/Example/Rule/Edit/Tab/Main.php

Conditions:

app/code/Vendor/Rules/Block/Adminhtml/Example/Rule/Edit/Tab/Conditions.php

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:

5

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

5

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.

This is the layout for the editing form:

app/code/Vendor/Rules/view/adminhtml/layout/vendor_rules_example_rule_edit.xml

The result should be the following:

  • Main fields

1

  • Conditions

2

3

TO BE CONTINUED…

 

Comments (5)

    1. Hello Ali, we are going to download the sources to our GitHub account soon. Will send you the link as soon as it’s ready πŸ™‚

Comments are closed.