blahblah blahblah - 1 month ago 14
PHP Question

Symfony2 password reset without overriding FOSUser

I am trying to build a form that resets user password. I am using FOSUserBundle to manage users, but I don't want to override FOSUser resetting controller due to some architecture reasons

So I decided to build my own type and controller to reset password

PasswordResettingType.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'attr' => ['class' => 'form-group has-feedback'],
'first_options' => array('label' => false,
'attr' => ['placeholder' => 'New Password']
),
'second_options' => array('label' => false,
'attr' => ['placeholder' => 'Repeat Password']),
'invalid_message' => 'Passwords don't match',
));
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CoreBundle\Entity\User',
'csrf_token_id' => 'resetting'
));
}


Resetting controller

/**
* @Route("/reset/{token}", name="api_resetting_reset")
*/
public function resetAction(Request $request, $token)
{
$userManager = $this->get('fos_user.user_manager');

$user = $userManager->findUserByConfirmationToken($token);

if (null === $user) {
return $this->render('APIBundle:Resetting:error.html.twig');
}

$form = $this->createForm(PasswordResettingType::class, $user);

$form->handleRequest($request);

if ($form->isValid()) {
$user->setConfirmationToken(null);
$user->setPasswordRequestedAt(null);
$user->setPlainPassword($form["plainPassword"]->getData());
$userManager->updateUser($user);

return $this->redirectToRoute('api_resetting_success');
}

return $this->render('APIBundle:Resetting:reset.html.twig', array(
'token' => $token,
'form' => $form->createView()
));
}


reset.html.twig

{{ form_start(form) }}

{% for passwordField in form.plainPassword %}
<div class="form-group has-feedback">
{{ form_widget(passwordField, { 'attr': {'class': 'form-control'} }) }}
<span class="show">show</span>
{{ form_errors(passwordField) }}
</div>
{% endfor %}

<input type="submit" class="btn" value="Submit" />
{{ form_end(form) }}


But when I submit form, new password is not set, ConfirmationToken and PasswordRequestedAt are not set to null.

Answer

I think you are doing it the wrong way. If you take a look to FOS User and read with detail the documentation, you will see that they are doing this using EventListeners.

That means you can hook on them and do your stuff. Or if you don't want to do it you can override it and make your own. Doing this half way like you are doing is not going to work properly. For example you are not checking the onResettingResetInitialize event that checks if the password request expired.

About last answer I think you don't really need to do this:

$encoder = $this->container->get('security.password_encoder');
$user->setPassword($encoder->encodePassword($user, $user->getPlainPassword()));

Since that is the job of the UserManager->UpdateUser()

By the way: Can't you debug from there and put a dump($user);exit(); and check what's the output and if it's being called properly.

Also Boulzy comment is right: /reset/{token} is the same route of FOS. If you debug the UpdateUser using echo debug_backtrace(); you can also see from where is being called the UpdateUser.