4

我正在使用 FOSUserBundle,并且正在尝试创建一个允许用户更新其用户配置文件的页面。我面临的问题是,如果用户不想更改/更新密码,我的表单不需要用户重新输入密码。因此,当用户使用空密码提交表单时,数据库将使用空字符串更新,并且用户将无法登录。

如果未设置密码字段,如何让我的表单忽略更新密码字段?下面是我正在使用的代码。

$user = $this->get('security.context')->getToken()->getUser();

//user form has email and repeating password fields    
$userForm = $this->createForm(new UserFormType(), $user);

if ($request->getMethod() == 'POST') {
   $userForm->bindRequest($request);

   if($userForm->isValid()){
      //this will be be empty string in the database if the user does not enter a password
      $user->setPlainPassword($userForm->getData()->getPassword());
      $em->flush();
   }
}

我已经尝试了以下一些方法,但这仍然是空的,因为 bindRequest 将空密码设置为用户

if($userForm->getData()->getPassword())
   $user->setPlainPassword($userForm->getData()->getPassword());

我也尝试过,但这会导致类似的情况并导致不需要的查询

if($userForm->getData()->getPassword())
   $user->setPlainPassword($userForm->getData()->getPassword());
else
   $user->setPlainPassword($user->getPlainPassword());

有什么优雅的方法来处理这个用例吗?

4

4 回答 4

6

问题是您在控制密码之前将表单绑定到用户对象。让我们分析您的代码片段。

请执行下列操作

$user = $this->get('security.context')->getToken()->getUser();

将现有用户加载到用户对象中。
现在您使用该数据“构建”一个表单,如果收到一个帖子,您会将发布的数据放入前一个对象中

$userForm = $this->createForm(new UserFormType(), $user);

if ($request->getMethod() == 'POST') {
   $userForm->bindRequest($request);

因此,如果将其留空,bindRequest您已经将先前的密码丢失到对象中(显然还没有丢失到数据库中)。从现在开始的每一个控制都是无用的。

$request在这种情况下,一种解决方案是在将表单字段的值绑定到底层对象之前,将其直接手动验证到对象中。
你可以用这个简单的代码片段来做到这一点

$postedValues = $request->request->get('formName');

现在您必须验证密码值是否已填写

if($postedValues['plainPassword']) { ... }

我想是plainPassword我们感兴趣的领域的名称。

如果您发现该字段包含一个值(其他分支),您无需执行任何操作。
否则,您必须从用户对象中检索原始密码并将其设置为$request相应的值。
(更新) 否则,您可以从用户对象中检索密码,但由于该密码以 hased 值存储,因此您不能将其放入$request对象中,因为它会再次受到散列的影响。
你可以做的——我想——是一个array_pop直接放入$request对象中,并把把所有事情搞砸的字段(plainPassword) 既然你已经完成了这些事情,你可以将发布的数据绑定到底层对象。

另一种解决方案(可能更好,因为您将一些业务逻辑从控制器中移开)是使用prePersist钩子,但在概念上更先进。如果您想探索该解决方案,您可以阅读有关表单事件的信息

于 2012-07-22T08:18:11.410 回答
1

我认为你应该重新考虑这是否真的是一个很好的用例。用户应该能够编辑其他用户的密码吗?在我们的机构,我们甚至不允许最高级别的管理员执行此任务。

如果用户需要更改密码,我们让他们自己处理。如果他们忘记了密码,我们允许他们通过电子邮件找回密码。如果他们在调整电子邮件方面需要帮助,我们允许我们的管理员在那时为用户提供帮助。但是所有密码更新和创建都是由用户单独完成的。

我认为 FOSUserBundle 让它很难做到这一点很棒,但如果你必须这样做,DonCallisto 似乎有一个很好的解决方案。

于 2012-07-23T20:52:49.633 回答
0
<?php

class User
{
    public function setPassword($password)
    {
        if (false == empty($password)) {
            $this->password = $password;
        }
    }
}

如果密码不为空,这只会更新用户的密码。

于 2012-07-20T10:49:35.533 回答
0

我找到了一个简单的技巧来摆脱“输入密码”表单错误。在用户实体中手动设置一个虚拟的 plainPassword。在表单验证之后,只需在刷新实体之前将其重置。

<?php

    public function updateAction(Request $request, $id)
    {
        $em = $this->getDoctrine()->getManager();

        $entity = $em->getRepository('AppBundle:User')->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find Customer entity.');
        }

        $deleteForm = $this->createDeleteForm($id);
        $editForm = $this->createEditForm($entity);
        
        $postedValues = $request->request->get('appbundle_user');
        
/* HERE */ $entity->setPlainPassword('dummy'); // hack to avoid the "enter password" error
        $editForm->handleRequest($request);

        if ($editForm->isValid()) {
/* AND HERE */ $entity->setPlainPassword(''); // hack to avoid the "enter password" error
            $em->flush();

            return $this->redirect($this->generateUrl('customer_edit', array('id' => $id)));
        }

        return array(
            'entity'      => $entity,
            'edit_form'   => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        );
    }

于 2015-05-23T22:36:21.320 回答