在Symfony控制器中使用自定义验证器

时间:2015-11-28 11:17:24

标签: 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 (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(); }

有关组织此方法的最佳方法的任何建议吗?谢谢!

1 个答案:

答案 0 :(得分:4)

有一种非常简单和干净的方式。

  1. 请求有效负载将映射到您的自定义模型类,并根据您的自定义验证类进行验证。
  2. 如果出现错误,则会收到错误列表。
  3. 如果没有错误,那么你将获得所有模型类 有效载荷数据将映射到其中的相关属性 使用该模型类进一步的逻辑(你应该做额外的逻辑 不在控制器中的服务类。)
  4. 我将给出一个有效的例子,但如果你想要一个完整的例子,那么it is here。如果你应用它,你将拥有一个非常薄的控制器。字面上不超过15行。这样你就可以了解@SergioIvanuzzo上面所说的内容。

    安装jms / serializer-bundle Doc

    "frameworks": {
        "dnx451": { },
        "dnxcore50": {
          "dependencies": {
            "System.Data.SqlClient": "4.0.0-beta-23516"
          }
         }
      }
    

    CUSTOM MODEL CLASS

    composer require jms/serializer-bundle
    
    // in AppKernel::registerBundles()
    $bundles = array(
        // ...
        new JMS\SerializerBundle\JMSSerializerBundle(),
        // ...
    );
    

    您的自定义验证员类

    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;
    }
    

    <强> CONTROLLER

    如果您不将控制器用作服务,则可以像上面一样直接使用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! } } 访问validatorserializer个服务。

    $this->get('put_the_name_here')

    <强>实施例

    请求1

    ...
    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;
        }
    }
    

    回复1

    {
      "id": 66,
      "name": "Acyraaaaa",
      "dob": "11/11/1111",
      "whatever": "test"
    }
    

    请求2

    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