3
votes

I'm migrating the website from symfony 2.6 to 3.4 and I have some trouble with registration forms and FOSUserBundle. I have this error popping-up. I checked his code and see that under his src\Pix\UserBundle\Form\RegistrationFormType.php but there is another folder "Type" with a file with the same name: "RegistrationFormType.php"

I tried modified the form with the newest style taking from there: https://github.com/symfony/symfony/blob/2.8/UPGRADE-2.8.md#form

app/config/config.yml:

fos_user:
    db_driver: orm
    firewall_name: main
    user_class: Pix\UserBundle\Entity\User
    registration:
        form:
            type: Pix\UserBundle\Form\RegistrationFormType
            validation_groups: [ pix_registration, Default ]

The service file under Pix/UserBundle/Resources/config/services.yml

services:
    pix_userbundle_registrationformtype:
        class: Pix\UserBundle\Form\Type\RegistrationFormType
        arguments: ["%fos_user.model.user.class%"]
        tags:
            - { name: form.type }

The Pix/UserBundle/Form/RegistrationFormType.php:

namespace Pix\UserBundle\Form;

use FOS\UserBundle\Form\Type\RegistrationFormType as BaseRegistrationFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;


class RegistrationFormType extends AbstractType
{

    public function __construct($class = "User")
    {
        parent::__construct($class);
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);

        $builder
            ->add('username', 'text', array(
                'label' => 'Pseudonyme',
            ))
            ->add('email', 'text', array(
                'label' => 'Adresse mail',
            ))
            ->add('plainPassword', 'repeated', array(
                'type' => 'password',
                'first_options' => array('label' => 'Mot de passe'),
                'second_options' => array('label' => 'Confirmation'),
                'invalid_message' => 'Mot de passe incorrect',
            ))
            ->add('enabled', 'checkbox', array(
                'label' => "Activé",
                'required' => false
            ))

            ->add('firstname', 'text', array(
                'label' => 'Prénom',
            ))
            ->add('lastname', 'text', array(
                'label' => 'Nom',
            ))
            ->add('phone', 'text', array(
                'label' => 'Téléphone',
            ))
            ->add('street', 'text', array(
                'label' => "Adresse postale",
                'required' => true
            ))
            ->add('number', 'text', array(
                'label' => "Numéro d'adresse",
                'required' => true
            ))
            ->add('npa', 'text', array(
                'label' => "Code postal",
                'required' => true
            ))
            ->add('city', 'text', array(
                'label' => "Ville",
                'required' => true
            ))
            ->add('state', 'text', array(
                'label' => "Canton",
                'required' => true
            ))
            ->add('country', 'text', array(
                'label' => "Pays",
                'required' => true
            ))
            ->add('latitude', 'text', array(
                'label' => "Latitude",
                'required' => true
            ))
            ->add('longitude', 'text', array(
                'label' => "Longitude",
                'required' => true
            ))
            ->add('code', 'text', array(
                'label' => 'Code de parrainage',
                'required' => false
            ))
            ->add('pro', 'choice', array(
                'label' => "Professionel",
                'choices'  => array(
                    true => 'Oui',
                    false => 'Non',
                ),
                'expanded' => false,
                'multiple' => false,
                'required' => true
            ))

            ->add('iban', 'text', array(
                'label' => 'IBAN',
                'required' => false
            ))
            ->add('distance', 'text', array(
                'label' => "Rayon d'intervention",
                'required' => false
            ))
            ->add('picture', new DocumentType(), array('required' => false))
            ->add('curriculum', new DocumentType(), array('required' => false))
            ->add('motivation', new DocumentType(), array('required' => false))
            ->add('document', new DocumentType(), array('required' => false))
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Pix\UserBundle\Entity\User'
        ));
    }
    public function getParent()
    {
        return BaseRegistrationFormType::class;
    }
    public function getBlockPrefix()
    {
        return 'pix_userbundle_registrationformtype';
    }
}

And finally the Pix/UserBundle/Form/Type/RegistrationFormType.php:

namespace Pix\UserBundle\Form\Type;

use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType;
use Symfony\Component\Form\AbstractType;
use Pix\UserBundle\Form\DocumentType;
use Pix\UserBundle\Entity\AbilityRepository;
use Symfony\Component\Form\Extension\Core\Type\TextType; 

class RegistrationFormType extends AbstractType
{

    public function __construct($class = "User")
    {
        parent::__construct($class);
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder->remove('username');
        $builder
            ->add('firstname', TexType::class, array(
                'label' => 'Prénom',
            ))
            ->add('lastname', TexType::class, array(
                'label' => 'Nom',
            ))
            ->add('phone', TexType::class, array(
                'label' => 'Téléphone',
            ))
            ->add('street', 'hidden')
            ->add('number', 'hidden')
            ->add('npa', 'hidden')
            ->add('city', 'hidden')
            ->add('state', 'hidden')
            ->add('country', 'hidden')
            ->add('latitude', 'hidden')
            ->add('longitude', 'hidden')
            ->add('code', TexType::class, array(
                'label' => 'Code de parrainage',
                'required' => false
            ))
            /*
            ->add('contact', 'choice', array(
                'label' => 'Moyen de contact favorisé',
                'choices'  => array(
                    true => 'Par téléphone',
                    false => 'Par e-mail',
                ),
                'expanded' => true,
                'multiple' => false,
                'required' => true
            ))
            */
            ->add('pro', 'choice', array(
                'label' => false,
                'choices'  => array(
                    true => 'Oui',
                    false => 'Non',
                ),
                'expanded' => false,
                'multiple' => false,
                'required' => true
            ))

            ->add('iban', TexType::class, array(
                'label' => 'IBAN',
                'required' => false
            ))
            ->add('distance', TexType::class, array(
                'label' => "Rayon d'intervention",
                'required' => false
            ))
            ->add('picture', new DocumentType(), array('required' => false))
            ->add('curriculum', new DocumentType(), array('required' => false))
            ->add('motivation', new DocumentType(), array('required' => false))
            ->add('document', new DocumentType(), array('required' => false))

            ->add('abilities', 'entity', array(
                'label' => 'Domaines de compétence',
                'attr' => array(
                    'class'=>'form-control multiselect'
                ),
                'class' => 'PixUserBundle:Ability',
                'property' => 'title',
                'multiple' => true,
                'expanded' => true,
                'required' => false,
                'query_builder' => function(AbilityRepository $er) {
                    return $er->getAbilities();
                },
            ))
            ->add('condition', 'checkbox', array('label' => "J'ai lu et j'accepte les conditions générales."))
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Pix\UserBundle\Entity\User',
            'intention'  => 'registration'
        ));
    }
    public function getBlockPrefix()
    {
        return 'pix_userbundle_registrationformtype';
    }
    public function getParent()
    {
    return RegistrationFormType::class;
    }
}

3
remove this line use FOS\UserBundle\Form\Type\RegistrationFormType; - by declaring that use statement you defining or using a class named RegistrationFormType - which is the same name as this class, then this part return RegistrationFormType::class; is ambiguous. - ArtisticPhoenix
These are either two different forms, although they look similar, or one of the files is an older version and not needed. Either way, it makes no sense why the webmaster has a use with the same class name there. Does FOS\UserBundle\Form\Type\RegistrationFormType exist? Keep in mind that with Symfony, they recommend having each form in it's own class but they should also have distinguishable names. - EternalHour
I had the same issue. after I fixed the namespace, the error message gone. - Raskul

3 Answers

5
votes

Its mainly due to your import or use statement having the same name as the class your defining:

use FOS\UserBundle\Form\Type\RegistrationFormType;

class RegistrationFormType extends AbstractType
{

For example take this code:

namespace foo{

    class class1{

    }

}
namespace bar{
    //use foo\class1;

    class class1{

    }
}

Sandbox

This works fine and produces no errors (as expected), however if you uncomment this line:

use foo\class1;

Output

<br />
<b>Fatal error</b>:  Cannot declare class bar\class1 because the name is already in use in <b>[...][...]</b> on line <b>14</b><br />

Sandbox

We should agree that the above example is roughly equivalent to what you are doing (which it is).

So basically whats happening is your defining this use statemnt:

use FOS\UserBundle\Form\Type\RegistrationFormType; 

Which allows you to use this class RegistrationFormType without the namespace, but as you are also defining that same class name, you get the error (see ambiguous below).

You can alias it, like so:

 use FOS\UserBundle\Form\Type\RegistrationFormType as FOSRegistrationFormType;

Then when you need something from that namespace you just use FOSRegistrationFormType. That said it looks like the only place your using it (maybe) is this method:

public function getParent()
{
    return RegistrationFormType::class;
}

I say "Maybe" because, the way it is it's ambiguous. I don't know if you want the class of the current object which is named RegistrationFormType or if you want FOS\UserBundle\Form\Type\RegistrationFormType::class. PHP doesn't know this either. If it's the class of the object then just do __CLASS__ and remove that use statment. If it's the other one (or you need that class somewhere I don't see), then just alias it and do FOSRegistrationFormType::class.

I agree the error message for this could be better, it should be something like use of class name RegistrationFormType is ambiguous or such. But that's not the case so we have to deal with it... This one has tripped me up a few times, which is why I basically instantly realized it.

I will share one last modification on my simple sandbox code:

namespace foo{

    class class1{

    }

}
namespace bar{
    use foo\class1 as f;

    class class1{
        public function test(){
            echo f::class;
        }
    }

    (new class1)->test();
}

Output

 foo\class1

Sandbox

Obviously use an alias that is more verbose then f but, this shows how you can alias it and then get the class from the alias, similar to what your code does.

PS While it's ugly, if you use it just the one time, there is no reason you can't just use the fully qualified name (namespace/class) for that, just make sure there is a leading \ (think of it how relative paths work) as in:

  \FOS\UserBundle\Form\Type\RegistrationFormType::class

Hope it helps.

3
votes

I encountered this error due to a misconfiguration in the services.yml file:

App\:
    resource: '../src/*'
    exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'

Example\:
    resource: '../src/Example/*'
    public: true

This would cause Symfony to try to load classes under the Example namespace as App\Example

You need to make sure you add any custom namespaces to the exclude list for App as well, as follows:

App\:
    resource: '../src/*'
    exclude: '../src/{Entity,Migrations,Tests,Kernel.php,Example}'
0
votes

I had such that there was a name conflict when forming the Doctrine cache for entities.

A conflict arises in this case (illustrative example):

class AlphaBeta {}

A cache file is generated for it: __CG__AlphaBeta.php.

namespace Alpha;

class Beta {}

A cache file is also generated for it: __CG__AlphaBeta.php and a name conflict is obtained! Those. the cache of only one class is stored and this provokes an error!

P.S. The path to the entity files cache is like this: ./var/cache/prod/doctrine/orm/Proxies