No Symfony, na minha opinião, uma funcionalidade muito conveniente para validação de entidade. Em particular, o uso do formato de anotação para configurar regras de validação realmente me suborna. Na grande maioria das tarefas, as soluções chave na mão cobrem casos padrão. Mas, como você sabe, a validação é uma questão delicada e você nunca sabe quais restrições terá que impor dessa vez. Por outro lado, uma validação mais flexível e bem pensada sempre ajudará a evitar erros do usuário.
Convidamos você a ver como é fácil escrever suas restrições e estender as comparações de dois campos disponíveis usando o exemplo de validação e validação básicas. O artigo pode ser de interesse para aqueles que ainda estão pouco familiarizados com a validação no Symfony ou que ignoraram a possibilidade de escrever seus próprios validadores.
Neste artigo, teremos em mente o contexto clássico de validação. Existe uma certa entidade, cujos dados são preenchidos no formulário correspondente, enquanto a validação impõe restrições a qualquer aspecto dos dados inseridos. Vale ressaltar que os validadores podem ser usados sem restrições para controlar a lógica interna, validação da API etc.
Determinamos imediatamente que os exemplos propostos não são as únicas soluções possíveis e não reivindicam ótima otimização ou uso extensivo, mas são oferecidos para fins de demonstração. Por outro lado, partes dos exemplos são tomadas e simplificadas em projetos de combate, e espero que possam ser úteis para ilustrar a simplicidade de escrever validações personalizadas sem interromper a realidade.
Validação básica
Para fazer uma validação totalmente funcional, você precisa criar apenas duas classes - os herdeiros de Constraint e ConstraintValidator. Restrição, como o nome indica, define e descreve as restrições, enquanto o ConstraintValidator as valida. Como exemplo, escreveremos um validador de hora no formato "hh: mm" armazenado em formato de texto. Na documentação oficial, propõe-se que o Constraint descreva as propriedades públicas da restrição. Então, vamos fazê-lo.
namespace App\Custom\Constraints;
use Symfony\Component\Validator\Constraint;
class TextTime extends Constraint
{
public $message = ' ';
}
Aqui, a anotação Target determina se a validação será usada: para uma propriedade ou para uma classe. Você também pode definir esse parâmetro substituindo a função.
public function getTargets()
{
return self::PROPERTY_CONSTRAINT;
}
A propriedade da mensagem, como você pode imaginar, é usada para exibir informações sobre um erro de validação.
, .
public function validatedBy()
{
return \get_class($this).'Validator';
}
, , ConstraintValidator. ConstraintValidator validate.
namespace App\Custom\Constraints;
use Symfony\Component\Validator\ConstraintValidator;
class TextTimeValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$time = explode(':', $value);
$hours = (int) $time[0];
$minutes = (int) $time[1];
if ($hours >= 24 || $hours < 0)
$this->fail($constraint);
else if ((int) $time[1] > 60 || $minutes < 0)
$this->fail($constraint);
}
private function fail(Constraint $constraint)
{
$this->context->buildViolation($constraint->message)
->addViolation();
}
}
, , , .
...
private $timeFrom;
...
, , . , , , message .
. , Symfony Time. : . , "hh:mm:ss". , .
, , - . , , : "hh:mm", "hh:mm"-"hh:mm". , , .
, AbstractComparsion. AbstractComparsion Constraint — .
namespace App\Custom\Constraints;
use Symfony\Component\Validator\Constraints\AbstractComparison;
class TextTimeInterval extends AbstractComparison
{
public $message = ' {{ compared_value }}.';
}
namespace App\Custom\Constraints;
use Symfony\Component\Validator\Constraints\AbstractComparisonValidator;
class TextTimeIntervalValidator extends AbstractComparisonValidator
{
protected function compareValues($timeFrom, $timeTo)
{
$compareResult = true;
$from = explode(':', $timeFrom);
$to = explode(':', $timeTo);
try {
if ((int) $from[0] > (int) $to[0])
$compareResult = false;
else if (((int) $from[0] == (int) $to[0]) && ((int) $from[1] > (int) $to[1])) {
$compareResult = false;
}
} catch (\Exception $exception) {
$compareResult = false;
}
return $compareResult;
}
}
Somente neste caso (uma das implementações possíveis) substituímos a função compareValues, que retorna true / false no êxito da validação e é processada no AbstractComparisonValidator pela função validate ().
Isso é essencialmente descrito da seguinte forma
...
private $timeFrom;
private $timeTo;
...
Esperamos que esta pequena análise e exemplos tenham mostrado como é fácil usar validadores personalizados. Como para iniciantes, consideramos os validadores mais simples, é claro, para não sobrecarregar a apresentação com descrições de assuntos, falhamos em fornecer exemplos excepcionais. Em artigos futuros, planejo considerar validadores mais complexos e casos específicos.