简体   繁体   English

Symfony表单验证与验证器服务

[英]Symfony form validation vs validator service

I'm having a strange issue and I think I'm missing something. 我有一个奇怪的问题,我想我错过了一些东西。

I'm using Symfony 2.7 and I'm working on a user password update function. 我正在使用Symfony 2.7,我正在使用用户密码更新功能。

I have a user entity (Extends FosUserBundle user entity) with multiple properties. 我有一个具有多个属性的用户实体(Extends FosUserBundle用户实体)。 One of them is the plainPassword (ofcourse not persisted to DB). 其中一个是plainPassword(当然没有持久化到DB)。

User.php user.php的

...

/**
 * @ORM\Table(name="prefix_users")
 * @ORM\Entity(repositoryClass="UserRepository")
 *
 * @UniqueEntity(fields={"email"}, message="unique", groups={"registration"})
 * @UniqueEntity("username", message="unique", groups={"registration"})
 *
 * @ExclusionPolicy("all")
 */
class User extends BaseUser
{

...

    /* @var string
     *
     * @Assert\NotBlank(message="blank",groups={"accountUpdate", "passwordUpdate"})
     * @Assert\Length(min=8, minMessage="short", max=4096, maxMessage="long")
     */
    protected $plainPassword;

As you can see I'm using annotations for the validation of my properties. 正如您所看到的,我正在使用注释来验证我的属性。 I'm also using validation groups to be sure only the correct properties will be validated. 我也使用验证组来确保只验证正确的属性。

I have created a form 我创建了一个表单

UserUpdatePasswordType.php UserUpdatePasswordType.php

class UserUpdatePasswordType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('plainPassword', 'repeated', array(
            'type' => 'password',
            'invalid_message' => 'password_mismatch',
        ));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'My\Bundle\UserBundle\Entity\User',
            'csrf_protection' => false,
            'intention' => 'resetting',
            /**
             * Need to add method to prevent this form from bein marked as invalid.
             * @see http://sroze.io/2013/10/30/symfony2-form-patch-requests-and-handlerequest-form-never-valid/
             */
            'method' => 'PATCH'
        ));
    }

I'm building a restful API with FOSRestBundle and I'd like to provide a nice and clean output if form validation fails. 我正在使用FOSRestBundle构建一个restful API,如果表单验证失败,我想提供一个漂亮而干净的输出。

As far as I know I can validate a form in two ways: 据我所知,我可以通过两种方式验证表单:

  1. $formErrors = $this->get('validator')->validate($user, null, ['passwordUpdate']); $ formErrors = $ this-> get('validator') - > validate($ user,null,['passwordUpdate']);
  2. $form->isValid() and to get errors $form->getErrors() $ form-> isValid()并获取错误$ form-> getErrors()

Now the strange part comes, the two methods above give different validation errors. 现在奇怪的部分来了,上面的两种方法给出了不同的验证错误。

Request parameters 请求参数

user_update_password[plainPassword][first]:sffsdfdsfds
user_update_password[plainPassword][second]:fdsfdsfsd

Response from $formErrors = $this->get('validator')->validate($user, null, ['passwordUpdate']); 响应来自$ formErrors = $ this-> get('validator') - > validate($ user,null,['passwordUpdate']); The response is not correct, because the plainPassword is not blank. 响应不正确,因为plainPassword不是空白​​。

{
      "property_path": "plainPassword",
      "message": "blank"
}

Response form $form->isValid() which seems to look better 响应形式$ form-> isValid()似乎看起来更好

"form": {
      "children": {
        "plainPassword": {
          "children": {
            "first": {
              "errors": [
                "password_mismatch"
              ]
            },
            "second": {}
          }
        }
      }
    },
    "errors": []

The only difference I can see is the difference that I'm not providing a validation group name in the $form->isValid(). 我能看到的唯一区别是我没有在$ form-> isValid()中提供验证组名称。

Why am I getting different results and what should I do to fix? 为什么我会得到不同的结果,我该怎么做才能解决? Can I provide a validation group name to the $form->isValid() or should I fix a problem with the $validator->validate code? 我可以为$ form-> isValid()提供验证组名称,还是应该修复$ validator-> validate代码的问题?

I would love to see how this is managed in other Symfony2 based APIs... 我很想知道如何在其他基于Symfony2的API中管理它...

There're three reasons of difference. 差异有三个原因。

  1. You probably don't set data from request to model when validating by service. 在按服务验证时,您可能不会将数据从request设置为model Use $form->submit($request) as a safe proxy data setter 使用$form->submit($request)作为安全代理数据设置器
  2. You don't use validation groups in form (do it in setDefaults ) BTW. 您不在表单中使用验证组(在setDefaults )BTW。 Your @Assert\\Length won't be used until you add groups to this annotation or add validation group Default to service/form validators array 在将组添加到此批注或添加验证组之前,不会使用@Assert\\Length Defaultservice/form validators数组
  3. You used repeated type in form, which have additional Constraints in comparison to your model Constraints . 你用repeated的表单类型,其中有额外的Constraints相比,模型Constraints Form validator checks for both model and form constraints belonging to passed validation groups (by default 'Default' group is used) 表单验证器检查属于通过的验证组的模型和表单约束(默认情况下使用“默认”组)

Actually, there is another difference (besides using of validation group). 实际上,还有另一个区别(除了使用验证组)。 When you are using Form (rather than just a Validator), there is a 'repeated' type involved. 当您使用Form(而不仅仅是Validator)时,会涉及“重复”类型。

Validation 验证

One of the key features of the repeated field is internal validation (you don't need to do anything to set this up) that forces the two fields to have a matching value. 重复字段的一个关键特性是内部验证(您不需要做任何设置),强制两个字段具有匹配值。 If the two fields don't match, an error will be shown to the user. 如果两个字段不匹配,则会向用户显示错误。

So actually in one case you're using an additional constraint, and at another you are not. 所以实际上在一种情况下你正在使用一个额外的约束,而在另一种情况下你不是。 No surprise validations give different results. 没有惊喜验证会给出不同的结果。

So in your case I would probably make own implementation of "repeat" for a password in the User object and would use a validator service. 因此,在您的情况下,我可能会在User对象中为密码自己实现“重复”,并使用验证器服务。

Another option that I see is to use a Form object to validate User, but it's not a clean and clear way to make API. 我看到的另一个选项是使用Form对象来验证User,但它不是一个干净清晰的API制作方法。

The big difference is that one validator is validating the model and the other is validating the form data. 最大的区别是一个验证器正在验证模型,另一个验证表单数据。 The model requires the field to not be empty. 该模型要求该字段不为空。 The FOSUser bundle ChangePasswordFormType adds the UserPassword constraint to the form for validation. FOSUser包ChangePasswordFormTypeUserPassword约束添加到表单以进行验证。 The UserPassword validator checks that the form values were properly submitted. UserPassword验证程序检查表单值是否已正确提交。

If you are using www-form-urlencoded data in your API, use the form validator. 如果您在API中使用www-form-urlencoded数据,请使用表单验证程序。 It will give more precise errors as they will be related to the state of the data submitted not the state of the data after it was transformed into the model. 它将提供更精确的错误,因为它们与提交的数据的状态有关,而不是在数据转换为模型后的状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM