We use forms the way recommended in the best practices. Meaning we don’t do any validation in our forms. We use validation_groups and annotations to add validation to the form. Thus our forms are only responsible for what is what data is being processed.

Forget Password Form

This is a form that uses data transformer on the whole form to transform the email address into a user object. If the form fails it will put the form error on the email object. This is done in the config with the “.” for error_mapping. You can read more about it Error Mapping Symfony Forms

/**
 * This will configure the form so all error / data transform failure go to the email field
 * We want this form getData method to return user, so that it's easier to deal with in the controller
 * @link http://symfony.com/doc/current/reference/forms/types/form.html#error-mapping
 * @param OptionsResolver $resolver
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => User::class,
        // This is what maps the error to the user
        'error_mapping' => [
            '.' => 'email'
        ],
        'invalid_message' => 'Email was not found.',
        'validation_groups' => [User::VALIDATION_GROUP_DEFAULT]
    ]);
}

Also note that the data transform always returns a User object. The reason is that it is transforming the whole form.

Change Password Form

This form is injects the AuthorizationChecker which is used to see if the user is an admin. If user is an admin we remove the current password field. This allows admins to change other user’s passwords.

// If the user is role admin entering a a password is not required
if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
    $builder->remove('currentPassword');
}

Also note that the change password form uses a ChangePasswordModel which has a UserPassword constraint. This validator will match the password entered with the password the user is trying to change.