Search code examples
phpsymfonyfosuserbundlesymfony-3.3

Symfony FOSUserBundle Password Reset - The file could not be found


I am using FOSUserBundle.

I defined the following trait:

trait Logo
{
    /**
     * @Assert\Image()
     * @ORM\Column(type="string", nullable=true)
     */
    private $logo;

    /**
     * @return mixed
     */
    public function getLogo()
    {
        return $this->logo;
    }

    /**
     * @param mixed $logo
     */
    public function setLogo($logo)
    {
        $this->logo = $logo;
    }
}

I then applied it to my User class:

use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="fos_user")
 */
class User extends BaseUser
{
    use Logo;

    ...

This all works great and provides the basis to being able to associate images to my users.

Problem is that this breaks the FOS password reset - after I submit the form I get the following message presented as a form error:

The file could not be found.

And the Symfony Profiler details this further as follows:

ConstraintViolation {#1368 
  root: Form {#879 …}
  path: "data.logo"
  value: "553d1f015637bf5d97b9eb66f71e6587.jpeg"
}

This is specifically due to the @Assert\Image() on the logo property and only presents if the account I am trying to reset the password for has an image associated already. It causes no issues if the record has no image.

So this is where I end up sort of lost. I understand that:

  1. for some reason Symfony wants to get the image at this stage and that

  2. for some other reason it fails to do so.

How can I work around this? I don't need the image at this stage so if there's a way to tell the bundle that would probably be ideal.

I am relatively new to Symfony so apologies if this there is an obvious answer to this question but I can't see it.


Solution

  • Create a validation group for the password reset as explained in the documentation.

    After that, override the ResettingFormType and define your own validation group to use.

    The goal here is that the assert check of the image shouldn't be done in this form, but since the whole user object will be injected as data into the form itself, all asserts will be made until the form got told to do otherwise.

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'validation_groups' => array('my_resetting'),
        ));
    }
    

    An example to override the FormType:

    # AppBundle\Form\Type\ProfileFormType.php
    class ProfileFormType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            # example -> disable change of username in profile_edit
            $builder
                ->add('username', TextType::class, array(
                    'disabled' => true,
                    'label' => 'form.username',
                    'translation_domain' => 'FOSUserBundle'
                ))
            ;
        }
    
        public function getParent()
        {
            return 'FOS\UserBundle\Form\Type\ProfileFormType';
        }
    
        public function getBlockPrefix()
        {
            return 'app_user_profile';
        }
    
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'validation_groups' => array('my_resetting'),
            ));
        }
    }
    

    and in the config.yml

    fos_user:
        profile:
            form:
                type: AppBundle\Form\Type\ProfileFormType