Ajax
Контроллер
Контроллер должен наследоваться от Bitrix\Main\Engine\Controller.
Контроллер хранит коллекцию ошибок в свойстве errorCollection. Ошибка — объект класса \Bitrix\Main\Error.
Как добавлять ошибки:
$this->addError(\Bitrix\Main\Error $error)— принимает объект-ошибку$this->addErrors(array $errors)— принимает массив ошибок. Сокращение для$this->errorCollection->add()$this->errorCollection->add(array $errors)— принимает массив ошибок$this->errorCollection->setError(\Bitrix\Main\Error $error, $offset = null)— принимает объект-ошибку. С помощью$offsetможно заменить существующую ошибку в коллекции. Передачаnullдобавляет ошибку в конец коллекции- Обработка
\Throwable,\Exception,\Error:$this->runProcessingException(\Exception $exception)— получает\Bitrix\Main\Errorиз\Exceptionи добавляет эту ошибку в коллекциюerrorCollection$this->runProcessingError(\Error $error)— получает\Bitrix\Main\Errorиз\Errorи добавляет эту ошибку в коллекциюerrorCollection$this->runProcessingThrowable(\Throwable $t)— получает\Bitrix\Main\Errorиз\Throwableи добавляет эту ошибку в коллекциюerrorCollection
Метод buildErrorFromException позволяет сформировать \Bitrix\Main\Error из \Exception
class MyController extends \Bitrix\Main\Engine\Controller
{
public function myAction()
{
$this->addError(new \Bitrix\Main\Error('Ошибка через addError'));
// сокращение для $this->errorCollection->add
$this->addErrors([
new \Bitrix\Main\Error('message'),
new \Bitrix\Main\Error('message'),
]);
$this->errorCollection->add([
new \Bitrix\Main\Error('Первая ошибка'),
new \Bitrix\Main\Error('Вторая ошибка'),
]);
// с использованием setError()
$this->errorCollection->setError(new \Bitrix\Main\Error('Первая ошибка'));
$this->errorCollection->setError(new \Bitrix\Main\Error('Вторая ошибка'));
try {
// что-то происходит
} catch (\Throwable $t) {
$this->runProcessingThrowable($t);
}
}
}
Битрикс проверяет по наличию элементов в errorCollection и формирует объект-результат \Bitrix\Main\Engine\Response\AjaxJson.
Если errorCollection пустой — вернётся success.
Response
Получить объект $response можно так:
Конфигурирование экшенов
Необходимо переопределить метод configureActions. Метод должен вернуть массив элементов.
Ключ — название экшена без суффикса Action. Значение — массив.
use \Bitrix\Main\Engine\Controller;
class MyController extends Controller
{
public function configureActions(): array
{
return [
// для checkAction ключ имеет название check
'check' => [
'prefilters' => [],
'+prefilters' => [], // добавление префильтров к существующему набору
'postfilters' => [],
'+postfilters' => [],
],
];
}
public function checkAction()
{}
}
Префильтры и постфильтры содержат коллекцию ActionFilter, каждый из которых должен был наследником \Bitrix\Main\Engine\ActionFilter\Base::class.
Контроллер проходит по каждому объявленному фильтру, для каждого prefilters регистрирует событие:
$eventManager->addEventHandler(
'main',
'MyController::onBeforeAction',
[$filter, 'onBeforeAction']
);
Для каждого postfilters
$eventManager->addEventHandler(
'main',
'MyController::onBeforeAction',
[$filter, 'onAfterAction']
);
Поэтому Фильтр всю свою логику должен реализовывать в методах onBeforeAction и onAfterAction.
Для ошибки фильтр должен вернуть \Bitrix\Main\EventResult. При инициализации EventResult должен обязательно быть передан $handler, который должен реализовывать интерфейс \Bitrix\Main\Errorable, и который заполнит errorCollection ошибками. Например, передать себя.
То есть должны сработать оба условия:
- возвращается
EventResultтипаEventResult::ERROR - передан
$handlerс непустойerrorCollection
// Реализация ActionFilter для Контроллера
class MyActionFilter extends \Bitrix\Main\Engine\ActionFilter\Base
{
/**
* Метод onBeforeAction будет вызван до срабатывания основного Action
*
* @param $event
* @return \Bitrix\Main\EventResult
*/
public function onBeforeAction($event)
{
// Добавление ошибки через свой метод, который принимает объект-ошибку
$this->addError(new \Bitrix\Main\Error('Первая ошибка'));
// либо добавление ошибок через errorCollection
$this->errorCollection->add([
new \Bitrix\Main\Error('Первая ошибка через errorCollection');
new \Bitrix\Main\Error('Вторая ошибка через errorCollection');
]);
$this->errorCollection->setError(new \Bitrix\Main\Error('Ещё одна ошибка через errorCollection'));
// обязательно вернуть EventResult типа EventResult::ERROR
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::ERROR,
null,
null,
$this
);
}
}
// Пример контроллера, использующего MyActionFilter
class MyController extends \Bitrix\Main\Engine\Controller
{
public function configureActions(): array
{
return [
'test' => [
'prefilters' => [
new MyActionFilter(),
]
]
];
}
public function testAction()
{}
}
Дефолтные фильтры для своего контроллера
В контроллере есть метод getDefaultPreFilters, который возвращает набор предустановленных фильтров.
В битриксе прописан такой дефолтный набор:
Bitrix\Main\Engine\ActionFilter\AuthenticationBitrix\Main\Engine\ActionFilter\HttpMethodBitrix\Main\Engine\ActionFilter\Csrf
Использование prefilters затирает набор дефолтных префильтров.
Использование +prefilters и -prefilters вместо переопределения списка позволяет добавлять/удалять новые к дефолтному списку.
Переопределив метод getDefaultPreFilters в своём контроллере,
можно определить новый список дефолтных фильтров для всех Action своего контроллера при условии что в configureActions не будет использоваться prefilters, а только +prefilters и -prefilters.
Так например можно ввести Фильтр для контроллера, который на каждый Action будет проверять, что пользователь входит в определённую группу
class CheckUserGroupActionFilter extends \Bitrix\Main\Engine\ActionFilter\Base
{
private array $userGroups;
public function __construct(array $userGroups)
{
parent::__construct();
$this->userGroups = $userGroups;
}
public function onBeforeAction($event): ?\Bitrix\Main\EventResult
{
$currentUserGroups = \Bitrix\Main\Engine\CurrentUser::get()->getUserGroups();
if (empty(array_intersect($currentUserGroups, $this->userGroups))) {
// если текущий пользователь не входит в разрешенные группы
$this->addError(new \Bitrix\Main\Error('Access denied'));
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::ERROR,
null,
null,
$this
);
}
return null;
}
}
class MyController extends \Bitrix\Main\Engine\Controller
{
public function getDefaultPreFilters(): array
{
// дополняем дефолтный набор фильтров своими фильтрами
$defaultPreFilters = parent::getDefaultPreFilters();
// на все Экшены контроллера навешивается проверка, что пользователь входит в эти группы
$defaultPreFilters[] = new CheckUserGroupActionFilter([1, 2, 3]),
return $defaultPreFilters;
}
public function configureAction(): array
{
return [
// prefilters очистит набор предустановленных фильтров
'first' => ['prefilters' => []],
// +prefilters добавит указанные фильтры к предустановленному набору
'second' => ['+prefilters' => [new class extends \Bitrix\Main\Engine\ActionFilter\Base {} ]]
// -prefilters удаляет из набора фильтров те, которые относятся к переданным классам. Проверяется через is_a
'third' => ['-prefilters' => [Bitrix\Main\Engine\ActionFilter\HttpMethod::class]]
];
}
public function firstAction(){}
public function secondAction(){}
public function thirdAction(){}
}
prefilters, иначе перезатрёте предустановленный набор.