Bonjour,
Je fais encore appel à vous pour un problème que je n'arrive pas à résoudre.

Je souhaite récupérer dans un formulaire des objets que j'ai dans mes entités.
Ici, je veux par exemple avoir dans mon formulaire, une liste déroulante avec tous les users de mon objet usertype.
J'ai lu dans la doc symfony quelque chose qui me semble adapté :

    class ProjetType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('user', EntityType::class, array(
                'class' => 'structureBundle:User',
                'choices' => $usertype->getUsers(),
                'label' => 'Attribuer un utilisateur au projet : ',                
                ))  
            ->add('save', SubmitType::class, array('label' => 'Démarrer un nouveau projet : '))              
        ;
    }

Le problème est que je n'arrive pas à passer mon objet usertype dans mon buildForm, depuis mon controller.

$form = $this->createForm(ProjetType::class, $projet);

Avez-vous une idée pour comment passer mon objet usertype à mon ProjetType ?

Par avance merci !
Nans

13 réponses


skp
Réponse acceptée

Si je comprends bien, tu veux dans ta liste déroulante uniquement les users qui sont liés à l'entreprise en question. Dans un premier temps il faut assigner $entreprise à $projet.

class ProjetController extends Controller
{
    public function newAction(Request $request, $entreprise_id){
        $projet = new Projet();
        $em = $this->getDoctrine()->getManager();
        $entreprise = $em->getRepository("\structureBundle\Entity\Entreprise")->findOneById($entreprise_id); //n'oublie pas de vérifie que tu recois bien un résultat
        $projet->setEntreprise($entreprise);
        $form = $this->createForm(ProjetType::class, $projet);

Ensuite, dans ton ProjetType :

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class ProjetType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('save', SubmitType::class, array('label' => 'Démarrer un nouveau projet : '))
            //pour comprendre les Form Events lis la doc en fin de mon message
            ->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
                $projet = $event->getData(); //ici tu récupère ton objet Projet avec l'entreprise que tu lui as assigné.
                $event->getForm()->add('user', EntityType::class, array(
                    'class' => 'structureBundle:User',
                    'query_builder' => function (EntityRepository $er) use ($projet) {
                        //je te laisserais regarder la doc pour le query_builder. Mais tu dois return un QueryBuilder, sois que tu fais directement ici, soit que tu as fais dans ton repository. Dans mon cas, je pars du principe que tu le fais dans ton repository
                        return $er->qbGetUsersByEntreprise($projet->getEntreprise()->getId()); //suis nul pour donner des noms à mes méthodes ^^ Mais la tu construit une requête qui va chercher les utilisateurs de ton entreprise uniquement
                    },
                    'label' => 'Attribuer un utilisateur au projet : ',
                ));
            };
    }

Pour comprendre voici les différentes docs :

J'espère que ce n'est pas trop en un post et j’insiste sur le fait que tu dois regarder la doc. Parce que, oui je te donne une solution. Mais si tu ne la comprends pas, tu seras surement bloquer plus tard ou dans un futur de tes projets sous symfony.

Bonjour,
Tu n'as pas précisé quelle version de Symfony tu utilises, car la syntaxe change selon les versions.

Voici ce que je préconise:

  • Remplacer 'EntityType::class' par 'entity'
  • Ajoute un paramètre choice_label afin de préciser quelle valeur tu veux afficher dans la liste déroulante
  • Enfin dans ton create_form() du controller, remplace ProjetType::class par new ProjetType()

En résumé :

<?php
public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('user', 'entity', array(
                'class' => 'structureBundle:User',
                'choice_label' => function ($user) {
                    return $user->getName();  // Mettre ici le nom de ta méthode à la place si tu n'as pas d'attribut n...
                }
                'label' => 'Attribuer un utilisateur au projet : ',                
                ))  
            ->add('save', new SubmitType(), array('label' => 'Démarrer un nouveau projet : '))              
        ;
    }
?>

J'ai enlevé l'attribut 'choice' car pour moi tu n'en as pas besoin,
Cette syntaxe fonctionne sous Symfony 2.7 et 2.8, à tester sur ta version...

N'oublie pas d'inclure les namespaces relatifs aux types:
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

nans
Auteur

Merci pour ta réponse. Je suis sur symfony3.
Le problème et que je ne veux pas qu'il y ait tous mes users dans ma liste déroulante. Je veux seulement ceux qui sont reliées à une entreprise en particulier.
Mon problème est donc de savoir comment faire pour sélectionner uniquement ceux que je souhaite. Je vais modifier les noms car ce n'est pas très explicite sur mon premier poste :

    class ProjetType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('user', EntityType::class, array(
                'class' => 'structureBundle:Entreprise',
                'choices' => $entreprise->getUsers(),
                'label' => 'Attribuer un utilisateur au projet : ',                
                ))  
            ->add('save', SubmitType::class, array('label' => 'Démarrer un nouveau projet : '))              
        ;
    }

Je ne sais pas comment passer mon $entreprise de mon controller à mon form

Bonsoir, avant de commencer le conseil de @Eyo de "Remplacer 'EntityType::class' par 'entity'" est déprécié depuis la version 2.8 (normalement dans la barre en bas tu as un warning). Par conséquent, garde ta syntaxe elle est correct. Avant de te donner une solution, j'aimerais bien voir ton controller.

nans
Auteur

Bonsoir skp. Voici ce qu'il y a dans mon controller jusqu'à l'appel du formulaire :

class ProjetController extends Controller
{
    public function newAction(Request $request, $entreprise_id){
        $projet = new Projet();
        $em = $this->getDoctrine()->getManager();
        $entreprise = $em->getRepository("\structureBundle\Entity\Entreprise")->findOneById($entreprise_id); 
        $form = $this->createForm(ProjetType::class, $projet);

Désolé, mais montre moi aussi ton entité Projet ^^

nans
Auteur

No pb

<?php

namespace structureBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Projet
 *
 * @ORM\Table(name="projet")
 * @ORM\Entity(repositoryClass="structureBundle\Repository\ProjetRepository")
 */
class Projet
{
    /**
     * @ORM\OneToOne(targetEntity="Liste")
     * @ORM\JoinColumn(name="liste_id", referencedColumnName="id", nullable=false)
     */
    protected $liste;

    /**
     * @ORM\OneToOne(targetEntity="EntBundle\Entity\Init")
     */
    protected $init;    

    /**
     * @ORM\OneToOne(targetEntity="EntBundle\Entity\Formulaire")
     * @ORM\JoinColumn(name="formulaire_id", referencedColumnName="id", nullable=true)
     */
    private $formulaire;      

    /**
     * @ORM\ManyToOne(targetEntity="Entreprise", inversedBy="projets")
     * @ORM\JoinColumn(name="entreprise_id", referencedColumnName="id", nullable=true)
     */
    protected $entreprise;

    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="projets")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $user;

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

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

Après il y a évidemment tous les getters et setters.

nans
Auteur

Merci skp. Je teste ça.
Oui je lis la doc, malgré mon pitoyable niveau en Anglais. (pour témoigner de mon investissement, je ne savais pas ce qu'était php le 25 Décembre 2015 et j'ai découvert symfony et la POO ce 15 Janvier, je passe beaucoup de temps sur mon projet).

nans
Auteur

Si je comprends bien la démarche, il y a un pré formulaire qui me permets de définir l'entreprise et ensuite, en fonction de l'entreprise, la suite du formulaire m'affichera les bons utilisateurs. C'est cela ?

Enfaite ton formulaire à plusieurs événements et tu as l'occasion lors de ces événements de faire des actions.
Si je ne fais pas d'erreur :

  1. Création du formulaire avec les valeurs des champs à vides
  2. Event PRE_SET_DATA
  3. Je remplie le formulaire avec les valeurs passées à createForm() (2ème paramètre)
  4. Event POST_SET_DATA
    Dans ton cas, tu as besoin de connaitre l'entreprise. Par conséquent, c'est l'événement POST_SET_DATA qui t'intéresse. N'oublie pas que dans ma solution, si tu n'attribues pas d'entreprise à ton Projet. Ben tu auras une erreur dans le code.

Je tiens quand même à te féliciter, pour je dirais ton apprentissage rapide et en plus tu n'as pas choisi le Framework PHP le plus simple pour commencer.

nans
Auteur

Merci pour ces encouragements ;) ça fait toujours plaisir !

Voici ce que j'ai mis dans mon EntrepriseRepository pour le querybuilder :

    public function findAllUsers($entreprise_id)
    {
        $qb = $this->createQueryBuilder('e');

        $qb->where('e.id = :id')
              ->setParameter('id', $entreprise_id);
        return $qb;
    } 

Je continue à essayer d'écrire le code dans mon ProjetType

nans
Auteur

ça y est !!!!!! Je poste de suite

nans
Auteur

Dans mon ProjetType :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('save', SubmitType::class, array('label' => 'Démarrer un nouveau projet : '))
            ->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
                $projet = $event->getData(); 
                $event->getForm()->add('user', EntityType::class, array(
                    'class' => 'structureBundle:User',
                    'choice_label' => 'name',
                    'query_builder' => function (UserRepository $ur) use ($projet) {
                                       return $ur->findAllUsersByEntreprise($projet->getEntreprise());

                    },
                    'label' => 'Attribuer un utilisateur au projet : ',
                ));
            });
    }

Dans mon UserRepository :


    public function findAllUsersByEntreprise($entreprise)
    {
        $qb = $this->createQueryBuilder('u');

        $qb->where('u.entreprise = :entreprise')
              ->setParameter('entreprise', $entreprise);
        return $qb;
    }  

Un grand merci skp,... encore une fois !