在Symfony控制器中使用自定义验证器
我想对控制器中的各种查询参数使用自定义验证器。文件给出了以下示例:在Symfony控制器中使用自定义验证器,symfony,Symfony,我想对控制器中的各种查询参数使用自定义验证器。文件给出了以下示例: // validate a query parameter (a hash in this case) $incomingHashConstraint = new CustomAssert\IncomingHash(); // use the validator to validate the value // If you're using the new 2.5 validation API (y
// validate a query parameter (a hash in this case)
$incomingHashConstraint = new CustomAssert\IncomingHash();
// use the validator to validate the value
// If you're using the new 2.5 validation API (you probably are!)
$errorList = $this->get('validator')->validate(
$incomingHash,
$incomingHashConstraint
);
if (0 === count($errorList)) {
// ... this IS a valid hash
} else {
// this is *not* a valid hash
$errorMessage = $errorList[0]->getMessage();
// ... do something with the error
throw $this->createNotFoundException('Not a valid hash ID ' . $incomingHash);
}
在很多控制器中使用它是相当笨拙的。理想情况下,我可以使用自定义验证器作为路线中的一个需求,但这似乎不是一个选项。这些验证器应该是服务吗?理想情况下,我想要像这样的东西
if(!isValid($incomingHash, IncomingHashConstraint)) {
throw \Exception(); }
关于组织这项活动的最佳方式有什么建议吗?谢谢 有一种非常简单干净的方法
namespace Application\FrontendBundle\Model;
use Application\FrontendBundle\Validator\Constraint as PersonAssert;
use JMS\Serializer\Annotation as Serializer;
/**
* @PersonAssert\Person
*/
class Person
{
/**
* @var int
* @Serializer\Type("integer")
*/
public $id;
/**
* @var string
* @Serializer\Type("string")
*/
public $name;
/**
* @var string
* @Serializer\Type("string")
*/
public $dob;
/**
* @var string
* @Serializer\Type("string")
*/
public $whatever;
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class Person extends Constraint
{
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class PersonValidator extends ConstraintValidator
{
public function validate($person, Constraint $constraint)
{
if (!is_numeric($person->id)) {
$this->context->buildViolation('Id must be a numeric value.')->addViolation();
}
if ($person->name == 'Acyra') {
$this->context->buildViolation('You name is weird.')->addViolation();
}
if ($person->dob == '28/11/2014') {
$this->context->buildViolation('You are too young.')->addViolation();
}
// I'm not interested in validating $whatever property of Person model!
}
}
您的自定义验证程序类
namespace Application\FrontendBundle\Model;
use Application\FrontendBundle\Validator\Constraint as PersonAssert;
use JMS\Serializer\Annotation as Serializer;
/**
* @PersonAssert\Person
*/
class Person
{
/**
* @var int
* @Serializer\Type("integer")
*/
public $id;
/**
* @var string
* @Serializer\Type("string")
*/
public $name;
/**
* @var string
* @Serializer\Type("string")
*/
public $dob;
/**
* @var string
* @Serializer\Type("string")
*/
public $whatever;
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class Person extends Constraint
{
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class PersonValidator extends ConstraintValidator
{
public function validate($person, Constraint $constraint)
{
if (!is_numeric($person->id)) {
$this->context->buildViolation('Id must be a numeric value.')->addViolation();
}
if ($person->name == 'Acyra') {
$this->context->buildViolation('You name is weird.')->addViolation();
}
if ($person->dob == '28/11/2014') {
$this->context->buildViolation('You are too young.')->addViolation();
}
// I'm not interested in validating $whatever property of Person model!
}
}
控制器
如果您不将控制器用作服务,那么您可以像上面那样使用$this->get('put_the_name_here')
直接访问验证程序
和序列化程序
服务
...
use JMS\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
....
/**
* @Route("person", service="application_frontend.controller.bank")
*/
class PersonController extends Controller
{
private $validator;
private $serializer;
public function __construct(
ValidatorInterface $validator,
SerializerInterface $serializer
) {
$this->validator = $validator;
$this->serializer = $serializer;
}
/**
* @param Request $request
*
* @Route("/person")
* @Method({"POST"})
*
* @return Response
*/
public function personAction(Request $request)
{
$person = $this->validatePayload(
$request->getContent(),
'Application\FrontendBundle\Model\Person'
);
if ($person instanceof Response) {
return $person;
}
print_r($person);
// Now you can carry on doing things in your service class
}
private function validatePayload($payload, $model, $format = 'json')
{
$payload = $this->serializer->deserialize($payload, $model, $format);
$errors = $this->validator->validate($payload);
if (count($errors)) {
return new Response('Some errors', 400);
}
return $payload;
}
}
示例
namespace Application\FrontendBundle\Model;
use Application\FrontendBundle\Validator\Constraint as PersonAssert;
use JMS\Serializer\Annotation as Serializer;
/**
* @PersonAssert\Person
*/
class Person
{
/**
* @var int
* @Serializer\Type("integer")
*/
public $id;
/**
* @var string
* @Serializer\Type("string")
*/
public $name;
/**
* @var string
* @Serializer\Type("string")
*/
public $dob;
/**
* @var string
* @Serializer\Type("string")
*/
public $whatever;
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class Person extends Constraint
{
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class PersonValidator extends ConstraintValidator
{
public function validate($person, Constraint $constraint)
{
if (!is_numeric($person->id)) {
$this->context->buildViolation('Id must be a numeric value.')->addViolation();
}
if ($person->name == 'Acyra') {
$this->context->buildViolation('You name is weird.')->addViolation();
}
if ($person->dob == '28/11/2014') {
$this->context->buildViolation('You are too young.')->addViolation();
}
// I'm not interested in validating $whatever property of Person model!
}
}
请求1
{
"id": 66,
"name": "Acyraaaaa",
"dob": "11/11/1111",
"whatever": "test"
}
Application\FrontendBundle\Model\Person Object
(
[id] => 66
[name] => Acyraaaaa
[dob] => 11/11/1111
[whatever] => test
)
响应1
{
"id": 66,
"name": "Acyraaaaa",
"dob": "11/11/1111",
"whatever": "test"
}
Application\FrontendBundle\Model\Person Object
(
[id] => 66
[name] => Acyraaaaa
[dob] => 11/11/1111
[whatever] => test
)
请求2
{
"id": "Hello",
"name": "Acyra",
"dob": "28/11/2014"
}
400 Bad request
Some errors
响应2
{
"id": "Hello",
"name": "Acyra",
"dob": "28/11/2014"
}
400 Bad request
Some errors
如果您转到我在上面给您的链接并应用其余的链接,那么您实际上会收到正确的错误消息,如:
{
"errors": {
"id": "Id must be a numeric value.",
"name": "You name is weird.",
"dob": "You are too young."
}
}
有一种非常简单和干净的方法
namespace Application\FrontendBundle\Model;
use Application\FrontendBundle\Validator\Constraint as PersonAssert;
use JMS\Serializer\Annotation as Serializer;
/**
* @PersonAssert\Person
*/
class Person
{
/**
* @var int
* @Serializer\Type("integer")
*/
public $id;
/**
* @var string
* @Serializer\Type("string")
*/
public $name;
/**
* @var string
* @Serializer\Type("string")
*/
public $dob;
/**
* @var string
* @Serializer\Type("string")
*/
public $whatever;
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class Person extends Constraint
{
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class PersonValidator extends ConstraintValidator
{
public function validate($person, Constraint $constraint)
{
if (!is_numeric($person->id)) {
$this->context->buildViolation('Id must be a numeric value.')->addViolation();
}
if ($person->name == 'Acyra') {
$this->context->buildViolation('You name is weird.')->addViolation();
}
if ($person->dob == '28/11/2014') {
$this->context->buildViolation('You are too young.')->addViolation();
}
// I'm not interested in validating $whatever property of Person model!
}
}
您的自定义验证程序类
namespace Application\FrontendBundle\Model;
use Application\FrontendBundle\Validator\Constraint as PersonAssert;
use JMS\Serializer\Annotation as Serializer;
/**
* @PersonAssert\Person
*/
class Person
{
/**
* @var int
* @Serializer\Type("integer")
*/
public $id;
/**
* @var string
* @Serializer\Type("string")
*/
public $name;
/**
* @var string
* @Serializer\Type("string")
*/
public $dob;
/**
* @var string
* @Serializer\Type("string")
*/
public $whatever;
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class Person extends Constraint
{
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class PersonValidator extends ConstraintValidator
{
public function validate($person, Constraint $constraint)
{
if (!is_numeric($person->id)) {
$this->context->buildViolation('Id must be a numeric value.')->addViolation();
}
if ($person->name == 'Acyra') {
$this->context->buildViolation('You name is weird.')->addViolation();
}
if ($person->dob == '28/11/2014') {
$this->context->buildViolation('You are too young.')->addViolation();
}
// I'm not interested in validating $whatever property of Person model!
}
}
控制器
如果您不将控制器用作服务,那么您可以像上面那样使用$this->get('put_the_name_here')
直接访问验证程序
和序列化程序
服务
...
use JMS\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
....
/**
* @Route("person", service="application_frontend.controller.bank")
*/
class PersonController extends Controller
{
private $validator;
private $serializer;
public function __construct(
ValidatorInterface $validator,
SerializerInterface $serializer
) {
$this->validator = $validator;
$this->serializer = $serializer;
}
/**
* @param Request $request
*
* @Route("/person")
* @Method({"POST"})
*
* @return Response
*/
public function personAction(Request $request)
{
$person = $this->validatePayload(
$request->getContent(),
'Application\FrontendBundle\Model\Person'
);
if ($person instanceof Response) {
return $person;
}
print_r($person);
// Now you can carry on doing things in your service class
}
private function validatePayload($payload, $model, $format = 'json')
{
$payload = $this->serializer->deserialize($payload, $model, $format);
$errors = $this->validator->validate($payload);
if (count($errors)) {
return new Response('Some errors', 400);
}
return $payload;
}
}
示例
namespace Application\FrontendBundle\Model;
use Application\FrontendBundle\Validator\Constraint as PersonAssert;
use JMS\Serializer\Annotation as Serializer;
/**
* @PersonAssert\Person
*/
class Person
{
/**
* @var int
* @Serializer\Type("integer")
*/
public $id;
/**
* @var string
* @Serializer\Type("string")
*/
public $name;
/**
* @var string
* @Serializer\Type("string")
*/
public $dob;
/**
* @var string
* @Serializer\Type("string")
*/
public $whatever;
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class Person extends Constraint
{
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
namespace Application\FrontendBundle\Validator\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class PersonValidator extends ConstraintValidator
{
public function validate($person, Constraint $constraint)
{
if (!is_numeric($person->id)) {
$this->context->buildViolation('Id must be a numeric value.')->addViolation();
}
if ($person->name == 'Acyra') {
$this->context->buildViolation('You name is weird.')->addViolation();
}
if ($person->dob == '28/11/2014') {
$this->context->buildViolation('You are too young.')->addViolation();
}
// I'm not interested in validating $whatever property of Person model!
}
}
请求1
{
"id": 66,
"name": "Acyraaaaa",
"dob": "11/11/1111",
"whatever": "test"
}
Application\FrontendBundle\Model\Person Object
(
[id] => 66
[name] => Acyraaaaa
[dob] => 11/11/1111
[whatever] => test
)
响应1
{
"id": 66,
"name": "Acyraaaaa",
"dob": "11/11/1111",
"whatever": "test"
}
Application\FrontendBundle\Model\Person Object
(
[id] => 66
[name] => Acyraaaaa
[dob] => 11/11/1111
[whatever] => test
)
请求2
{
"id": "Hello",
"name": "Acyra",
"dob": "28/11/2014"
}
400 Bad request
Some errors
响应2
{
"id": "Hello",
"name": "Acyra",
"dob": "28/11/2014"
}
400 Bad request
Some errors
如果您转到我在上面给您的链接并应用其余的链接,那么您实际上会收到正确的错误消息,如:
{
"errors": {
"id": "Id must be a numeric value.",
"name": "You name is weird.",
"dob": "You are too young."
}
}
如果你不想在很多控制器中重复这些逻辑,那么使用事件监听器怎么样?例如,而不是检查多个控制器实例,您可以只向这些控制器添加一个简单的接口并应用您的逻辑。您可以使用所需的逻辑定义一个控制器,然后从中扩展控制器。请看下面的示例,尤其是其中的完整示例链接,它完全符合@SergioIvanuzzo上面所说的,我同意他的观点!如果你不想在很多控制器中重复这些逻辑,那么使用事件监听器怎么样?例如,而不是检查多个控制器实例,您可以只向这些控制器添加一个简单的接口并应用您的逻辑。您可以使用所需的逻辑定义一个控制器,然后从中扩展控制器。请看下面的示例,尤其是其中的完整示例链接,它完全符合@SergioIvanuzzo上面所说的,我同意他的观点!