OOP Designer Admin for Bitrix

The more serious we take our projects, the more we want the tasks to be solved in the best possible way. For example, we want to provide the client with a high-quality admin panel in an adequate time frame. Personally, at such moments I immediately recall Django: created a model - get an admin panel. Or widgets in Yii. Or a wonderful combination of hooks and classes in Drupal 7. Or Sonata in Symfony, about which I, however, have only heard. But what if we got Bitrix?

Admin on bitrix "feng shui"


Unfortunately, Bitrix, despite attempts by developers to somehow rectify the situation, in many of its aspects remains a system of archaic: procedural pieces of code of several hundred lines, copy-paste, raised to the level of the manual, classes from which it is impossible to inherit normally - all this to this the day remains a reality for those who have to work with this system. And I’m sure it won’t pass soon.

What should a developer do if he needs to create an administrative interface for some custom table in the database? According to the manual, we need to copy the “fish” with a code of 417 lines - for the page of the list of elements and 365 lines- for the item edit page. Well, or write everything yourself if we are happy owners of phenomenal memory. Well, 2016 in the yard is a good start!

But after all nothing works for us! After we have completed the copy-paste act, we need to carefully read 782 lines of code, delete everything superfluous and add our own. Namely:

  1. Write the validation of these filters.
  2. Specify a list of columns for filtering the selection.
  3. Write the processing of actions on an individual element and on a group of list elements.
  4. Make the selection itself. And usually no one is steaming, they just do SELECT * FROM ... - in the "fish" from the bitrix it is by no means proposed to limit the list of selectable fields to only those that are necessary.
  5. Specify a list of columns to display in the list.
  6. In the process of listing, for each column, display a specific control.
  7. Print footer table.
  8. Display a filter above the table.

This is for the list page. I specifically indicated the points not in the order in which the logic prompts, and in which they are displayed on the resulting page, but in the order in which this code is found in the "fish" from the manual.

Now, what do we need to do if we decide to, say, add another field to the list? Or even just rename some existing one? We must register this new field in 7 places or change the existing one without making a mistake! The situation is complicated by the fact that along with the php code in the same file there is also html, moreover, in the completely different order in which it is displayed on the page, unreadable by either your favorite IDE or the human eye, because many tags are generated somewhere in the bowels. This is all very difficult to navigate. Especially when the page is not at all simple and it also contains JS-code, usually written inline.

What do we get as a result? Bugs. Complexity of support. Unreasonably high time costs even when changing any little things. The situation is the same for the item edit page. I sincerely do not understand how many years it was possible to chew such a cactus ?!

How could everything be


Oddly enough, the Bitrix admin admin API is well-designed. After the horrors described above, this is hard to believe, but this is true. Because the problem is not in the API itself, but in how they began to use it further. It seems that the developer (s) of the API had some plans for the future about him, or just some vague insights, but did not make the simple and logical next step: creating a set of MVC classes. Probably the reason for this is, until recently, the lack of a single interface for working with the database.

After viewing a great number of self-written admins, it becomes clear that, regardless of the complexity and characteristics of the task, the process of building the admin panel includes the same steps that I described above. This means that the code is the same everywhere, it remains only to change the input data. The following entities can be distinguished without being tied to the code:

  1. Interface config: a list of fields that will be used to form filters, columns of the list table or a set of inputs on the edit page.
  2. Presentation class for interface output. At the entrance, he should receive a config, “under the hood” he will have all the logic that we see in the “fish” from the bitrix, at the output he will give out a rendered page.
  3. Widget. It contains the logic of a separate admin area. With the help of the list, the cells of the table are drawn in the list, on the edit page - the fields of the element.

In fairness, it must be said that the echoes of this concept are visible in the bitrix source code: in particular, the “user types”, which are available both for info blocks and for “Highload” info blocks, are nothing but “widgets” in the above scheme.

By implementing the above classes, we could significantly reduce the “fish” from bitrix to something like this:

$fields = include(‘fields.conf.php’);
$adminListHelper = new MyHelper($fields);
$adminListHelper->buildList(array($by => $order));
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_admin_after.php");
$adminListHelper ->createFilterForm();
$adminListHelper ->show();
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/epilog_admin.php");

In this seven-line piece of code, the basic steps for creating the admin panel are described, which are described at the beginning of the article. But instead of copying this, albeit short, snippet every time, it’s better to work a little more and do this:

  • register the above code in a special route.php file, to which all requests to the administrative interface created through our add-on over the bitrix API will be redirected;
  • in the file with the interface config description, register this config in any global variable or static class variable;
  • when accessing the pages of the administrative interface, use not direct URLs, but aliases and functions that construct the correct URL from these aliases;
  • in the end, all the requests will come to route.php, which will figure out which class to create, which interface config to pass to it, and how to display it all.

As a result, the code necessary for creating the basic pages of the list and editing is reduced many times, and since we are not talking about hundreds of lines, I can give it here:

List class
class TableListHelper extends AdminListHelper
{
    static protected $model = 'MyModelTable';
    static public $module = 'my.module';
    static protected $viewName = 'table_list';
    static protected $editViewName = 'table_detail';
}


Edit Page Class
class TableEditHelper extends AdminEditHelper
{
    static protected $model = 'MyModelTable';
    static public $module = 'my.module';
    static protected $listViewName = 'table_list';
    static protected $viewName = 'table_detail';
}


Interface settings
AdminBaseHelper::setInterfaceSettings(
    array(
        'FIELDS' => array(
            'ID' => array(
                'WIDGET' => new NumberWidget(),
                'TITLE' => 'ID',
                'TAB' => 'TAB_ONE'
            ),
            'STRING' => array(
                'WIDGET' => new StringWidget(),
                'TITLE' => 'STRING',
                'TAB' => 'TAB_ONE'
            ),
            'NUMBER' => array(
                'WIDGET' => new NumberWidget(),
                'TITLE' => 'NUMBER',
                'TAB' => 'TAB_ANOTHER'
            ),
            'TEXT' => array(
                'WIDGET' => new TextAreaWidget(),
                'TITLE' => 'TEXT',
                'TAB' => 'TAB_ANOTHER'
            )
        ),
        'TABS' => array(
            'TAB_ONE' => Loc::getMessage('TAB_ONE'),
            'TAB_ANOTHER' => Loc::getMessage('TAB_ANOTHER'),
        )
    ),
    array(
        '\TableEditHelper',
        '\TableListHelper'
    ),
    'my.module'
);


Menu.php file
$menu = array(
    array(
        "parent_menu" => "global_menu_services",
        "section" => "table",
        "sort" => 140,
        "text" => Loc::getMessage('TABLE_MENU_TEXT'),
        "title" => Loc::getMessage('TABLE_MENU_TITLE'),
        "icon" => "table_menu_icon",
        "page_icon" => "table_page_icon",
        "items_id" => "menu_table",
        "url" => TableEditHelper::getListPageURL(),
        "more_url" => array(
            TableListHelper::getEditPageURL()
        ),
    ),
);
return $menu; 


There are not hundreds of lines of copy paste and copying files to / bitrix / admin - and as a result we get a quite working admin panel for a table with four columns: a list page, an edit page, and links to them in the system menu. With support for CRUD operations out of the box. With normal routing (in this example - /bitrix/admin/route.php?module=my.module&view=tab_list will open the list page. You can modify this to "CNC" if you want or need). Then we just redefine the methods of the base classes in order to customize its behavior for your tasks. It looks tempting, doesn't it?

The future is here!


And now about the pleasant: the above is no longer just a concept, but a real, working, already visited the production of many projects module, which I would like to share:

github.com/DigitalWand/digitalwand.admin_helper

The code becomes several orders of magnitude more concise, template copy-paste is minimized, giving way to arrays with a configuration, which, in principle, was not in the bitrix:

The amount of code using the module and without it
Comparison is based on:


The module can work both with fully custom tables and with tables created through the Bitrix functionality of the “Highload” infoblocks, while instead of “widgets” it is possible to use classes of “user properties”. Thus, all the functionality available in the admin panel of "Highload" -folders is available to us, only now we can easily customize it to fit our needs.

I should also warn readers that in this article the “old style” of working with the module from its first version was deliberately used in order to more clearly demonstrate the internal mechanism of its operation. In the latest versions in helper classes, it’s enough to specify only the model - the module will determine the rest itself.

More useful materials are available:
  • A small presentation , designed to convince supporters of the "old school" and "Bitrix Way" to switch to new "rails".
  • The outline outline illustrates the architecture of the module: Module architecture


I would like to end the article with words of gratitude to the authors of Qt Framework, which inspired the pursuit of beauty and the web, a wish for success to those who are actively developing this module, as well as the hope that someday writing under Bitrix will be not only profitable, but also pleasant.

Also popular now: