Schema: валидация данных
Практичная библиотека для проверки и нормализации структур данных по заданной схеме с интеллектуальным и простым в понимании API.
Установка:
Использование
В переменной $schema
у нас есть схема валидации (что именно это
значит и как её создать, мы расскажем позже), а в переменной $data
у
нас есть структура данных, которую мы хотим валидировать и
нормализовать. Это могут быть, например, данные, отправленные
пользователем через API, конфигурационный файл и т. д.
Задачей занимается класс Nette\Schema\Processor, который обрабатывает входные данные и либо возвращает нормализованные данные, либо выбрасывает исключение Nette\Schema\ValidationException при ошибке.
Метод $e->getMessages()
возвращает массив всех строк сообщений, а
$e->getMessageObjects()
возвращает все сообщения в виде объектов Nette\Schema\Message.
Определение схемы
А теперь давайте создадим схему. С помощью класса Nette\Schema\Expect мы фактически
определяем, как должны выглядеть данные. Предположим, что входные
данные должны представлять собой структуру (например, массив),
содержащий элементы processRefund
типа bool и refundAmount
типа int.
Мы считаем, что определение схемы выглядит понятным, даже если вы видите его в первый раз.
Отправим следующие данные для проверки:
Выход, т. е. значением $normalized
, является объект stdClass
. Если
мы хотим, чтобы результатом был массив, мы добавляем приведение к схеме
Expect::structure([...])->castTo('array')
.
Все элементы структуры являются необязательными и имеют значение по
умолчанию null
. Пример:
Тот факт, что значением по умолчанию является null
, не означает,
что оно будет принято во входных данных 'processRefund' => null
. Нет,
входные данные должны быть булевыми, т. е. только true
или
false
. Нам пришлось бы явно разрешить null
через
Expect::bool()->nullable()
.
Элемент можно сделать обязательным, используя
Expect::bool()->required()
. Мы меняем значение по умолчанию на false
,
используя Expect::bool()->default(false)
или коротко Expect::bool(false)
.
А что если мы захотим принимать 1
и 0
помимо булевых
чисел? Перечислим допустимые значения, которые мы также нормализуем в
boolean:
Теперь вы знаете основы того, как определяется схема и как ведут себя отдельные элементы структуры. Теперь мы покажем, какие ещё элементы могут быть использованы при определении схемы.
Типы данных: type()
Все стандартные типы данных PHP могут быть перечислены в схеме:
А затем все типы, поддерживаемые
валидаторами через Expect::type('scalar')
или сокращенно
Expect::scalar()
. Также принимаются имена классов или интерфейсов,
например: Expect::type('AddressEntity')
.
Вы также можете использовать нотацию объединения:
Значение по умолчанию всегда null
, за исключением array
и
list
, где это пустой массив. (Список — это массив, индексированный
в порядке возрастания числовых ключей от нуля, то есть неассоциативный
массив).
Массив значений: arrayOf() listOf()
Массив — слишком общая структура, полезнее указать, какие именно элементы он может содержать. Например, массив, элементами которого могут быть только строки:
Второй параметр может использоваться для указания ключей (начиная с версии 1.2):
Список представляет собой индексированный массив:
Параметр также может быть схемой, поэтому мы можем написать:
Значение по умолчанию — пустой массив. Если вы укажете значение по
умолчанию, оно будет объединено с переданными данными. Это можно
отключить с помощью mergeDefaults(false)
(начиная с версии 1.1).
Перечисление: anyOf()
anyOf()
— это набор значений или схем, которыми может быть
значение. Вот как записать массив элементов, которые могут быть либо
'a'
, либо true
, либо null
:
Элементы перечисления также могут быть схемами:
Метод anyOf()
принимает варианты как отдельные параметры, а не
как массив. Чтобы передать ему массив значений, используйте оператор
распаковки anyOf(...$variants)
.
Значение по умолчанию — null
. Используйте метод
firstIsDefault()
, чтобы сделать первый элемент элементом по
умолчанию:
Структуры
Структуры — это объекты с определенными ключами. Каждая из этих пар ключ ⇒ значение называется „свойством“:
Структуры принимают массивы и объекты и возвращают объекты
stdClass
.
По умолчанию все свойства являются необязательными и имеют значение
по умолчанию null
. Вы можете определить обязательные свойства,
используя required()
:
Если вы не хотите выводить свойства только со значением по умолчанию,
используйте skipDefaults()
:
Хотя null
является значением по умолчанию свойства optional
,
оно не допускается во входных данных (значение должно быть строкой).
Свойства, принимающие значение null
, определяются с помощью
nullable()
:
Массив всех свойств структуры возвращается методом getShape()
.
По умолчанию, во входных данных не может быть лишних элементов:
Подобные элементы изменить с помощью otherItems()
. В качестве
параметра мы укажем схему для каждого дополнительного элемента:
Вы можете создать новую структуру, производя ее от другой с помощью
extend()
:
Массив
Массив с определенными ключами. Применяются те же правила, что и для структур.
Вы также можете определить индексированный массив, известный как кортеж:
Устаревшие элементы
Вы можете объявить свойство устаревшим, используя метод
deprecated([string $message])
. Уведомления об устаревании возвращаются с
помощью $processor->getWarnings()
:
Диапазоны: min() max()
Используйте min()
и max()
для ограничения количества
элементов в массивах:
Для строк ограничивает их длину:
Для чисел ограничивает их значение:
Конечно, можно упомянуть только min()
, или только max()
:
Регулярные выражения: pattern()
Используя pattern()
, вы можете указать регулярное выражение,
которому должна соответствовать вся входная строка (т.е. как если
бы она была завернута в символы ^
a $
):
Пользовательские утверждения: assert()
Вы можете добавить любые другие ограничения, используя
assert(callable $fn)
.
Или
Вы можете добавить собственное описание для каждого утверждения. Оно будет частью сообщения об ошибке.
Этот метод можно вызывать многократно для добавления нескольких
ограничений. Его можно смешивать с вызовами transform()
и
castTo()
.
Трансформация: transform()
Успешно подтвержденные данные могут быть изменены с помощью пользовательской функции:
Этот метод можно вызывать многократно для добавления нескольких
преобразований. Он может перемежаться с вызовами assert()
и
castTo()
. Операции будут выполняться в том порядке, в котором они
объявлены:
Метод transform()
может одновременно преобразовывать и проверять
значение. Это часто проще и менее избыточно, чем выстраивание цепочек
transform()
и assert()
. Для этого функция получает объект Context с методом addError()
,
который может быть использован для добавления информации о проблемах
валидации:
Кастинг: castTo()
Успешно проверенные данные могут быть приведены:
Помимо собственных типов PHP, можно также приводить данные к классам. При этом различается, является ли это простой класс без конструктора или класс с конструктором. Если класс не имеет конструктора, то создается его экземпляр и в его свойства записываются все элементы структуры:
Если класс имеет конструктор, то элементы структуры передаются конструктору в качестве именованных параметров:
Кастинг в сочетании со скалярным параметром создает объект и передает его значение в качестве единственного параметра конструктору:
Нормализация: before()
Перед самой проверкой данные могут быть нормализованы с помощью
метода before()
. В качестве примера, пусть есть элемент, который
должен быть массивом строк (например, ['a', 'b', 'c']
), но получает
входные данные в виде строки a b c
:
Отображение на объекты: from()
Из класса можно сгенерировать структурную схему. Пример:
Поддерживаются также анонимные классы:
Поскольку информации, полученной из определения класса, может быть недостаточно, можно добавить пользовательскую схему для элементов с помощью второго параметра: