суббота, 29 сентября 2018 г.

Прерывание работы компонента на классе

При работе с компонентом иногда приходится прерывать работу компонента еще на стадии проверки входных параметров $arParams. Например, если вам требуется ИД инфоблока, а его не указано, то нет смысла заводить всю шарманку с кешированием и прочим, так как получать в общем-то нечего.

В компонентах, построенных на процедурном подходе в файле component.php это решалось приблизительно так:

if (!CModule::IncludeModule('iblock')) {
    ShowError(GetMessage("IBLOCK_MODULE_NOT_INSTALLED"));
    return;
}


В этом случае на странице выводилось красным текстом какое-либо сообщение, и страница продолжала свою работу.
Теперь давайте рассмотрим как реализовать сходное поведение в компоненте на классах (с файлом class.php вместо component.php).

Итак, когда вы наследуете свой класс для работы компонента от CBitrixComponent, то обычно в нем требуется переопределить как минимум два метода: onPrepareComponentParams($params) и executeComponent().

Так вот, в методе onPrepareComponentParams($params) обычно производятся все проверки входных параметров. Значит, мы можем в каких-то случаях понимать, что параметр передан не верный и... Что делать? Бросать исключение - не вариант. Во-первых, это не всегда критично, если в компонент не передали ИД инфоблока - ну и ладно, не выведем ничего, но последующие компоненты смогут отработать и что-то другое показать. А во-вторых: по-умолчанию ловить это исключение некому. Значит, в onPrepareComponentParams($params) попробуем собрать сообщения об ошибках в некий массив или объект и затем его обработать.

Так как после выполнения onPrepareComponentParams сразу выполняется executeComponent, то обрабатывать ошибки будем именно в executeComponent. Простейшее решение - просто обойти массив и вывести каждое ранее добавленное сообщение. Но мы же в новом битриксе, d7, oop, вот это всё. Поэтому и использовать будем иной подход.

Для хранения ошибок битрикс предлагает специальный объект Bitrix\Main\ErrorCollection. Для добавления новой ошибки используется метод setError, в качестве аргумента в него передается объект Bitrix\Main\Error. Получается как-то так:

if ($something_is_wrong) {
    $this->errorCollection->setError(
        new Error('SOMETHING IS WRONG')
    );
    // Можно сразу прекратить выполнение onPrepareComponentParams если ошибка серьезная
    // Если нет - то return можно опустить.
    return $params;
}


Также, объект ErrorCollection подерживает интерфейс Countable, поэтому число ошибок можно проверить просто через count($errorCollection). А затем просто пройтись по данному объекту циклом foreach (так как ErrorCollection поддерживает интерфейс Iterator) и вывести ошибки. После вывода ошибок можно со спокойной душой написать return и позволить последующим компонентам работать.

Примерный код метода executeComponent:

public function executeComponent()
{
    if (count($this->errorCollection)) {
        /** @var Error $error */
        foreach ($this->errorCollection as $error) {
            $code = $error->getCode();
            if ($code === self::SEVERE_ERROR) {
                // Если ошибка серьезная - то можно показать например 404-ю
            } elseif ($code === self::ALARM_ERROR) {
                ShowError($error->getMessage());
            }
        }
        // Заканчиваем выполнение компонента
        return;
    }

    // Продолжаем выполнение компонента
    //...
}


Полный код можно стянуть с гиста или подсмотреть в классе Bitrix\Iblock\Component\Base.

Комментариев нет:

Отправить комментарий