Ignore Password when user updates profile with FOSUserBundle

会有一股神秘感。 提交于 2019-12-04 10:15:11

I think you should reconsider if this is in fact a good use case. Should users be able to edit other users passwords? At our institution we do not allow even the highest level admin to perform this task.

If a user needs their password changed we let them handle that themselves. If they have forgotten their password we allow them to retrieve it via email. If they need assistance with adjusting their email we allow our admins to assist users then. But all password updating and creation is done soley by the user.

I think it is great that FOSUserBundle makes it so difficult to do otherwise but if you must DonCallisto seems to have a good solution.

The problem is that you bind a form to a User Object before controls upon password. Let's analyze your snippet of code.

Do the following

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

will load an existing user into a User Object.
Now you "build" a form with that data and if receive a post, you'll take the posted data into the previous object

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

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

So, onto bindRequest you have alredy lost previous password into the object (obviously not into database yet) if that was leave empty. Every control from now on is useless.

A solution in that case is to manually verify value of form's field directly into $request object before binding it to the underlying object.
You can do this with this simple snippet of code

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

Now you have to verify that password value is filled

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

where plainPassword I suppose to be the name of the field we're interesting in.

If you find that this field contain a value (else branch) you haven't to do anything.
Otherwise you have to retrieve original password from User Object and set it into $request corrisponding value.
(update) Otherwise you may retrieve password from User Object but since that password is stored with an hased valued, you can't put it into the $request object because it will suffer from hashing again.
What you could do - i suppose - is an array_pop directly into $request object and put away the field that messes all the things up (plainPassword) Now that you had done those things, you can bind posted data to underlying object.

Another solution (maybe better because you move some business logic away from controller) is to use prePersist hook, but is more conceptually advanced. If you want to explore that solution, you can read this about form events

<?php

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

This will only update the password on the user if it isn't empty.

I have found a simple hack to get rid of the "Enter a password" form error. Manualy set a dummy plainPassword in the user entity. After form validation just reset it before you flush the entity.

<?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(),
        );
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!