【问题标题】:Symfony2 - using entity value as default when form is submitted with empty fieldsSymfony2 - 使用空字段提交表单时使用实体值作为默认值
【发布时间】:2014-09-09 12:00:28
【问题描述】:

我正在 Symfony 2 中构建一个 Web 应用程序,其中我有一个 User 实体类来保存注册用户。

当然,每个用户至少应该有一个用户名和一个密码,因此,我对实体中的两个字段都使用@Assert\NotBlank 验证规则。用户名是静态的,但是,能够更改密码是可取的。

因此,我正在构建一个表单,登录用户可以在其中更改密码(除其他外)。此表单使用 Symfony 中的重复字段类型来确认密码。

现在,在大多数情况下,我猜用户并不想更改密码,而是更新个人资料中的其他字段。因此,我希望他们可以将密码字段留空。但是,这会干扰NotBlank 验证规则。

删除NotBlank 验证规则当然是一种选择。虽然,这几乎不是我正在寻找的解决方案,因为这会导致用户最终获得空白密码的问题。

最后,据我了解,symfony Request 对象在提交表单时将表单数据自动填充回用户实体。

现在,我的问题是:有什么方法可以在密码字段为空的情况下,让 Symfony 使用数据库中的现有密码而不是空白值重新填充用户实体?这将允许验证进行,并且不会在保存时对密码进行任何不希望的更改。

这是实体中密码字段的代码

/**
 * @var string
 * 
 * @ORM\Column(name="password",type="string",length=255) 
 * @Assert\NotBlank()
 * @Assert\Type(type="string")
 * @Assert\Length(max="255")
 * @Assert\NotEqualTo(value="password")
 */
private $password;

这是生成表单的代码

private function initForm($user) {
  return $this->createFormBuilder($user)
           ->add('name', 'text')
           ->add('mail', 'email')
           ->add('password', 'repeated', [
              'type' => 'password',
              'invalid_message' => 'The password fields must match.',
              'first_options' => ['label' => false],
              'second_options' => ['label' => false] //set to false to hide label in view
           ])
           ->add('save', 'submit')->getForm();
}

这是/profile/edit 页面的操作代码:

/**
 *  @ParamConverter("user",class="MyBundle:User")
 */
public function editAction(User $user, Request $request) {

   $form = $this->initForm($user);
   $form->handleRequest($request);

   if ($form->isValid()) {
      //update to database and redirect user back to profile_view
      $this->getDoctrine()->getManager()->flush();
      return $this->redirect($this->generateUrl('profile_view'));
   }

   return $this->render('MyBundle:User:edit.html.twig',
                        array('form' => $form->createView()));
}

提前感谢您的帮助!

编辑

我确实尝试过“显而易见”的方法,即将原始密码临时存储在一个变量中,如果在提交表单后它是空白的,则将其“放回”:

/**
 * @ParamConverter("user",
                   class="MyBundle:User")
 */
public function editAction(User $user, Request $request) {
   $password = $user->getPassword();

   $form = $this->initForm($user)->getForm();
   $form->handleRequest($request);

   if ( $user->getPassword() == NULL ) {
       $user->setPassword($password);
       $form = $this->initForm($user)->getForm(); //this is the problem

   }

   if ( $form->isValid() ) {
       //update to database and redirect user back to profile view
       $this->getDoctrine()->getManager()->flush();
       return $this->redirect($this->generateUrl('profile_view'));
   }
   return $this->render('MyBundle:User:edit.html.twig',
                        array('form' => $form->createView()));
}

但是,由于明显的原因,这并没有奏效。当表单在 if 语句中重新初始化时,Symfony 发现表单从未被提交过,即没有执行验证。添加$form->handleRequest($request) 让我们回到第一个问题,即密码字段可能为空白。

不过,我确实觉得很奇怪。 Symfony 验证实体而不是表单。但是删除问题行$form->initForm($user)->getForm() 仍然无效,尽管实体应该是有效的。

【问题讨论】:

    标签: php forms validation symfony


    【解决方案1】:

    我认为这不是一个好主意。正确的方法是创建一个单独的表单来更改用户密码。示例:twitterfacebookgoogle

    【讨论】:

    • 经过一些持续的研究,我相信你是对的!我会接受它作为答案.. 但如果有人应该找到方法,我会全神贯注!
    • 我完全忘记了;非常感谢您的帮助! =)
    【解决方案2】:

    一个解决方案是使用一个额外的类成员$rawPassword,而不是存储在数据库中,只用于您的表单。当然,您将保留您的 $password 变量用于您问题中定义的数据库存储。

    在您的编辑操作中,您只需在$form->bind($request); 之后测试您的用户是否定义为$rawPassword 密码。如果是这种情况,请将$password 更新为$rawPassword 的编码值,然后刷新。

    编辑:$form->bind($request); 低于 2.3,$form->handleRequest($request); 否则。

    【讨论】:

    • 有趣的想法!那对我绝对有用。非常感谢!也只是一句客气的话,我相信 $form->bind($request) 方法自 Symfony 2.3 以来已被弃用。
    • 冬青牛!确实 !这次感谢你是我的工作,我完全错过了这个。
    【解决方案3】:

    我认为解决方案是在它自己的表单上使用EVENT

    1. 在创建新用户时将保持验证不变

    2. 将模型数据放回现有用户的请求数据 密码字段为空

    3. 将对密码字段为空的现有用户触发验证 在模型数据(DB)中

    ->addEventListener(FormEvents::PRE_SUBMIT,function(FormEvent $event) {
    
        /** @var array $requestData */
        $requestData = $event->getData();
    
        /** @var \AppBundle\Entity\User $user */
        $user = $event->getForm()->getData();
    
        if ($user && !$requestData['password']){
            $requestData['password'] = $user->getPassword();
        }
    
        $event->setData($requestData);
    })
    

    FormEvents::PRE_SUBMIT 将允许您访问 2 种数据类型,我在代码中用它们各自的类型对其进行了评论。

    $requestData 是来自用户输入的归一化数据,此数据将在本例中应用于模型 $user ,这将在事件 PRE_SUBMIT 之后发生。

    验证将在 $requestData 上进行,但仅在 PRE_SUBMIT 之后进行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-20
      • 2017-04-14
      • 1970-01-01
      • 2018-01-10
      • 1970-01-01
      • 2014-11-30
      • 2011-05-03
      • 1970-01-01
      相关资源
      最近更新 更多