用户使用FOSUserBundle更新配置文件时忽略密码

Mik*_*ike 4 symfony doctrine-orm fosuserbundle

我正在使用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();
   }
}
Run Code Online (Sandbox Code Playgroud)

我尝试了一些如下所示的东西,但这仍然是空的,因为bindRequest将空密码设置为用户

if($userForm->getData()->getPassword())
   $user->setPlainPassword($userForm->getData()->getPassword());
Run Code Online (Sandbox Code Playgroud)

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

if($userForm->getData()->getPassword())
   $user->setPlainPassword($userForm->getData()->getPassword());
else
   $user->setPlainPassword($user->getPlainPassword());
Run Code Online (Sandbox Code Playgroud)

有没有优雅的方法来处理这个用例?

Don*_*sto 6

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

请执行下列操作

$user = $this->get('security.context')->getToken()->getUser();
Run Code Online (Sandbox Code Playgroud)

将现有用户加载到用户对象中.
现在,您使用该数据"构建"表单,如果收到帖子,您将把发布的数据放入上一个对象

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

if ($request->getMethod() == 'POST') {
   $userForm->bindRequest($request);
Run Code Online (Sandbox Code Playgroud)

所以,如果那是空的,那么bindRequest你已经将以前的密码丢失到了对象中(显然还没有进入数据库).从现在开始,每一个控制都是无用的.

在这种情况下,解决方案是在将表单字段的值$request绑定到底层对象之前直接手动验证表单字段的值.
您可以使用这个简单的代码片段来完成此操作

$postedValues = $request->request->get('formName');
Run Code Online (Sandbox Code Playgroud)

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

if($postedValues['plainPassword']) { ... }
Run Code Online (Sandbox Code Playgroud)

在那里plainPassword,我想是我们在有趣的字段的名称.

如果您发现此字段包含值(else分支),则您无需执行任何操作.
否则,您必须从User Object检索原始密码并将其设置为$request相应的值.
(更新)否则,您可以从用户对象中检索密码,但由于该密码存储有hased值,因此您无法将其置于$request对象中,因为它将再次遭受散列.
你能做什么 - 我想 - 是一个array_pop直接进入$request对象并收起混乱的领域(plainPassword)既然你已经完成了这些事情,你可以将发布的数据绑定到底层对象.

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