Symfony 4,编辑用户实体并保存新密码

Symfony 4, edit user entity and save new password

我执行了 make:crud 命令来为实体用户生成一些文件。

一切都很顺利,但我在编辑用户时遇到了一个问题。 当我编辑用户时,我可以:

来自生成的用户 'edit' 控制器:

/**
 * @Route("/{id}/edit", name="user_edit", methods={"GET","POST"})
 */
public function edit(Request $request, User $user): Response
{
    $form = $this->createForm(UserType::class, $user);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        // HERE : How can I check if the password was changed ? 

        $this->getDoctrine()->getManager()->flush();

        return $this->redirectToRoute('user_index', [
            'id' => $user->getId(),
        ]);
    }

    return $this->render('user/edit.html.twig', [
        'user' => $user,
        'form' => $form->createView(),
        'title' => 'edit userr'
    ]);
}

如何检查密码是否已更改?用户变量包含新密码值...

如果密码是新的,我必须使用编码器服务。如果没有,我只需要用新数据更新用户

为此,在您的用户中有一个未写入数据库的 class 变量会有所帮助。然后,在您的表单中,您可以使用此变量临时存储更新后的密码,然后对其进行编码和删除。这就是用户界面中的 eraseCredentials() 方法的用途。

例如在你的用户中你可以

class User implements UserInterface
{
    private $plainPassword;

    // ...

    public function setPlainPassword(string $plainPassword)
    {
        $this->plainPassword = $plainPassword;
    }

    public function getPlainPassword()
    {
        return $this->plainPassword;
    }

    public function eraseCredentials()
    {
        $this->plainPassword = null;
    }
}

注意 private $plainPassword 没有任何 ORM 注释,这意味着它不会存储在数据库中。但是,您可以使用验证约束,例如如果您想确保密码具有最小长度或一定的复杂性。您仍然需要存储加密密码的原始密码字段。

然后您将此字段添加到您的用户更新表单,而不是实际的密码字段。在您的控制器中,您只能检查新的 plainPassword-field 是否已填写,然后读取该值,对其进行编码并替换实际的密码字段。

if ($form->isSubmitted() && $form->isValid()) {
    $user = $form->getData();
    if ($user->getPlainPassword() !== null) {
        $user->setPassword($this->userPasswordEncoder->encode(
            $user->getPlainPassword(),
            $user
        );
    }

    // ...

不向用户添加此 "helper"-属性 的另一种方法是使用未映射的表单字段:

# UserForm
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        // ...
        ->add('plainPassword', PasswordType::class, ['mapped' => false])
    ;
}

控制器看起来很相似,只是您从未映射的字段而不是从用户那里获取数据:

 $form->get('plainPassword')->getData();