Библиотека spaceonfire/bitrix-tools
предоставляет базовые классы, нацеленные на упрощение разработки собственных
компонентов Битрикс. Подробнее о технологии можно почитать в курсе Битрикса.
Эти классы реализуют проверка параметров и универсальный порядок выполнения с обработкой исключений.
Обычный компонент, предназначенный для работы с данными, представлен классом spaceonfire\BitrixTools\Components\BaseComponent
.
В первую очередь базовый компонент позволяет производить проверку переданных параметров на соответствие типа.
Чтобы задать правила проверки параметров компонента, необходимо перегрузить метод getParamsTypes()
.
Правила описываются в виде массива, ключами которого являются названия параметров, а значениями - объекты,
реализующие интерфейс spaceonfire\Type\Type
из библиотеки spaceonfire/type
.
Библиотека spaceonfire/type
предоставляет широкие возможности для описания ожидаемого типа параметра, например:
- Встроенные типы PHP (int, float и string могут быть указаны как не строгие с возможностью привидения к указанному типу)
- Проверка экземпляра класса (instanceof)
- Комбинирование типов (конъюнкция и дизъюнкция)
- Коллекционный тип, который проверяет итерируемые параметры на соответствие типов ключей и значений
use spaceonfire\BitrixTools\Components\BaseComponent;
use spaceonfire\Type\BuiltinType;
use spaceonfire\Type\DisjunctionType;
class MyComponent extends BaseComponent
{
protected function getParamsTypes(): array
{
return [
'REQUIRED_INT_PARAM' => new BuiltinType(BuiltinType::INT, false),
'REQUIRED_STRING_PARAM' => new BuiltinType(BuiltinType::STRING, false),
'NULLABLE_STRING_PARAM' => new DisjunctionType([
new BuiltinType(BuiltinType::STRING, false),
new BuiltinType(BuiltinType::NULL),
]),
];
}
}
Пример выше определяет следующие проверки типов для параметров:
REQUIRED_INT_PARAM
- обязательный целочисленный параметр с возможностью приведения значения. Т.е. если в параметр значение было передано в виде строки, например'42'
, оно будет приведено к целочисленному типу.REQUIRED_STRING_PARAM
- обязательный строковый параметр с возможностью приведения значения.NULLABLE_STRING_PARAM
- не обязательный строковый параметр с возможностью приведения значения. Проверяется, что параметр является строкой илиnull
.
Метод выполнения компонента executeComponent()
содержит следующий код:
try {
$this->run();
} catch (Throwable $e) {
$this->catchError($e);
}
return $this;
Как можно заметить выполнение компонента, происходит в методе run()
, его мы рассмотрим чуть позже. Любое исключение,
выброшенное в процессе выполнения будет обработано в catchError()
. И наконец возвращается текущий экземпляр компонента,
это позволяет использовать информацию из него после выполнения, например в другом компоненте:
/** @global $APPLICATION CMain */
$myFooComponent = $APPLICATION->IncludeComponent('my:foo.component', '', []);
$APPLICATION->IncludeComponent('my:bar.component', '', [
'FOO_DATA' => $myFooComponent->getSomeData(),
]);
Рассмотрим, что происходит в методе run()
, в порядке его выполнения:
includeModules()
- подключает модули, указанные в свойствеneedModules
класса компонента.init()
- инициализация компонентаexecuteProlog()
- пролог компонентаstartCache()
- запуск кэшированияexecuteMain()
- основная логика компонентаrender()
- подключение шаблона компонента. По-умолчанию рендер шаблона кэшируется. Чтобы кэшировалась только логика без шаблона, необходимо установить свойство компонентаcacheTemplate
=false
writeCache()
- запись результатов в кэш
render()
- подключение шаблона компонента, если кэширование шаблона отключено свойствомcacheTemplate
executeEpilog()
- эпилог компонента
Хотя перегрузка метода
executeComponent()
не рекомендуется, в редких случаях предлагаемый порядок выполнения может не подходить для компонента. Тогда это допустимо под ответственность разработчика.
Базовые компоненты используют исключения для контроля хода выполнения компонента и обработки непредвиденных ситуаций.
Если компонент не может продолжать свою работу, нужно выбросить исключение, которое будет перехвачено и обработано:
class MyComponent extends spaceonfire\BitrixTools\Components\BaseComponent
{
protected function executeProlog(): void
{
throw new RuntimeException('Some error occurred');
}
}
Обработка исключения происходит в методе catchError()
следующим образом:
- Во-первых, сбрасывается кэш
- Выставляется HTTP статус исходя из исключения,
можно выбросить исключение из библиотеки
narrowspark/http-status
- Вывод сообщения об ошибке
- Запись исключения в
ExceptionHandler
Битрикса
Заострим внимание на вывод сообщения об ошибке:
- Вывод основного сообщения об ошибке производится методом
renderExceptionMessage()
- По-умолчанию для обычных пользователей выводится общее сообщение об ошибке, а для админов - сообщение из исключения.
В каких ситуациях выводить сообщение из исключения можно определить в методе
canShowExceptionMessage()
- Далее при включенном режиме отладки для админов выводится трейс исключения. Переопределить, в каких ситуациях следует
показывать трейс, можно в методе
canShowExceptionTrace()
. А за вывод отвечает методrenderExceptionTrace()
Кеширование базового компонента включается автоматически, если ему передать соответствующие параметры CACHE_TYPE
и CACHE_TIME
.
Кешируется только метод executeMain()
и шаблон. Если кеширование шаблона необходимо отключить, нужно установить
свойство класса компонента cacheTemplate
в значение false
.
Базовый компонент может разделять кеш для разных групп пользователей.
Для этого установите параметр компонента CACHE_GROUPS = Y
.
Так же можно добавить дополнительный идентификатор кеша с помощью метода addCacheAdditionalId($id)
.
Для тегирования кэша компонента пользуйтесь методом registerCacheTag($tag)
. Пометив таким образом кеш,
в будущем его можно сбросить его по тегу:
Bitrix\Main\Application::getInstance()->getTaggedCache()->clearByTag('my-cache-tag');
Комплексный компонент, предназначенный для динамического роутинга между страницами,
представлен классом spaceonfire\BitrixTools\Components\BaseRouterComponent
.
Проверка параметров реализована так же, как и в простом базовом компоненте. См. выше.
Метод выполнения компонента executeComponent()
аналогичен простому базовому компоненту,
поэтому сразу перейдем к разбору метода run()
:
includeModules()
- подключает модули, указанные в свойствеneedModules
класса компонента.init()
- инициализация компонентаsetSefDefaultParams()
- установка параметров ЧПУ по-умолчаниюsetPage()
- определение запрошенной страницыexecuteProlog()
- пролог компонентаexecuteMain()
- основная логика компонента: в$arResult
добавляются полученные переменны запроса.render()
- подключение шаблона компонентаexecuteEpilog()
- эпилог компонента
Так как комплексные компоненты обычно реализуют только роутинг, а не работают с данными, то кэширование здесь не включается.
Обработка исключений реализована так же, как и в простом базовом компоненте. См. выше.
Для базовых компонентов библиотеки можно включить использование виртуальных свойств.
К таким свойствам можно обращаться как к обычным свойствам класса, только они хранятся в $arResult
компонента.
Такой подход позволяет отслеживать использование свойств в коде проекта, при этом сохраняя значения в кэше.
Для работы с виртуальными свойствами необходимо подключить к проекту библиотеку phpdocumentor/reflection-docblock
:
composer require phpdocumentor/reflection-docblock
После этого используем трейт spaceonfire\BitrixTools\Components\Property\ComponentPropertiesTrait
,
указываем виртуальные свойства в DocBlock и используем их:
// В компоненте: class.php
use spaceonfire\BitrixTools\Components\BaseComponent;
use spaceonfire\BitrixTools\Components\Property\ComponentPropertiesTrait;
/**
* My Component
*
* @property string $property
* @property-write int $writeProperty
* @property-read array $readProperty
*/
class MyComponent extends BaseComponent
{
use ComponentPropertiesTrait;
protected function executeMain(): void
{
parent::executeMain();
$this->property = 'Hello from component';
$this->writeProperty = 1;
$this->readProperty = [['id' => 42, 'name' => 'Main']];
}
}
// В шаблоне: template.php
/**
* @var MyComponent $component
*/
echo $component->property; // Hello from component
$component->property = 'Hello from template';
$component->writeProperty = 2;
var_dump($this->readProperty);
К виртуальным свойствам можно ограничить доступ: только на чтение (@property-read
) или только на запись (@property-write
).
Это ограничение не действует внутри класса компонента.