Вы можете создать собственный валидационный фильтр путем расширения базового класса фильтра, Constraint. Например, вы собираетесь создать простой валидатор, который проверяет, содержит ли строка только буквы и цифры.
Создание класса фильтра
Прежде всего, необходимо создать класс фильтра и отнаследоваться от Constraint
:
// src/AppBundle/Validator/Constraints/ContainsAlphanumeric.php namespace AppBundle\Validator\Constraints; use Symfony\Component\Validator\Constraint; /** * @Annotation */ class ContainsAlphanumeric extends Constraint { public $message = 'The string "%string%" contains an illegal character: it can only contain letters or numbers.'; }
Аннотации @Annotation
необходимые для этого нового ограничения для того,
чтобы сделать его доступным для использования в классах через аннотации.
Опции для вашего фильтра представлены в качестве открытых свойств класса фильтра.
Создание самого валидатора
Как вы можете видеть, ограничение класса довольно минимальны. Фактическая проверка осуществляется другим классом «constraint validator». Класс фильтра валидатора, содержит метод валидатора validatedBy(), который, по умолчанию, содержит в себе некий простой код:
// in the base Symfony\Component\Validator\Constraint class public function validatedBy() { return get_class($this).'Validator'; }
Другими словами, если вы создаете пользовательский ограничение (например, MyConstraint), Symfony будет автоматически искать другой класс, MyConstraintValidator, который, фактически выполняет проверку.
Класс проверки также прост, и имеет только один обязательный метод validate():
// src/AppBundle/Validator/Constraints/ContainsAlphanumericValidator.php namespace AppBundle\Validator\Constraints; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; class ContainsAlphanumericValidator extends ConstraintValidator { public function validate($value, Constraint $constraint) { if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) { // If you're using the new 2.5 validation API (you probably are!) $this->context->buildViolation($constraint->message) ->setParameter('%string%', $value) ->addViolation(); // If you're using the old 2.4 validation API /* $this->context->addViolation( $constraint->message, array('%string%' => $value) ); */ } } }
Внутри validate
, вам не нужно возвращать значение. Вместо этого, вы добавляете варианты нарушений проверок в свойства context
валидатора и значение будет считаться действительным, если оно не вызывает каких-либо нарушений. Метод buildViolation принимает сообщение об ошибке в качестве аргумента и возвращает экземпляр ConstraintViolationBuilderInterface. Вызов метода addViolation, наконец, добавляет нарушение в контекст.
Способ buildViolation был добавлен в Symfony 2.5. Примеры использования
с более старыми версиями Symfony приведены на соответствующих этой версии
странице документации.
Использование нового валидатора
Использовать пользовательские валидаторы очень легко, так же, как и встроенные в Symfony:
// src/AppBundle/Entity/AcmeEntity.php use Symfony\Component\Validator\Constraints as Assert; use AppBundle\Validator\Constraints as AcmeAssert; class AcmeEntity { // ... /** * @Assert\NotBlank * @AcmeAssert\ContainsAlphanumeric */ protected $name; // ... }
Если ваш ограничение содержит параметры, то они должны быть открытыми свойствами пользовательского класса Constraint, который вы создали ранее. Эти параметры могут быть настроены как параметры ограничений для ядра Symfony.
Ограничение валидаторов с зависимостями
Если ваш валидатор имеет зависимости, например, подключения к базе данных, он должен быть настроен в качестве службы контейнера внедрения зависимостей. Эта служба должна включать в себя тег validator.constraint_validator и атрибут псевдоним:
# app/config/services.yml services: validator.unique.your_validator_name: class: Fully\Qualified\Validator\Class\Name tags: - { name: validator.constraint_validator, alias: alias_name }
Теперь Ваш класс ограничения должны использовать этот псевдоним, чтобы ссылаться на соответствующий валидатор:
public function validatedBy() { return 'alias_name'; }
Как упоминалось выше, Symfony будет автоматически искать класса ограничения, содержащий соответствующие средства проверки. Если ваш валидатор указан в качестве службы, важно переопределить метод validatedBy () для возврата псевдонима, который использоваться при определении вашего сервиса, в противном случае Symfony не будет использовать ваш сервис, и экземпляр класса будет использоваться без указанных зависимостей.
Класс Constraint Validator
Кроме проверки свойств класса, ограничение может иметь область , указывающую на своей Constraint класс:
public function getTargets() { return self::CLASS_CONSTRAINT; }
При этом, метод validate()
валидатора получает объект в качестве первого аргумента:
class ProtocolClassValidator extends ConstraintValidator { public function validate($protocol, Constraint $constraint) { if ($protocol->getFoo() != $protocol->getBar()) { // If you're using the new 2.5 validation API (you probably are!) $this->context->buildViolation($constraint->message) ->atPath('foo') ->addViolation(); // If you're using the old 2.4 validation API /* $this->context->addViolationAt( 'foo', $constraint->message, array(), null ); */ } } }
Обратите внимание, что ограничение класса валидатора применяется для самого класса, а не для его свойства:
# src/AppBundle/Resources/config/validation.yml AppBundle\Entity\AcmeEntity: constraints: - AppBundle\Validator\Constraints\ContainsAlphanumeric: ~
Спасибо. Еще бы добавить подсветку синтаксиса.