Documentação do Symfony2
Renderizada do repositório symfony-docs-pt-BR no Github
Você pode criar uma constraint personalizada estendendo uma classe base de constraint Symfony\Component\Validator\Constraint. Como exemplo vamos criar um validador simples que verifica se uma string contém apenas caracteres alfanuméricos.
Primeiro você precisa criar uma classe de Constraint e estender Symfony\Component\Validator\Constraint:
// src/Acme/DemoBundle/Validator/constraints/ContainsAlphanumeric.php
namespace Acme\DemoBundle\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.';
}
Note
A annotation @Annotation é necessária para esta nova constraint para torná-la disponível para uso em classes através de annotations. Opções para a sua constraint são representadas como propriedades públicas na classe constraint.
Como você pode ver, uma classe de constraint é muito curta. A validação real é realizada por uma outra classe “validadora de constraint”. A classe validadora de constraint é especificada pelo método de constraint validatedBy(), que inclui alguma lógica padrão simples:
// in the base Symfony\Component\Validator\Constraint class
public function validatedBy()
{
return get_class($this).'Validator';
}
Em outras palavras, se você criar uma Constraint personalizada (Ex. MyConstraint), o Symfony2 automaticamente irá procurar a outra classe MyConstraintValidator quando realmente executar a validação.
A classe validadora também é simples, e só contém um método necessário: isValid:
// src/Acme/DemoBundle/Validator/Constraints/ContainsAlphanumericValidator.php
namespace Acme\DemoBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class ContainsAlphanumericValidator extends ConstraintValidator
{
public function isValid($value, Constraint $constraint)
{
if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) {
$this->setMessage($constraint->message, array('%string%' => $value));
return false;
}
return true;
}
}
Note
Não esqueça de chamar setMessage para construir uma mensagem de erro quando o valor for inválido.
Usar validadores personalizados é muito fácil, assim como os fornecidos pelo Symfony2 em si:
Se a sua constraint contém opções, então elas devem ser propriedades públicas na classe Constraint personalizada que você criou anteriormente. Essas opções podem ser configuradas como opções nas constraints do núcleo do Symfony.
Se o seu validador de restrição possui dependências, como uma conexão de banco de dados, ela terá que ser configurada como um serviço no container de injeção de dependência. Este serviço deve incluir a tag validator.constraint_validator e um atributo alias:
Sua classe de constraint pode agora usar este alias para referenciar o validador apropriado:
public function validatedBy()
{
return 'alias_name';
}
Como mencionado acima, o Symfony2 irá procurar automaticamente por uma classe chamada após a constraint, com Validator acrescentado. Se o seu validador constraint está definido como um serviço, é importante que você sobrescreva o método validatedBy() para retornar o alias utilizado na definição de seu serviço, caso contrário, o Symfony2 não vai usar o serviço do validador de constraint, e, em vez disso, irá instanciar a classe, sem quaisquer dependências injetadas.
Junto da validação de uma propriedade de classe, uma constraint pode ter um escopo de classe, fornecendo um alvo:
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
Com isso, o método validador isValid() obtém um objeto como seu primeiro argumento:
class ProtocolClassValidator extends ConstraintValidator
{
public function isValid($protocol, Constraint $constraint)
{
if ($protocol->getFoo() != $protocol->getBar()) {
$propertyPath = $this->context->getPropertyPath() . 'foo';
$this->context->setPropertyPath($propertyPath);
$this->context->addViolation($constraint->getMessage(), array(), null);
return false;
}
return true;
}
}
Note que a classe constraint validadora é aplicada na classe em si, e não à propriedade: