Laravel валидация boolean: проверка флагов на true
Как правильно настроить валидацию в Laravel Form Request для проверки boolean флагов на true. Почему in:true не работает с FormData и JSON, и как использовать prepareForValidation с filter_var для надежной проверки.
Как правильно настроить валидацию в Laravel для проверки, что значение поля равно true? В моем Form Request классе я использую следующие правила:
public function rules(): array
{
return [
'flag1' => ['required', 'in:true'],
'flag2' => ['required', 'in:true'],
'flag3' => ['required', 'in:true'],
'flag4' => ['required', 'in:true'],
];
}
Подходит ли такой подход для проверки, что все четыре флага установлены в true? Я заметил, что при отправке в FormData просто true валидация проходит успешно, но при отправке строки "true" (в кавычках) - нет. Однако при отправке JSON вида:
{
"flag1": "true"
}
валидация проходит, хотя это тоже строка. Почему такое поведение и как правильно реализовать валидацию для булевых значений в Laravel?
Использовать правило in:true для проверки, что поле равно true — ненадёжно: сравнение зависит от типа и формата входных данных (FormData / application/json). Для корректной laravel валидация boolean-флагов нормализуйте вход (например, в prepareForValidation() с filter_var) и затем проверяйте через правило boolean/accepted или через кастомное правило, которое явно требует true. Это уберёт разницу между строками "true", числами 1 и настоящим булевым true.
Содержание
- Как работает правило boolean в Laravel
- Почему
in:trueдаёт неожиданные результаты (FormData vs JSON) - Надёжные способы проверки: prepareForValidation, кастомное Rule, accepted
- Примеры кода (FormRequest и кастомное правило)
- Рекомендации по отправке данных с клиента
- Источники
- Заключение
Как работает правило boolean в Laravel
Правило boolean в документации Laravel описано как проверка, что поле может быть приведено к логическому типу: “Accepted input are true, false, 1, 0, “1”, and “0”.” Это означает, что Laravel ожидает значения вроде true, false, 1, 0, "1", "0" и приведёт совместимые значения к boolean перед дальнейшей обработкой — подробнее в документации Laravel и в русской версии laravel.su.
Правило in — другое: оно проверяет, что значение равно одному из перечисленных параметров (либо строка, либо значение, зависящее от типов). Это делает in:true хрупким решением: всё зависит от того, как именно пришло значение (строка "true", булево true, строка с кавычками "\"true\"" и т.д.). Сообщество неоднократно обсуждало неоднозначности поведения boolean-валидации в разных сценариях — см. обсуждение на Stack Overflow и на GitHub.
Почему in:true даёт неожиданные результаты для FormData и JSON
Коротко: всё зависит от типа, который попадает в PHP. Два ключевых момента:
- FormData / application/x-www-form-urlencoded: браузер присылает значения как строки. В JS
formData.append('flag', true)превращаетtrueв строку"true". Если вы случайно добавите лишние кавычки (например,formData.append('flag', '"true"')) — в запрос попадёт строка с кавычками и сравнение не пройдёт. - application/json: если клиент отправил JSON и значение без кавычек —
{ "flag": true }— тоjson_decodeвыдаст в PHP булевоtrue. Если же вы отправили{ "flag": "true" }, то это строка"true".
Пример клиента (FormData):
const fd = new FormData();
fd.append('flag1', true); // отправится как "true"
fd.append('flag2', 'true'); // отправится как "true"
fd.append('flag3', '"true"'); // отправится как "\"true\"" — опасно
Пример клиента (JSON):
fetch('/api/flags', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ flag1: true }) // булевое true
});
Итог: in:true иногда проходит и иногда нет, потому что сервер может получать либо булево, либо строку, либо строку с лишними символами. Поэтому полагаться на in:true для API, где формат входа меняется, — плохая идея. На эту проблему указывает и обсуждение на Stack Overflow.
Надёжные способы: prepareForValidation, кастомное Rule, accepted
Ниже — рабочие подходы, упорядоченные от простого к надёжному.
- Нормализация в prepareForValidation()
- Приведите вход к boolean до валидации с помощью PHP
filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)— он распознаёт"1","true","on","yes"как true и"0","false","off","no"как false; с флагомFILTER_NULL_ON_FAILUREвозвращаетnullдля некорректных значений (хорошо для детекции ошибок). Практический пример и обсуждение такого подхода есть в статье Echebaby.
- Использовать правило
boolean+ строгую проверку
- После нормализации в
prepareForValidation()можно применить правилоbooleanи затем требовать=== trueс помощью замыкания илиRule-класса.
- Кастомное правило (implements Rule)
- Реализуйте Rule, которое внутри использует
filter_var(..., FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)и возвращает true только если именноtrue. Это централизует логику и делает код читаемым.
- Правило
accepted
- Для HTML-checkbox/тогглов удобнее
accepted— оно принимаетyes,on,1,true. Но помните:acceptedориентировано на формы, не на произвольные API-пейлоады.
- Валидация после приведения (withValidator/after)
- Можно проверить все четыре флага сразу в
withValidator()и добавить ошибки, если какой-то флаг не равенtrue.
Замечание: в разных версиях и контекстах поведение boolean/in обсуждалось (см. GitHub issue), поэтому нормализация на вашей стороне — самый устойчивый путь.
Примеры кода (FormRequest и кастомное правило)
Пример FormRequest с нормализацией и строгой проверкой:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class FlagsRequest extends FormRequest
{
protected array $flags = ['flag1', 'flag2', 'flag3', 'flag4'];
protected function prepareForValidation(): void
{
$data = [];
foreach ($this->flags as $f) {
$value = $this->input($f, null);
// NULL при ошибке парсинга, true/false при валидных значениях
$data[$f] = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
$this->merge($data);
}
public function rules(): array
{
// теперь в $this->input($f) будут true/false/null
return array_combine($this->flags, array_map(fn() => ['required', 'boolean', function($attr, $val, $fail) {
if ($val !== true) {
$fail("Поле {$attr} должно быть true.");
}
}], $this->flags));
}
}
Кастомное правило (короткая версия):
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class IsTrue implements Rule
{
public function passes($attribute, $value): bool
{
return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === true;
}
public function message(): string
{
return 'Поле :attribute должно быть true.';
}
}
Использование в правилах:
'flag1' => ['required', new \App\Rules\IsTrue()],
// аналогично для flag2..flag4
Рекомендации по отправке данных с клиента
- Для API: предпочтительнее JSON и реальные булевы значения. Пример:
fetch(…, { body: JSON.stringify({ flag1: true }) }) — тогда Laravel получит булевtrue. - Для FormData/старых форм: отправляйте однозначные значения, например
'1'или'on', и нормализуйте на сервере. HTML-галочка по умолчанию отправляетon. - Всегда логируйте или делайте
dd($request->all()), если поведение кажется странным — так вы увидите, что реально пришло на сервер. - Не отправляйте строки с кавычками внутри (например
"\"true\""), это частая ошибка при сериализации.
Источники
- Validation - Laravel 11.x - The PHP Framework For Web Artisans
- Validating boolean with Laravel Validation - Stack Overflow
- Laravel validate ‘true’ and ‘false’ as booleans — Echebaby blog
- Валидация Laravel 12.x (laravel.su)
- Boolean validation does not accept “true” and “false”, but accepts “1”, “0” — GitHub
Заключение
Коротко: in:true — ненадёжный способ для проверки булевых флагов, потому что формат и тип данных зависят от клиента (FormData vs JSON). Для корректной laravel валидация нормализуйте вход (prepareForValidation с filter_var или кастомное Rule) и затем требуйте true (через boolean + замыкание или Rule, или через accepted для чекбоксов). Сделав нормализацию, вы получите устойчивую и предсказуемую валидацию вне зависимости от того, приходит ли "true", 1 или настоящий булев true.