Bonjour,

Lorsqu'un utilisateur qui veut s'enregistrer, je lui demande si c'est un utilisateur standart ou spécifique.
Si ce dernier est spécifique, il à des champs supplémntaire à remplir, et il ne dois pas être valider de suite, car il y aura une phase de validation manuel du coté admin.

J'ai donc une entité user et professionnel, qui sont en relation.

User:

<?php

namespace AppBundle\Entity;

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

/**
 * User
 *
 * @ORM\Table(name="sy_user")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 */
class User extends BaseUser
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="Professional", mappedBy="user", cascade={"persist","remove"})
     */
    protected $professional;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="created", type="datetime")
     */
    protected $created;

    /**
     * @var bool
     *
     * @ORM\Column(name="enable", type="boolean")
     */
    protected $enable;

    /**
     * @var bool
     *
     * @ORM\Column(name="newsletter", type="boolean")
     */
    protected $newsletter;

    /**
     * @var string
     *
     * @ORM\Column(name="lastname", type="string", length=255)
     *
     * @Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"})
     * @Assert\Length(
     *     min=3,
     *     max=255,
     *     minMessage="The name is too short.",
     *     maxMessage="The name is too long.",
     *     groups={"Registration", "Profile"}
     * )
     */
    protected $lastname;

    /**
     * @var string
     *
     * @ORM\Column(name="firstname", type="string", length=255, nullable=true)
     *
     * @Assert\Length(
     *     min=3,
     *     max=255,
     *     minMessage="The name is too short.",
     *     maxMessage="The name is too long.",
     *     groups={"Registration", "Profile"}
     * )
     */
    protected $firstname;

    /**
     * @var string
     *
     * @ORM\Column(name="phone", type="string", length=25)
     *
     * @Assert\NotBlank(message="Please enter your phone.", groups={"Registration", "Profile"})
     * @Assert\Length(
     *     min=10,
     *     max=25,
     *     minMessage="Your phone is too short.",
     *     maxMessage="Your phone is too long.",
     *     groups={"Registration", "Profile"}
     * )
     */
    protected $phone;

    /**
     * @var string
     *
     * @ORM\Column(name="cellphone", type="string", length=25, nullable=true)
     *
     * @Assert\Length(
     *     min=10,
     *     max=25,
     *     minMessage="Your cell phone is too short.",
     *     maxMessage="Your cell phone is too long.",
     *     groups={"Registration", "Profile"}
     * )
     */
    protected $cellphone;

    /**
     * @var string
     *
     * @ORM\Column(name="fax", type="string", length=25, nullable=true)
     *
     * @Assert\Length(
     *     min=10,
     *     max=25,
     *     minMessage="Your fax is too short.",
     *     maxMessage="Your fax is too long.",
     *     groups={"Registration", "Profile"}
     * )
     */
    protected $fax;

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

     public function __construct()
    {
        parent::__construct();
        $this->created      = new \DateTime();
        $this->professional = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set created
     *
     * @param \DateTime $created
     *
     * @return User
     */
    public function setCreated($created)
    {
        $this->created = $created;

        return $this;
    }

    /**
     * Get created
     *
     * @return \DateTime
     */
    public function getCreated()
    {
        return $this->created;
    }

    /**
     * Set enable
     *
     * @param boolean $enable
     *
     * @return User
     */
    public function setEnable($enable)
    {
        $this->enable = $enable;

        return $this;
    }

    /**
     * Get enable
     *
     * @return bool
     */
    public function getEnable()
    {
        return $this->enable;
    }

    /**
     * Set newsletter
     *
     * @param boolean $newsletter
     *
     * @return User
     */
    public function setNewsletter($newsletter)
    {
        $this->newsletter = $newsletter;

        return $this;
    }

    /**
     * Get newsletter
     *
     * @return bool
     */
    public function getNewsletter()
    {
        return $this->newsletter;
    }

    /**
     * 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 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 phone
     *
     * @param string $phone
     *
     * @return User
     */
    public function setPhone($phone)
    {
        $this->phone = $phone;

        return $this;
    }

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

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

        return $this;
    }

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

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

        return $this;
    }

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

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

        return $this;
    }

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

    /**
     * Add professional
     *
     * @param \AppBundle\Entity\Product $professional
     *
     * @return User
     */
    public function addProfessional(\AppBundle\Entity\Product $professional)
    {
        $this->professional[] = $professional;

        return $this;
    }

    /**
     * Remove professional
     *
     * @param \AppBundle\Entity\Product $professional
     */
    public function removeProfessional(\AppBundle\Entity\Product $professional)
    {
        $this->professional->removeElement($professional);
    }

    /**
     * Get professional
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getProfessional()
    {
        return $this->professional;
    }
}

Profesionnal

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Professional
 *
 * @ORM\Table(name="sy_professional")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ProfessionalRepository")
 */
class Professional
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="professional", cascade={"persist"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $user;

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

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

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

    /**
     * @var bool
     *
     * @ORM\Column(name="paymentPeriod", type="boolean")
     */
    private $paymentPeriod;

    /**
     * @var bool
     *
     * @ORM\Column(name="deleveryReims", type="boolean")
     */
    private $deleveryReims;

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

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

    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set company
     *
     * @param string $company
     *
     * @return Professional
     */
    public function setCompany($company)
    {
        $this->company = $company;

        return $this;
    }

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

    /**
     * Set siret
     *
     * @param integer $siret
     *
     * @return Professional
     */
    public function setSiret($siret)
    {
        $this->siret = $siret;

        return $this;
    }

    /**
     * Get siret
     *
     * @return int
     */
    public function getSiret()
    {
        return $this->siret;
    }

    /**
     * Set icVat
     *
     * @param string $icVat
     *
     * @return Professional
     */
    public function setIcVat($icVat)
    {
        $this->icVat = $icVat;

        return $this;
    }

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

    /**
     * Set paymentPeriod
     *
     * @param boolean $paymentPeriod
     *
     * @return Professional
     */
    public function setPaymentPeriod($paymentPeriod)
    {
        $this->paymentPeriod = $paymentPeriod;

        return $this;
    }

    /**
     * Get paymentPeriod
     *
     * @return bool
     */
    public function getPaymentPeriod()
    {
        return $this->paymentPeriod;
    }

    /**
     * Set deleveryReims
     *
     * @param boolean $deleveryReims
     *
     * @return Professional
     */
    public function setDeleveryReims($deleveryReims)
    {
        $this->deleveryReims = $deleveryReims;

        return $this;
    }

    /**
     * Get deleveryReims
     *
     * @return bool
     */
    public function getDeleveryReims()
    {
        return $this->deleveryReims;
    }

    /**
     * Set maxWeight
     *
     * @param integer $maxWeight
     *
     * @return Professional
     */
    public function setMaxWeight($maxWeight)
    {
        $this->maxWeight = $maxWeight;

        return $this;
    }

    /**
     * Get maxWeight
     *
     * @return int
     */
    public function getMaxWeight()
    {
        return $this->maxWeight;
    }

    /**
     * Set comment
     *
     * @param string $comment
     *
     * @return Professional
     */
    public function setComment($comment)
    {
        $this->comment = $comment;

        return $this;
    }

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

    /**
     * Set user
     *
     * @param \AppBundle\Entity\User $user
     *
     * @return Professional
     */
    public function setUser(\AppBundle\Entity\User $user = null)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * Get user
     *
     * @return \AppBundle\Entity\User
     */
    public function getUser()
    {
        return $this->user;
    }
}

Et ma surcharge du formulaire registration de FOS

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

class RegistrationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
             ->add('enable', HiddenType::class, array(
                                                    'data' => 1,
                                                    ))
            ->add('newsletter', CheckboxType::class, array('required' => false,))
            ->add('lastname', TextType::class)
            ->add('firstname', TextType::class, array('required' => false,))
            ->add('phone', TextType::class)
            ->add('cellphone', TextType::class, array('required' => false,))
            ->add('fax', TextType::class, array('required' => false,))
            ->add('type', ChoiceType::class, array(
                                                   'choices' => array(
                                                                      'Administration' => 'admin',
                                                                      'Association' => 'assoc',
                                                                      'Particular' => 'parti',
                                                                      'Professional' => 'profe',
                                                                      ),
                                                    'preferred_choices' => array('parti', 'profe')
                                                   ))
            ->add('professional', EntityType::class, array(
                                                           'class' => 'AppBundle:Professional',
                                                           ));
    }

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

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

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

Le formulaire s'affiche correctement, mais je n'ai pas les champs correspondant à mon entité professional.

Je but dessus depuis plusieurs jours, c'est pourquoi je me tourne vers vous, je suis sur symfony 3.0.

Merci d'avance pour votre aide.

8 réponses


Bonjour,

Ton attribut professional est une ArrayCollection. Par conséquent, dans ton formulaire si ton ArrayCollection est vide il n'affichera rien. Si quand un utilisateur s'enregistre il ne peut travailler que pour une société, alors il te suffit d'ajouter manuellement un item vide de type Professional. Dans le cas contraire, il te faut ajouter un bouton qui permet à l'utilisateur d'ajouter toutes les sociétés. Pour ça, tu peux regarder la documentation officielle http://symfony.com/doc/current/cookbook/form/form_collections.html. Tu peux aussi faire un mixe, ajouter manuellement un premier item et permettre d'en ajouter d'autre.

astavrou
Auteur

Bonjour,

Merci pour ta réponse.

Donc si je comprends bien je retire "professional" du registrationType, et je le rajoute manuellement dans le template ?
Mais si le client n'est pas un particulier, il me faut au moins le nom de la company, mais égalment la possibilité de renseigner le siret et le numéro intra communautaire.

En tout cas merci pour la piste, car là je désepéré.

Alors non, mais avant que je te répondre, peux tu me montrer la méthod de ton controller.

astavrou
Auteur

En faite j'utilise le bundle FOS User, dans lequel j'ai surchager la class User et le formulaire registration (mis dans le premier post).
Le controller de FOS User

<?php

/*
 * This file is part of the FOSUserBundle package.
 *
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace FOS\UserBundle\Controller;

use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use FOS\UserBundle\Model\UserInterface;

/**
 * Controller managing the registration
 *
 * @author Thibault Duplessis <thibault.duplessis@gmail.com>
 * @author Christophe Coevoet <stof@notk.org>
 */
class RegistrationController extends Controller
{
    public function registerAction(Request $request)
    {
        /** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
        $formFactory = $this->get('fos_user.registration.form.factory');
        /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
        $userManager = $this->get('fos_user.user_manager');
        /** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
        $dispatcher = $this->get('event_dispatcher');

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

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

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

        $form = $formFactory->createForm();
        $form->setData($user);

        $form->handleRequest($request);

        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;
        }

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

Comme vous avez dit plus haut, un client appartiendra à une seule société, mais il doit renseigner au minimum son nom de société, champ qui se trouve dans l'entité professional (voir 1er post).

J'ai essayé de courcicuiter le controller de FOS, en regardant la documentation Symfony, mais il me met des erreur de service.

Encore merci de prendre du temps pour essayer de ésoudre mon problème.

Dans ton RegistrationType, ajoute à la méthode "buildForm" :

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event)
{
    $user = $event->getData();
    $user->addProfessional(new Professional()); //avec ça l'ArrayCollection aura un item Professional vide
    $event->setData($user);
});

Pour la documentation http://symfony.com/doc/current/components/form/form_events.html

Après, il te faudra peut-être un autre EventLister sur ton formulaire pour vider "professional" si l'utiliateur ne travail pas dans une société.

astavrou
Auteur

J'ai donc procéder à la modification de mon RegistrationType :

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormEvents;

class RegistrationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
             ->add('enable', HiddenType::class, array(
                                                    'data' => 1,
                                                    ))
            ->add('newsletter', CheckboxType::class, array('required' => false,))
            ->add('lastname', TextType::class)
            ->add('firstname', TextType::class, array('required' => false,))
            ->add('phone', TextType::class)
            ->add('cellphone', TextType::class, array('required' => false,))
            ->add('fax', TextType::class, array('required' => false,))
            ->add('type', ChoiceType::class, array(
                                                   'choices' => array(
                                                                      'Administration' => 'admin',
                                                                      'Association' => 'assoc',
                                                                      'Particular' => 'parti',
                                                                      'Professional' => 'profe',
                                                                      ),
                                                    'preferred_choices' => array('parti', 'profe')
                                                   ))
            ->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
    }

    public function onPreSetData(FormEvent $event)
    {
        $user = $event->getData();
        $user->addProfessional(new Professional()); //avec ça l'ArrayCollection aura un item Professional vide
        $event->setData($user);
    }

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

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

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

Voici l'erreur qui apparaît :
Catchable Fatal Error: Argument 1 passed to AppBundle\Form\RegistrationType::onPreSetData() must be an instance of AppBundle\Form\FormEvent, instance of Symfony\Component\Form\FormEvent given

J'avoue que j'ai du mal là, je ne comprends pas la logique.

Il te manque un use

use Symfony\Component\Form\FormEvent;

Normalement, avec la doc de mes messages précédents, tu devrais pouvoir comprendre. Il y a d'autres solutions que celle que je t'ai proposée. Mais, je t'ai proposé celle-ci pour éviter de toucher au controller du bundle FOS User.

Après, tu peux attendre l'aide d'une autre personne. Je comprends ton soucis, mais peut-être que je n'arrive pas à t'expliquer suffisamment bien.

astavrou
Auteur

Je te remercie, je vais creuser un peu tout ça.