Валидация v1.1.0
Filter, Range, Regex, ArrayOf, PropertyValidator и ValidationException.
Введение
Правила проверки — PHP-атрибуты, реализующие Devcraft\Interfaces\ValidationRule. Метод validate() возвращает null, если значение подходит, иначе короткое сообщение без самого значения. Вход null всегда проходит: обязательность поля решает запасной путь mapper при заполнении из массива.
Зачем: одни и те же правила на DTO (AbstractReflection) и при ручной проверке через PropertyValidator.
Предварительные требования
Контракт правила
interface ValidationRule
{
/** null — ок; иначе сообщение без фактического значения. */
public function validate(mixed $value): ?string;
}Сообщения описывают ожидание (must be numeric), не фактическое значение. Пути полей и типы добавляют ReflectionMapper / ValidationException.
См. также: ValidationRule, PropertyValidator, ValidationException.
Атрибуты
Все атрибуты валидации вешаются на свойства и могут повторяться.
Filter
Обёртка над PHP filter_var:
use Devcraft\Attributes\Filter;
#[Filter(FILTER_VALIDATE_EMAIL)]
public string $email;
#[Filter(FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]])]
public int $quantity;Для FILTER_VALIDATE_BOOLEAN автоматически добавляется FILTER_NULL_ON_FAILURE, чтобы неверные значения отклонялись, а не превращались в false.
Сообщение при ошибке: must pass filter <id>.
См. Filter.
Range
Числовые границы для int или float:
use Devcraft\Attributes\Range;
#[Range(min: 1, max: 65535)]
public int $port;
#[Range(min: 0.0)]
public float $ratio;Любую границу можно опустить. Нечисловые значения → must be numeric.
См. Range.
Regex
Совпадение строки с шаблоном:
use Devcraft\Attributes\Regex;
#[Regex('/^[0-9a-f-]{36}$/i')]
public string $id;Конструктор проверяет шаблон через preg_match и бросает InvalidArgumentException, если выражение битое. Не-строка → must be a string.
См. Regex.
ArrayOf
Значение — список, элементы которого соответствуют имени типа:
use Devcraft\Attributes\ArrayOf;
#[ArrayOf('string')]
public array $tags;
#[ArrayOf(Address::class)]
public array $locations;Встроенные имена: mixed, string, int/integer, float/double, bool/boolean, array, object. Остальные — проверка class/interface через instanceof.
В ReflectionMapper ArrayOf ещё и управляет преобразованием элементов до валидации.
См. ArrayOf.
PropertyValidator
Devcraft\Validation\PropertyValidator запускает правила атрибутов без заполнения из массива:
use Devcraft\Validation\PropertyValidator;
use ReflectionProperty;
$validator = new PropertyValidator();
$errors = $validator->validateValue(
new ReflectionProperty(Profile::class, 'port'),
0,
);
// ['must be greater than or equal to 1']
$objectErrors = $validator->validateObject($profile);
// ['port' => [...], ...]validateObject() смотрит только public, не static, уже инициализированные свойства. Атрибуты не из ValidationRule игнорируются. Несколько правил на одном свойстве дают несколько сообщений.
ValidationException
Бросается ReflectionMapper, когда один или несколько обязательных путей не проходят:
use Devcraft\Exceptions\ValidationException;
try {
Profile::fromArray($payload);
} catch (ValidationException $exception) {
$exception->getMessage();
// "Validation failed for: port, address.city"
$exception->getErrors();
// [
// 'port' => ['must be greater than or equal to 1'],
// 'address.city' => ['must be string'],
// ]
}getErrors() возвращает array<string, list<string>>: ключ — путь свойства через точку.