Валидация в контроллерах

Валидация входящих данных — обязательный этап не только для слоя бизнес-функций, но и обработки HTTP-запроса. Она гарантирует, что запрос с несоответствующими ожидаемым форматам и правилам параметры будет остановлен с ошибкой раньше.

Передача валидации на уровень контроллера (с использованием PHP-атрибутов и встроенного механизма) позволяет избавиться от ручных проверок внутри методов. Это делает код чище, снижает риск ошибок и гарантирует унифицированный формат ответов с ошибками для клиентской части.

Валидация простых типов данных

Для проверки скалярных значений (чисел, строк) достаточно добавить атрибут валидации к аргументу метода действия. Рассмотрим пример, где идентификатор пользователя должен быть положительным числом.

Ручная проверка (устаревший подход):

class AwardController extends Controller
{
    public function getByUserIdAction(int $userId): array
    {
        $awards = [];

        if ($userId <= 0) {
            throw new Exception("Неправильно указан идентификатор пользователя");
        }

        // Логика получения данных...

        return $awards;
    }
}

Валидация через атрибуты:

Используйте атрибут #[PositiveNumber]. Контроллер автоматически проверит значение до выполнения метода.

use Bitrix\Main\Validation\Rule\PositiveNumber;

class AwardController extends Controller
{
    public function getByUserIdAction(
        #[PositiveNumber]
        int $userId
    ): array
    {
        $awards = [];

        // Логика получения данных...

        return $awards;
    }
}

Если валидация не пройдет, метод не выполнится, а клиент получит ошибку в стандартном формате.

Пример AJAX-запроса с невалидными данными:

BX.ajax.runAction(
    'fusion:badge.Award.getByUserId',
    {
        data: {
            userId: -1
        }
    }
);

Ответ сервера:

{
    "status":"error",
    "data":null,
    "errors":[
        {
            "message":"Invalid value to match parameter: [userId] Значение поля должно быть не меньше, чем 1.",
            "code":100,
            "customData":null
        }
    ]
}

Автоматическая валидация через AutoWire

Чтобы избежать ручного заполнения DTO (Data Transfer Object) из запроса в каждом действии, используется механизм AutoWire с параметром ValidationParameter.

use Bitrix\Main\HttpRequest;
use Bitrix\Main\Validation\Rule\NotEmpty;
use Bitrix\Main\Validation\Rule\PhoneOrEmail;

final class CreateUserDto
{
    public function __construct(
        #[PhoneOrEmail]
        public ?string $login = null,

        #[NotEmpty]
        public ?string $password = null,

        #[NotEmpty]
        public ?string $passwordRepeat = null,
    ) {}

    public static function createFromRequest(HttpRequest $request): self
    {
        return new static(
            login: (string) $request->get('login'),
            password: (string) $request->get('password'),
            passwordRepeat: (string) $request->get('passwordRepeat'),
        );
    }
}

Затем подключите фабричный метод в контроллере через getAutoWiredParameters:

use Bitrix\Main\Validation\Engine\AutoWire\ValidationParameter;

class UserController extends Controller
{
    public function getAutoWiredParameters()
    {
        return [
            new ValidationParameter(
                CreateUserDto::class,
                fn() => CreateUserDto::createFromRequest($this->getRequest()),
            ),
        ];
    }

    public function createAction(CreateUserDto $dto): ?array
    {
        // Метод выполнится только если $dto прошел валидацию.
        // Иначе контроллер автоматически вернет ошибку.
        
        // Логика создания пользователя...
    }
}

Если данные в запросе не соответствуют правилам валидации, указанным в DTO, действие createAction не будет вызвано, а клиенту сразу вернется JSON с перечнем ошибок.