FosUser creation formulaire /register et /pro/register

Default
,

Bonjour,

Voila je rencontre un petit problème avec mon code, J'ai suivis tuto de jeffcoding sur youtube, mais je suis sur symfony 3.4 et une erreur est levée pour /pro/register alors que /register fonctionne parfaitement.

Ce que je fais

namespace AppBundle\Entity;

use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="fos_user")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="firstName", type="string", length=255)
     */
    private $firstName;

    /**
     * @var string
     * @ORM\Column(name="lastName", type="string", length=255)
     */
    private $lastName;

    /**
     * @var string
     * @ORM\Column(name="corporateName", type="string", length=255, nullable=true)
     */
    private $corporateName;

    /**
     * @var string
     * @ORM\Column(name="legalForm", type="string", length=255, nullable=true)
     */
    private $legalForm;

    /**
     * @var int
     * @ORM\Column(name="tva", type="integer", nullable=true)
     */
    private $tva;

    /**
     * @var string
     * @ORM\Column(name="street", type="string", length=255)
     */
    private $street;

    /**
     * @var int
     * @ORM\Column(name="number", type="integer")
     */
    private $number;

    /**
     * @var string
     * @ORM\Column(name="box", type="string", nullable=true)
     */
    private $box;

    /**
     * @var int
     * @ORM\Column(name="postalCode", type="integer")
     */
    private $postalCode;

    /**
     * @var string
     * @ORM\Column(name="city", type="string", length=255)
     */
    private $city;

    /**
     * @var int
     * @ORM\Column(name="nbrchildren", type="integer", nullable=true)
     */
    private $nbrchildren;

    public function __construct()
    {
        parent::__construct();
        // your own logic
    }

    /**
     * Set firstName
     *
     * @param string $firstName
     *
     * @return User
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;

        return $this;
    }

    /**
     * Get firstName
     *
     * @return string
     */
    public function getFirstName()
    {
        return $this->firstName;
    }

    /**
     * Set lastName
     *
     * @param string $lastName
     *
     * @return User
     */
    public function setLastName($lastName)
    {
        $this->lastName = $lastName;

        return $this;
    }

    /**
     * Get lastName
     *
     * @return string
     */
    public function getLastName()
    {
        return $this->lastName;
    }

    /**
     * Set corporateName
     *
     * @param string $corporateName
     *
     * @return User
     */
    public function setCorporateName($corporateName)
    {
        $this->corporateName = $corporateName;

        return $this;
    }

    /**
     * Get corporateName
     *
     * @return string
     */
    public function getCorporateName()
    {
        return $this->corporateName;
    }

    /**
     * Set legalForm
     *
     * @param string $legalForm
     *
     * @return User
     */
    public function setLegalForm($legalForm)
    {
        $this->legalForm = $legalForm;

        return $this;
    }

    /**
     * Get legalForm
     *
     * @return string
     */
    public function getLegalForm()
    {
        return $this->legalForm;
    }

    /**
     * Set tva
     *
     * @param integer $tva
     *
     * @return User
     */
    public function setTva($tva)
    {
        $this->tva = $tva;

        return $this;
    }

    /**
     * Get tva
     *
     * @return integer
     */
    public function getTva()
    {
        return $this->tva;
    }

    /**
     * Set street
     *
     * @param string $street
     *
     * @return User
     */
    public function setStreet($street)
    {
        $this->street = $street;

        return $this;
    }

    /**
     * Get street
     *
     * @return string
     */
    public function getStreet()
    {
        return $this->street;
    }

    /**
     * Set number
     *
     * @param integer $number
     *
     * @return User
     */
    public function setNumber($number)
    {
        $this->number = $number;

        return $this;
    }

    /**
     * Get number
     *
     * @return integer
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * Set box
     *
     * @param integer $box
     *
     * @return User
     */
    public function setBox($box)
    {
        $this->box = $box;

        return $this;
    }

    /**
     * Get box
     *
     * @return integer
     */
    public function getBox()
    {
        return $this->box;
    }

    /**
     * Set postalCode
     *
     * @param integer $postalCode
     *
     * @return User
     */
    public function setPostalCode($postalCode)
    {
        $this->postalCode = $postalCode;

        return $this;
    }

    /**
     * Get postalCode
     *
     * @return integer
     */
    public function getPostalCode()
    {
        return $this->postalCode;
    }

    /**
     * Set city
     *
     * @param string $city
     *
     * @return User
     */
    public function setCity($city)
    {
        $this->city = $city;

        return $this;
    }

    /**
     * Get city
     *
     * @return string
     */
    public function getCity()
    {
        return $this->city;
    }

    /**
     * Set nbrchildren
     *
     * @param integer $nbrchildren
     *
     * @return User
     */
    public function setNbrchildren($nbrchildren)
    {
        $this->nbrchildren = $nbrchildren;

        return $this;
    }

    /**
     * Get nbrchildren
     *
     * @return integer
     */
    public function getNbrchildren()
    {
        return $this->nbrchildren;
    }
}
namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class RegistrationType extends AbstractType
{

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

            ->add('lastName', null, ["label"=>"Nom"])
            ->add('firstName', null, ["label"=>"Prénom"])
            ->add('street', null, ["label"=>"Rue"])
            ->add('number', null, ["label"=>"Numéro"])
            ->add('box', null, ["label"=>"Boîte"])
            ->add('postalCode', null, ["label"=>"Code Postal"])
            ->add('city', null, ["label"=>"Ville"])
            ->add('nbrchildren', null, ["label"=>"Nombre(s) d'enfant(s)"])
        ;
    }

    public function getParent()
    {
        return 'FOS\UserBundle\Form\Type\RegistrationFormType';
    }

    public function getBlockPrefix()
    {
        return 'app_user_registration';
    }
}

namespace AppBundle\Form;

use FOS\UserBundle\Form\Type\RegistrationFormType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;

class ProRegistrationType extends RegistrationFormType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('corporateName', textType::class, ["label"=>"Nom de l'entreprise"])
            ->add('legalForm', textType::class, ["label"=>"Forme juridique"])
            ->add('tva', textType::class)
            ->add('lastName', textType::class)
            ->add('firstName', textType::class)
            ->add('street', textType::class)
            ->add('number', IntegerType::class)
            ->add('box', textType::class)
            ->add('postalCode', IntegerType::class)
            ->add('city', textType::class)
            ->add('nbrchildren')

        ;
    }



    public function getBlockPrefix()
    {
        return 'app_user_pro_registration';
    }
}

namespace AppBundle\Controller;


use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\RegistrationController as BaseController;
use AppBundle\Form\ProRegistrationType;
use Symfony\Component\Routing\Annotation\Route;
use FOS\UserBundle\Form\Factory\FactoryInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;




class RegistrationController extends BaseController
{
    /**
     * @Route("/pro/register", name="app_user_pro_register")
     */
    public function registerProAction(Request $request)
    {

        /** @var $formFactory FactoryInterface */
        $formFactory = $this->get('form.factory');
        /** @var $userManager UserManagerInterface */
        $userManager = $this->get('fos_user.user_manager');
        /** @var $dispatcher EventDispatcherInterface */
        $dispatcher = $this->get('event_dispatcher');

        $user = $userManager->createUser();
        $user->setEnabled(true);
        $user->addRole('ROLE_PRO');

        $event = new GetResponseUserEvent($user, $request);
        $dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, $event);

        if (null !== $event->getResponse()) {
            return $event->getResponse();
        }

        //$form = $formFactory->createForm();
        $form = $formFactory->create(new ProRegistrationType($this->container->getParameter("fos_user.model.user.class")));
        $form->setData($user);

        $form->handleRequest($request);

        if ($form->isSubmitted()) {
            if ($form->isValid()) {
                $event = new FormEvent($form, $request);
                $dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);

                $userManager->updateUser($user);

                if (null === $response = $event->getResponse()) {
                    $url = $this->generateUrl('fos_user_registration_confirmed');
                    $response = new RedirectResponse($url);
                }

                $dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));

                return $response;
            }

            $event = new FormEvent($form, $request);
            $dispatcher->dispatch(FOSUserEvents::REGISTRATION_FAILURE, $event);

            if (null !== $response = $event->getResponse()) {
                return $response;
            }
        }

        return $this->render('@Appbundle/Registration/register.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

    app.form.registration:
        class: AppBundle\Form\RegistrationType
        tags:
            - { name: form.type, alias: app_user_registration }

    app_user_pro.pro.registration:
        class: AppBundle\Form\ProRegistrationType
        arguments: [fos_user.model.user.class]
        tags :
            - { name: form.type, alias: app_user_pro_registration }

Ce que je veux

Mon but est simplement que sur les 2 formulaires, les infos communes s'affichent, et les infos propre à chaque condition, à savoir user particulier, et user professionnel.

Ce que j'obtiens

Voici l'erreur:
Expected argument of type "string", "AppBundle\Form\ProRegistrationType" given

En cherchant l'erreur viens de la ligne : $form = $formFactory->create(new ParentRegistrationType($this->container->getParameter('fos_user.model.user.class')));
du contrôleur qui n'est plus actualité dans symfony 3.

Je ne parviens pas à y remedier.... Si quelq'un a une idée, je suis preneur.......

Merci d'avance à vous tous ;)

Personne ne peux m'aider? .....

11 Réponse

Default
,

Bonjour liberatio
Je suis dans la meme situation que toi. As-tu finalement trouvé une reponse ?

87112
,

Hello!
La réponse ici : https://api.symfony.com/3.3/Symfony/Component/Form/FormFactory.html
La méthode create de ton form factory ne demande pas un objet, mais un string...
Essaye de remplacer :

$form = $formFactory->create(new ProRegistrationType($this->container->getParameter("fos_user.model.user.class")));

par

$form = $formFactory->create('AppBundle\Form\ProRegistrationType', $user);

Ca donne quoi?...

Petite remarque, ton listener ne devrait pas se trouver dans ton controller, mais dans un listener (class propre), voire dans ton Form...
Les controllers ne devraient pas contenir de logique métier (https://symfony.com/doc/current/best_practices/controllers.html)

Default
,

Merci Digivia. J'avais essayé $form = $formFactory->create('UsersBundle\Form\ProRegistrationType', $user); , mais symfony me renvoi cela :
Warning: Missing argument 1 for FOS\UserBundle\Form\Type\RegistrationFormType::__construct(), called in C:\wamp64\www\site\vendor\symfony\symfony\src\Symfony\Component\Form\FormRegistry.php on line 92 and defined

Je ne suis pas sûr de ce que doit contenir $user (mon formulaire devrait pouvoir en créer un nouveau)

Merci pour le conseil sur les listeners, je vais changer cela egalement.

87112
,

sylvigouroux, tu devrais aller jeter un oeil à la doc : https://symfony.com/doc/master/bundles/FOSUserBundle/overriding_forms.html
Ca parait répondre à ton besoin, non?

Default
,

En fait, j'avais bien lu la doc, mais ils expliquent simplement comment surcharger un form pour tous les formulaires d’enregistrement FOSUser.
Mon besoin est different. je voudrais créer deux types de Form : un pour les utilisateurs ROLE_USER, et un autre pour les ROLE_PRO, avec un filtrage des entités a renseigner pour le role_user et une inscription utilisant une vue spécifique en role_pro. Autrement dit, je cherche à créer des utilisateurs avec des attributs différents et pouvant s'inscrire sur des pages différentes… bref, je voudrais surcharger le contrôleur lui-même.
Mais visiblement, ça n’est pas vraiment prévu par FOSUser… ou il faudrait bidouiller (ce qui est bien au-dessus de mon niveau).
Du coup, je me suis contenté de faire un form à la main en méthode GET… faute de mieux.

Merci beaucoup pour ton aide.

87112
,

Tu peux bien surcharger le controller de fos_user : https://symfony.com/doc/current/bundles/FOSUserBundle/overriding_controllers.html
Par contre, dans le code de @liberatio, je ne comprends pas bien la définition des 2 formulaires? Pourquoi le Pro n'a-t-il pas pour parent le form fos comme l'autre :

public function getParent()
    {
        return 'FOS\UserBundle\Form\Type\RegistrationFormType';
    }

Et pourquoi la définition du service est différente? Quel est le but?

Default
,

Merci pour la doc sur la surcharge ! Je n'avais pas configuré le bundle comme indiqué dans le lien. Ca marche, c'est top.
Je voulais surcharger surtout pour attribuer un role particulier aux utilisateurs courants. Je ne suis donc pas allé plus loin (un form dans la vue me suffit pour l'instant). Mais l'idée de @liberatio serait, si j'ai bien compris, d'avoir deux formulaires differents : un user et un pro. Certains champs seraient affichés pour les pro seulement et les formulaires se lanceraient par deux url differentes : app_dev.php/register et app_dev.php/pro/register
Cf. https://www.youtube.com/watch?v=Y797Rr5ypQk
Bon, j'ai beau débuter sur symfony, ca ne me semble un peu tiré par les cheveux tout de même. Quel est l'interet de surcharger TOUS les élements de FOSuser : le form, les entités et le controleur d'enregistrement ? Surtout que l'on s'en sort très bien avec un formulaire fait a la mano dans la vue... non ?

87112
,

Sylvigouroux,
C'est le principe de base de Symfony, et c'est pour cela que c'est génial, tu peux tout surcharger!
C'est suivant tes besoins, dans certains cas, il peut être utile de surcharger pas mal de choses.
Après sur un bundle tiers comme fos user, si tu commences à avoir besoin de tout surcharger, tu repars from scratch et tu dev à partir de la brique sécu (très bien pensée) de Symfony. Fos user est très bien si ton besoin est standard, j'entends par là proche de la philsophie de ce bundle. Rien n'est imposé par Symfony (surtout pas des bundles tiers!), et c'est tout l'intérêt de ce framework.
Ce qu'il amène de plus important, ce sont les bonnes pratiques et une manières moderne de développer (interfaces, modularité, etc.). Regarde du côté de la V4 de Symfony, c'est exactement ça! Use what you need....

Default
,

Merci pour les explications sur la philosophie Symfony. C'est assez important quand l’on débute pour cerner les bonnes pratiques. Bien compris. Sinon, il faudrait que je passe à la 4 en effet... mais j'ai quelques (c’est un euphémisme) dépréciations à régler auparavant.

87112
,

Tu peux passer par la 3.3 puis 3.4 pour résoudre tes dépréciations.
Pour la V4, regarde quand même le temps à passer, si ton app est bien avancée, ça vaut peut-être le coup de rester en 3.4 (qui est LTS, donc support 3 ans)... Pour un nouveau projet ça vaut le coup, pour de l'existant, il faut mesurer, pas forcément rentable (changements de directories, namespaces, ect.)... Sauf si tu as un manque de perfs (les benchmark de la V4 sont hallucinants).
PS : tu as tout compris, l'utilisation des bonnes pratiques est l'élément le plus important :)

Default
,

Salut je sais que le sujet est vieux mais je rencontre la meme difficulté ... @sylvigouroux peux tu m'expliquer comment tu as résolu le problème après avoir suivi le meme tuto sur youtube? J'espere que vous me repondrez...Merci d'avance