Здрасте!
Очередная суицидальная статья от меня на тему Битрикс, надеюсь в этот раз хабраобщество будет более снисходительно, т.к. здесь все по факту, с кодом, схемками, никакого холивара и все по-честному.
В статье я рассмотрю альтернативу BitrixFramework, которая призвана облегчить жизнь разработчика и как-нибудь повлиять на развитие CMS Битрикс в нужном направлении.
Акция для хейтеров: если напишите комментарий с нормальной критикой и по теме + к карме лично отправлю ;-). Вот вам Вольфыча для затравки, все интересное внутри…

Все что написано ниже лично мое мнение и может быть спокойно закидано тапками, но я уверен, что я прав:
Наверняка многие знакомы с этим персонажем (из Marvel, не из Dota), которого «невозможно остановить». Слегка пафосное название, на самом деле отражает суть данного проекта: абсолютно безразлично как развивается Битрикс, какие новшества он вводит и что он делает, все равно библиотека будет жить и процветать.
Bitrix нацелен на пользователей. Juggernaut нацелен на разработчиков.
Потому что это надо! Все на самом деле очень логично:
Битрикс нужно было с версии 14 просто закончить поддержку старого ядра и сделать основной упор на новом, но нет, «заботятся о клиентах». Бред. Это тоже самое если бы Yii2 поддерживал и обратно совмещал Yii1.
Раз Битрикс никакие подвижки не делает, то их будет делать сообщество (вместо того чтобы ныть, писать в сервис «Идея», и как-то выкручивать используя стандартные компоненты).
Поругали Bitrix, теперь можно приступить и к обзору Juggernaut. Далее начнется обзор составляющих частей библиотеки и краткое описание их использования.
Компоненты – это кирпичи из которых строиться сайт на Битрикс. Компоненты условно разделены на 2 категории: виджеты и роутеры (в нотации Битрикс: «обычный» и «комплексный»).
Виджет – это компонент, который тупо делает одну элементарную задачу (выводит форму, список, информацию). Виджет получает на вход данные и каким-либо образом их преобразует. Больше делать он ничего не должен. Виджеты не управляют маршрутизацией, но могут ее использовать.
Порядок выполнения компонента по умолчанию:

По порядку:
Чаще всего достаточно переопределить метод initResult и накидать шаблон компонента.
Ниже представлен пример класса компонента (class.php), который выводит список элементов инфоблока. На вход он получает массив параметров ($params), которые используются для фильтра и сортировки данных.
Задача роутера – это сбор виджетов воедино. Роутер — представляет из себя контроллер, который на основе запро��а пользователя (REQUEST_URI), вызывает соответствующее действие. Действие может быть либо страницей с информацией (в том числе виджетами), либо содержать какую-либо логику.
Порядок выполнения компонента по умолчанию:

По порядку:
Ниже представлен пример компонента, которые реализует каталог:
По данному вопросу много говорить не буду, потому что и так ясно что это очень нужная вещь, просто опишу все работает.
Как реализовано в Juggernaut:
В папке «lib» вы должны соблюдать следующую структуру: имена файлов классов, идентичны именам пространства имен, не включая расширение и верхнего пространства имен. Например, классу «Iblock\Property\Table» будет соответствовать файл «…/modules/Iblock/lib/Property/Table.php».
Вызывать «includeModule» больше не нужно, т.к. при необходимости все классы подгрузятся автоматически из нужных директорий.
Если директория модуля отличается от названия пространства имен, или в любой другой ситуации, можно вручную задать соответствие пространства имен и директории:
У Битрикс тоже реализована автозагрузка, но формирует она путь несколько иначе:
Класс «Olof\Catalog\Tools\File» транслируется как «/Olof.Catalog/lib/Tools/File.php».
Если Вам нужен класс «Olof\Catalog» — то извините, руками указывайте его наличие (см.ниже). Директория модуля у Вас должна быть именно с разделителем «.» иначе гуляйте лесом. При чем директория «olof.catalog.iblock» — является некорректной.
Господа из Битрикс на самом деле сделали нормальную штуку: позаботились об указании вендора в имени модуля, но я считаю это лишнее условие именования директории.
Автозагрузка неявно реагирует на классы вида «ElementTable» удаляя постфикс, транслируя их в файлы «element.php». Собственно, из-за этого, вы не можете создать класс с именем Table.
Также загрузить классы из модулей, которые в данный момент не подключены (includeModule) – нельзя.
Рассмотрим пример работы Битриксового варианта: имеем модуль «olof.iblock» и соответствующий файл include.php:
Слишком много неявностей и условий на мой взгляд. Да и никто не знает, какую глупость Битрикс завтра придумают. А придумать им стоит указание директории для префикса пространства имен (как в PSR-4) и тогда будет круто. А пока есть Juggernaut ;-)
Для удобства работы с сущностями, а в частности с инфоблоками, реализован шаблон ActiveRecord. На данный момент AR базируется (по факту является надстройкой) на битриксовых DataMapper’ах, в дальнейшем планируется полный перенос на независимый ORM / DAO.
Ниже представлен пример работы с инфоблоками через AR, охвачены практически все, имеющиеся на данный момент, методы.
Методы: getPrimary, getRow, getRowByField, getList, getListByField — идентичны для всех ActiveRecord.
Функционал AR на данный момент достаточно беден (например, нет перекрестного поиска по таблицам), но т. к. они являются оберткой над стандартными функциями, в методах «getList» и «getRow» можно использовать Битриксовые плюшки. После создания / заимствования нормального DAO, этот момент будет допилен.
Сильной стороной Битрикс, и я думаю многие согласятся, является его пользовательский интерфейс a.k.a. «Эрмитаж». Он очень удобен и гибок.
Ниже представлен пример работы с Эрмитажем:
Так похвалил и так мало написал)) На самом деле этого достаточно для взаимодействия с пользователем. Очень много нужно реализовать касаемо административного интерфейса, но это уже не Эрмитаж, и это все в планах.
В Битрикс на сколько я знаю (а в данном вопросе, скрывать не буду, я особо не ковырялся), с безопасностью сайта (именно в коде) вообще грустно (только защита от SI). В будущем данный раздел будет содержать в себе инструменты для защиты от различных атак и вредоносных действий (XSS, генерация случайных данных, различные крипто-функции, валидация форм, работа с паролями, …). На данный момент реализован только инструментарий для защиты от CSRF:
После каждой проверки (удачно или неудачной) – токен из сессии удаляется, таким образом проверить токен можно только один раз.
Маршрутизация в Битрикс, не сказал бы что на высоте, поэтому и эта область затронута в Juggernaut. Данный класс позволяет динамически создавать и использовать URL маршруты (используется в компонентах-роутерах).
Рассмотрим пример парсинга и генерирования URL:
В дальнейшем планируется также подвязаться и к urlRewrite.php.
Данный класс является просто оберткой над функциями D7, с более удобным использованием.
Планы на ближайшее будущее:
Много чего задумано, много чего не сделано. Библиотека развивается по мере моей необходимости, поэтому очень зависит от текущих заказов (которое очень часто однотипны) и свободного времени.
Как я уже сказал вначале, проект будет развиваться несмотря ни на что, от количества ее авторов и заинтересованных лиц зависит лишь скорость развития. Так что выбор только за вами:
Помочь может каждый желающий филантроп (а иначе никак), для этого нужно:
Проект лежит на GitHub, так что править, добавлять, комментировать и спрашивать может любой желающий.
Спасибо за внимание! Конструктивная критика очень даже приветствуется :-)
P.S. комментарии типа «да на фиг Битрикс» огромная просьба не писать. Я в курсе какое у людей отношение к этой системе, и данный проект как раз направлен на ее облагораживание. Поэтому если вы считаете что «лучше и проще сделать проект на любом фреймворке» — то я это знаю и очень рад за вас, поэтому оставьте свое мнение при себе. Спасибо!
Репозиторий: github.com/irpsv/juggernaut.bitrix_release
Маркетплейс: скоро будет
Очередная суицидальная статья от меня на тему Битрикс, надеюсь в этот раз хабраобщество будет более снисходительно, т.к. здесь все по факту, с кодом, схемками, никакого холивара и все по-честному.
В статье я рассмотрю альтернативу BitrixFramework, которая призвана облегчить жизнь разработчика и как-нибудь повлиять на развитие CMS Битрикс в нужном направлении.
Акция для хейтеров: если напишите комментарий с нормальной критикой и по теме + к карме лично отправлю ;-). Вот вам Вольфыча для затравки, все интересное внутри…

Для начала расставим все точки над ‘i’
Все что написано ниже лично мое мнение и может быть спокойно закидано тапками, но я уверен, что я прав:
- «У Битрикс миллион строк говнокода» — да, бесспорно. Вся проблема заключается в том, что Битрикс поддерживает обратную совместимость (якобы обновив версию 12.0 до 16.5 все будет нормально работать). Зачем они это делают я не знаю (мне кажется никто не знает). Если же говорить про исходники стандартных компонентов (2К строк кода для вывода элементов инфоблока – в порядке вещей), то здесь ребята решили облегчить работу конечным юзерам и предусмотрели все что можно было предусмотреть (и то не факт), при чем все полностью это очень редко когда нужно. Ну и в догонку, на недавнем семинаре разработчик Битрикс сообщил свое отношение к PSR: «Ну что этот PSR, читал я его, собрались какие-то ребята и написали какую-то фигню» (не точная цитата). Так что код будет пахнуть всегда.
- «У Битрикс ужасная структура» — не совсем. Битрикс основан на файлах, и понимание MVC отличается от общепринятого, а для многих «не MVC» = «ужас-ужас какая структура». Так что это весьма спорный и спорный вопрос. И с Битриксовой структурой можно жить.
- «BitrixFramework никогда не будет развиваться» — это уже мое мнение и вот почему: с каждым релизом Битрикс дорабатывает только модуль «Магазин», делают какие-то правки, но все они направлены на магазин. На остальное им откровенно наплевать. Развитие BF начнется, когда они откажутся от обратной совместимости и начнут заниматься не только модулем «Магазин».
Знакомьтесь, Juggernaut!
Наверняка многие знакомы с этим персонажем (из Marvel, не из Dota), которого «невозможно остановить». Слегка пафосное название, на самом деле отражает суть данного проекта: абсолютно безразлично как развивается Битрикс, какие новшества он вводит и что он делает, все равно библиотека будет жить и процветать.
Bitrix нацелен на пользователей. Juggernaut нацелен на разработчиков.
Зачем это надо?
Потому что это надо! Все на самом деле очень логично:
- Битрикс разрабатывают новое ядро (good), но документировать вообще не хотят (bad);
- Битрикс разрабатывают новый функционал (good), но только для магазина (bad);
- Битрикс разрабатывают новые компоненты (good), но от их кода кровь из глаз (bad);
- Битрикс запатентовали «новую» технологию «Композитный сайт» (bad).
Битрикс нужно было с версии 14 просто закончить поддержку старого ядра и сделать основной упор на новом, но нет, «заботятся о клиентах». Бред. Это тоже самое если бы Yii2 поддерживал и обратно совмещал Yii1.
Раз Битрикс никакие подвижки не делает, то их будет делать сообщество (вместо того чтобы ныть, писать в сервис «Идея», и как-то выкручивать используя стандартные компоненты).
Поругали Bitrix, теперь можно приступить и к обзору Juggernaut. Далее начнется обзор составляющих частей библиотеки и краткое описание их использования.
Компоненты
Компоненты – это кирпичи из которых строиться сайт на Битрикс. Компоненты условно разделены на 2 категории: виджеты и роутеры (в нотации Битрикс: «обычный» и «комплексный»).
Виджет
Виджет – это компонент, который тупо делает одну элементарную задачу (выводит форму, список, информацию). Виджет получает на вход данные и каким-либо образом их преобразует. Больше делать он ничего не должен. Виджеты не управляют маршрутизацией, но могут ее использовать.
Порядок выполнения компонента по умолчанию:

По порядку:
- init — инициализирует начальные данные. Преобразует входные параметры ($arParams) в свойства класса;
- onBefore — проводит проверку возможности проведения действия;
- isCachedTemplate — флаг, определяющий есть ли кешированная копия. Если есть — выводит данные кеша, если нет — формирует их (в коде это выглядит несколько иначе, на схеме указано так для простоты);
- initResult — формирует данные для представления ($arResult);
- run — функция непосредственного исполнения виджета. В ней определяется что необходимо сделать с данными ($arResult);
- onBeforeRender — проводит проверку возможности вывода шаблона и выполняет какие либо преобразования (аналог result_modifier.php, хотя можно и им пользоваться);
- render — непосредственный вывод шаблона компонента;
- onAfter — выполнение действия после отработки виджета (аналог component_epilog.php).
Чаще всего достаточно переопределить метод initResult и накидать шаблон компонента.
Ниже представлен пример класса компонента (class.php), который выводит список элементов инфоблока. На вход он получает массив параметров ($params), которые используются для фильтра и сортировки данных.
Код
<?php namespace Widget\Iblock\Element\List_; use Jugger\Db\Orm\Ib\IblockElement; use Jugger\Component\WidgetComponent; class Component extends WidgetComponent { /* * при выполнения метода 'init', * все переменные из $arParams присваиваются существующим свойствам класса компонента, * в данном случае: $this->params = $arParams['params'] */ public $params = []; /* * по умолчанию, кеширование компонентов отключено * в данном методе, мы его включаем */ protected function init() { parent::init(); $this->isCachingTemplate = true; } /* * инициализируются элементы для отображения */ protected function initResult() { $this->arResult['elements'] = IblockElement::getList($this->params); } }
Роутер
Задача роутера – это сбор виджетов воедино. Роутер — представляет из себя контроллер, который на основе запро��а пользователя (REQUEST_URI), вызывает соответствующее действие. Действие может быть либо страницей с информацией (в том числе виджетами), либо содержать какую-либо логику.
Порядок выполнения компонента по умолчанию:

По порядку:
- init — инициализирует начальные данные. Преобразует входные параметры ($arParams) в свойства класса;
- initUrlManager — заполняет UrlManager данные маршрутов (aliases). Это действие необходимо для выполнения маршрутизации по действием и дальнейшей генерацией URL адресов;
- parseRequest — производится разбор запроса UrlManager и определяется какое действие запрошено пользователем;
- existBeforeAction — проверка наличия персонального обработчика onBefore. Если есть действие 'index' и есть метод 'onBeforeIndex', то будет вызван именно он, иначе будет вызван общий 'onBefore';
- onBefore — проводит проверку возможности проведения действия;
- run — функция непосредственного исполнения компонентв. В ней определяется что необходимо сделать с данными ($arResult);
- existMethodAction — проверка на наличие обработчика действия. Если запрошено действие 'index' и есть метод 'actionIndex', то будет вызван этот метод, иначе роутер попытается вывести представление с именем 'index';
- onBeforeRender — проводит проверку возможности вывода шаблона и выполняет какие либо преобразования (в параметрах передается имя действия, поэтому можно настроить персональную проверку);
- render — непосредственный вывод шаблона компонента;
- onAfter — выполнение действия после отработки виджета (аналог component_epilog.php). Работает аналогично с методом 'onBefore': если для действия 'index' существует метод 'onAfterIndex', то будет вызван он, иначе общий 'onAfter'.
Ниже представлен пример компонента, которые реализует каталог:
- список элементов,
- список разделов
- детальная карточка элемента.
Код
<?php namespace Widget\Iblock\Element\Catalog; use Jugger\Db\Orm\Ib\IblockElement; use Jugger\Db\Orm\Ib\IblockSection; use Jugger\Component\RouteComponent; class Component extends RouteComponent { /* * ID инфоблока, который отображается */ public $iblockId; /* * Маршруты действий, в которые будут транслироваться адреса и по которым будер производиться маршрутизация * по умолчанию, маршруты беруться из параметров компонента из свойства 'aliases' */ protected function getAliases() { return [ "sectionList" => "index.php", "elementList" => "#SECTION_CODE#/", "elementView" => "#SECTION_CODE#/#ELEMENT_CODE#/" ]; } /* * Если инфоблок не указан, то выходим */ protected function onBefore($action) { if (!$this->iblockId) { throw new \Exception("Не указан 'iblockId' ". get_called_class()); } return parent::onBefore($action); } /* * Получаем раздел по его символьному коду */ protected function getSection($sectionCode) { return IblockSection::getRow([ "filter" => [ "IBLOCK_ID" => $this->iblockId, "CODE" => $sectionCode ], ]); } /** * Список разделов инфоблока */ public function actionSectionList() { $sectionList = IblockSection::getListByField( "=IBLOCK_ID", $this->iblockId, [ "order" => ["SORT" => "ASC"] ] ); $this->arResult['sectionList'] = $sectionList; $this->render('list'); } /** * Список элементов указанного раздела * Параметр $sectionCode содержит данные из URL */ public function actionElementList($sectionCode) { $section = $this->getSection($sectionCode); if (!$section) { $this->error404(); } // $this->arResult['section'] = $section; $this->arResult['elementList'] = $section->getElements(); $this->render('section'); } /** * Отображение карточки товара * Параметры передаются в том же порядке, в каком они указаны в методе 'aliases' */ public function actionElementView($sectionCode, $elementCode) { $section = $this->getSection($sectionCode); if (!$section) { $this->error404(); } // $element = IblockElement::getRow([ "filter" => [ "IBLOCK_ID" => $this->iblockId, "IBLOCK_SECTION_ID" => $section->ID, "CODE" => $elementCode, ], ]); if (!$element) { $this->error404(); } $this->arResult['element'] = $element; $this->arResult['section'] = $section; $this->render('view'); } }
Автозагрузка классов
По данному вопросу много говорить не буду, потому что и так ясно что это очень нужная вещь, просто опишу все работает.
Как реализовано в Juggernaut:
В папке «lib» вы должны соблюдать следующую структуру: имена файлов классов, идентичны именам пространства имен, не включая расширение и верхнего пространства имен. Например, классу «Iblock\Property\Table» будет соответствовать файл «…/modules/Iblock/lib/Property/Table.php».
Вызывать «includeModule» больше не нужно, т.к. при необходимости все классы подгрузятся автоматически из нужных директорий.
Если директория модуля отличается от названия пространства имен, или в любой другой ситуации, можно вручную задать соответствие пространства имен и директории:
// класс "Jugger\D7\Iblock" доступен по адресу "./lib/D7/Iblock.php" – по умолчанию так и работает \Jugger\Psr\Psr4\Autoloader::addNamespace('Jugger', __DIR__.'/lib'); // класс "Jugger\D7\Iblock" доступен по адресу "./classes/Iblock.php" \Jugger\Psr\Psr4\Autoloader::addNamespace('Jugger\D7', __DIR__.'/classes');
У Битрикс тоже реализована автозагрузка, но формирует она путь несколько иначе:
Класс «Olof\Catalog\Tools\File» транслируется как «/Olof.Catalog/lib/Tools/File.php».
Если Вам нужен класс «Olof\Catalog» — то извините, руками указывайте его наличие (см.ниже). Директория модуля у Вас должна быть именно с разделителем «.» иначе гуляйте лесом. При чем директория «olof.catalog.iblock» — является некорректной.
Господа из Битрикс на самом деле сделали нормальную штуку: позаботились об указании вендора в имени модуля, но я считаю это лишнее условие именования директории.
Автозагрузка неявно реагирует на классы вида «ElementTable» удаляя постфикс, транслируя их в файлы «element.php». Собственно, из-за этого, вы не можете создать класс с именем Table.
Также загрузить классы из модулей, которые в данный момент не подключены (includeModule) – нельзя.
Рассмотрим пример работы Битриксового варианта: имеем модуль «olof.iblock» и соответствующий файл include.php:
namespace Olof\Iblock; use Bitrix\Main\Loader; // подключаем модуль Loader::includeModule("Olof.Iblock"); // переопределяем стандартное поведение для класса Api Loader::registerAutoLoadClasses("Olof.Iblock", [ "\Olof\Classes\Api" => ". /modules/Olof.Iblock/classes/api.php", ]); // Примеры доступа к классам: // Olof\Iblock\Element -> ./modules/Olof.Iblock/lib/Element.php // Olof\Classes\Api -> ./modules/Olof.Iblock/classes/api.php // Olof\Classes\Help -> ./modules/Olof.Classes/lib/Help.php
Слишком много неявностей и условий на мой взгляд. Да и никто не знает, какую глупость Битрикс завтра придумают. А придумать им стоит указание директории для префикса пространства имен (как в PSR-4) и тогда будет круто. А пока есть Juggernaut ;-)
ActiveRecord
Для удобства работы с сущностями, а в частности с инфоблоками, реализован шаблон ActiveRecord. На данный момент AR базируется (по факту является надстройкой) на битриксовых DataMapper’ах, в дальнейшем планируется полный перенос на независимый ORM / DAO.
Ниже представлен пример работы с инфоблоками через AR, охвачены практически все, имеющиеся на данный момент, методы.
Код
use Jugger\Db\Orm\Ib\Iblock; use Jugger\Db\Orm\Ib\IblockSection; use Jugger\Db\Orm\Ib\IblockElement; /* * Получаем инфоблок */ $iblock = Iblock::getByPrimary(1); $iblock = Iblock::getRowByField("=ID", 1); $iblock = Iblock::getRow([ "filter" => [ "=ID" => 1, ], ]); $iblock = new Iblock($iblock); /** * Доступ к полям таблицы, возможен как к свойствам класса */ $iblock->NAME; $iblock->IBLOCK_TYPE_ID; /** * Дочерние элементы и разделы */ $iblock->getElements(); $iblock->getSections(); /* * Получить разделы инфоблока */ $sectionList = $iblock->getSections(); $sectionList = $iblock->getSections([ "order" => [ "NAME" => "ASC", ], ]); $sectionList = IblockSection::getListByField("=IBLOCK_ID", $iblock->ID); $sectionList = IblockSection::getList([ "filter" => [ "=IBLOCK_ID" => $iblock->ID, ], ]); /* * Получить дочерние разделы */ $section = new IblockSection($sectionList->fetch()); $section->getChilds(); // получить детей 1-ого уровня вложенности $section->getChilds(2); // получить детей до 2-ого уровня вложенности (вернется массив, в порядке вложенности потомков) $section->getChilds(0); // получить всех детей $section->getIblock(); // родительский инфоблок /* * Работа с элементами */ $elementList = $section->getElements(); while($element = $elementList->fetch()) { /* * Массив преобразуется в AR без дополнительного запроса к базе */ $element = new IblockElement($element); $element->getProperties(); // свойства элемента /* * Работа со свойствами */ $elementProperty = $element->getProperty(1); /* * значение свойства (оба вызова равносильны) */ $value = $elementProperty->VALUE; $value = $elementProperty->getValue(); /* * при получении значения любым из способов выше, * значение автоматически приводится к типу свойства одним из методов ниже */ $elementProperty->getValueRaw(); // значение без преобразования $elementProperty->getValueEnum(); // IblockPropertyEnum - значение элемента списка (L) $elementProperty->getValueFile(); // CFile::GetFileArray $elementProperty->getValueHtml(); // (string) HTML код $elementProperty->getValueElement(); // IblockElement - связный элемент (E) $elementProperty->getValueSection(); // IblockSection - связный раздел (G) $elementProperty->getValueNumber(); // (float) или (int) в зависимости от значения /* * Получить объект свойства */ $property = $elementProperty->getMeta(); $property->NAME; $property->HINT; }
Методы: getPrimary, getRow, getRowByField, getList, getListByField — идентичны для всех ActiveRecord.
Функционал AR на данный момент достаточно беден (например, нет перекрестного поиска по таблицам), но т. к. они являются оберткой над стандартными функциями, в методах «getList» и «getRow» можно использовать Битриксовые плюшки. После создания / заимствования нормального DAO, этот момент будет допилен.
Hermitage
Сильной стороной Битрикс, и я думаю многие согласятся, является его пользовательский интерфейс a.k.a. «Эрмитаж». Он очень удобен и гибок.
Ниже представлен пример работы с Эрмитажем:
Код
use Jugger\Db\Orm\Ib\IblockSection; use Jugger\Db\Orm\Ib\IblockElement; use Jugger\Ui\Hermitage; use Jugger\Ui\Hermitage\Icon; use Jugger\Context\UrlManager\Iblock; /* @var $this CBitrixComponentTemplate */ /* @var $component CBitrixComponent */ /* * Добавление кнопок "редактировать" и "удалить" для элементов и разделов */ $element = IblockSection::getByPrimary(1); Hermitage::addButtonEditIblockElement($this, $element); Hermitage::addButtonDeleteIblockElement($this, $element); $section = IblockSection::getByPrimary(1); Hermitage::addButtonEditIblockSection($this, $section); Hermitage::addButtonDeleteIblockSection($this, $section); /* * Добавление кнопок в тулбар компонента */ Hermitage::addButton( $component, Iblock::getElementCreateUrl(1), "Добавить элемент", [ "ICON" => Icon::TOOLBAR_CREATE, ] ); /* * Добавление кнопок в верхнюю панель */ Hermitage::addPanelButton("#", "Надпись", [ "ICON" => Icon::PANEL_TRANSLATE, ]);
Так похвалил и так мало написал)) На самом деле этого достаточно для взаимодействия с пользователем. Очень много нужно реализовать касаемо административного интерфейса, но это уже не Эрмитаж, и это все в планах.
Безопасность
В Битрикс на сколько я знаю (а в данном вопросе, скрывать не буду, я особо не ковырялся), с безопасностью сайта (именно в коде) вообще грустно (только защита от SI). В будущем данный раздел будет содержать в себе инструменты для защиты от различных атак и вредоносных действий (XSS, генерация случайных данных, различные крипто-функции, валидация форм, работа с паролями, …). На данный момент реализован только инструментарий для защиты от CSRF:
use Jugger\Security\Csrf; /* * "автоматический" режим */ if (Csrf::validateTokenByPost()) { // ok } else { // error } echo Csrf::printInput(); /* * "ручной" режим */ $nameField = "csrf"; $token = Bitrix\Main\Context::getCurrent()->getRequest()->getPost($nameField); if (Csrf::validateToken($token)) { // ok } else { // error } $token = Csrf::createToken(); echo "<input type='hidden' name='{$nameField}' value='{$token}'>";
После каждой проверки (удачно или неудачной) – токен из сессии удаляется, таким образом проверить токен можно только один раз.
UrlManager
Маршрутизация в Битрикс, не сказал бы что на высоте, поэтому и эта область затронута в Juggernaut. Данный класс позволяет динамически создавать и использовать URL маршруты (используется в компонентах-роутерах).
Рассмотрим пример парсинга и генерирования URL:
Код
use Jugger\Context\UrlManager; /* * Установка базового URL и маршрутов */ UrlManager::setBaseUrl("/catalog"); UrlManager::addAlias("sectionList", "index.php"); UrlManager::addAlias("elementList", "#SECTION_CODE#/"); UrlManager::addAlias("elementView", "#SECTION_CODE#/#ELEMENT_CODE#/"); /* * Получаем запрашиваемый 'alias' на основе запроса * Например, для запроса '/catalog/section1/element1/' будет получен маршрут 'elementView' */ $alias = UrlManager::parseRequest(); /* * Аналог используя старые фукнции (хотя по сути UrlManager тоже их использует, просто это сокрыто в недрах) */ $folder404 = "/catalog"; $arUrlTemplates = [ "sectionList" => "index.php", "elementList" => "#SECTION_CODE#/", "elementView" => "#SECTION_CODE#/#ELEMENT_CODE#/", ]; $arVariables = []; // UrlManager::$params CComponentEngine::parseComponentPath($folder404, $arUrlTemplates, $arVariables); /* * Добавляем параметры маршрутов в систему */ UrlManager::addParams([ "param1" => "value1", "param2" => "value2", ]); /* * Получаем сгенерированый URL. * Параметры указанные в данном методе будут использоваться локально. * После выполнения метода параметр "ELEMENT_CODE" - не будет доступен */ UrlManager::addParam("SECTION_CODE", "section1"); $url = UrlManager::build("elementView", [ "ELEMENT_CODE" => "element1", ]); // $url: /catalog/section1/element1/
В дальнейшем планируется также подвязаться и к urlRewrite.php.
События
Данный класс является просто оберткой над функциями D7, с более удобным использованием.
use Jugger\Helper\Event; /* * добавление обработчика */ Event::on("имя события", function(){ // обработчик }); Event::on("имя события", "\ClassName::MethodName", "moduleName"); /* * удаление обработчиков */ Event::off("имя события"); Event::off("имя события", 3); // удалить 4-ий по счету (с нуля) обработчик /* * Вызов события */ Event::trigger("имя события"); /* * Вызов события с указанием сендера (вызывателя) */ Event::trigger("имя события", $this);
Что дальше?
Планы на ближайшее будущее:
- нормальный QueryBuilder
- нормальное кеширование
- нормальный AssetsManager
- набор компонентов для создания и работы с административным интерфейсом
- нормальная маршрутизация (завязанная на HttpException)
Заключение
Много чего задумано, много чего не сделано. Библиотека развивается по мере моей необходимости, поэтому очень зависит от текущих заказов (которое очень часто однотипны) и свободного времени.
Как я уже сказал вначале, проект будет развиваться несмотря ни на что, от количества ее авторов и заинтересованных лиц зависит лишь скорость развития. Так что выбор только за вами:
- ныть, ждать и подстраиваться под Bitrix (а развитие BitrixFramework явно не в приоритете);
- взять все в свои руки и помочь в развитии Juggernaut.
Помочь может каждый желающий филантроп (а иначе никак), для этого нужно:
- поделиться идеей
- рефакторить то что есть
- сделать что-нибудь своими ручками
Проект лежит на GitHub, так что править, добавлять, комментировать и спрашивать может любой желающий.
Спасибо за внимание! Конструктивная критика очень даже приветствуется :-)
P.S. комментарии типа «да на фиг Битрикс» огромная просьба не писать. Я в курсе какое у людей отношение к этой системе, и данный проект как раз направлен на ее облагораживание. Поэтому если вы считаете что «лучше и проще сделать проект на любом фреймворке» — то я это знаю и очень рад за вас, поэтому оставьте свое мнение при себе. Спасибо!
Репозиторий: github.com/irpsv/juggernaut.bitrix_release
Маркетплейс: скоро будет
