IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

[Form] Combiner un formulaire imbriqué (collection) avec un événement de formulaire paramétré [2.x]


Sujet :

Symfony PHP

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 8
    Points : 3
    Points
    3
    Par défaut [Form] Combiner un formulaire imbriqué (collection) avec un événement de formulaire paramétré
    Bonjour,

    je suis actuellement face à un problème et j'avoue que j'ai du mal à voir si une solution peut exister. J'ai bon espoir mais personnellement j'ai beau tourner le problème dans tous les sens je trouve pas.

    Mon objectif est d'offrir plusieurs mode de saisie pour une même entité, elle même incluse dans une collection d'une autre entité. J'ai bien compris la notion des forms embed, j'ai bien compris la notion des event forms, mais je n'arrive pas à fusionner les deux. J'explique.

    Prenons l'exemple de la tâche avec les tags de la doc officielle. Mon objectif serait ici de contrôler les champs tags du formulaire.

    http://symfony.com/doc/current/cookb...llections.html

    En objets on a donc :
    • Entity Task
    • Entity Tag
    • Form TaskType
    • Form TagType


    Pour ce qui est de la notion de form embed, la Task contient une liste de Tags, mappé dans le formulaire par la collection :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $builder->add('tags', 'collection', array('type' => new TagType()));
    Pour ce qui est des event forms, j'aurais quelque chose dans ce style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    class TagFieldCreator implements EventSubscriberInterface
    {
        private $factory;
        private $display;
     
        public function __construct(FormFactoryInterface $factory, $display_type)
        {
            $this->factory = $factory;
            $this->display = $display_type;
        }
     
        public static function getSubscribedEvents()
        {
            return array(FormEvents::PRE_SET_DATA => 'preSetData');
        }
     
        public function preSetData(DataEvent $event)
        {
            $data = $event->getData();
            $form = $event->getForm();
     
            switch ($this->display)
            {
                case 'text':
                    $form->add($this->factory->createNamed('text', 'name'));
                    break;
                case 'select':
                    $form->add($this->factory->createdNamed('choice', 'name', null, array(
                        'choices'   => array(
                            'tag1' => 'Tag 1',
                            'tag2' => 'Tag 2',
                            'tag3' => 'Tag 3',
                        )
                    )));
            }
        }
    }
    Avec ça, mon TagType devrait ressembler à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class TagType extends AbstractType
    {
        private $display;
     
        public function __construct($display)
        {
            $this->display = $display;
        }
     
        public function buildForm(FormBuilder $builder, array $options)
        {
            $subscriber = new TagFieldCreator($builder->getFormFactory(), $display);
            $builder->addEventSubscriber($subscriber);
        }
     
        public function getName()
        {
            return 'tag';
        }
    }
    Et mon problème dans tout ça, c'est que si je créais un formulaire simple pour un Tag directement depuis le controleur, j'aurais moyen de savoir quel $display je veux envoyer à mon TagType. Ce qui donnerait quelque chose du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $form = $this->createForm(new TagType($display), $tag);
    Or, mon TagType est appelé dans la création de la collection, dans la classe TaskType. Rappel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $builder->add('tags', 'collection', array('type' => new TagType()));
    Donc comment à partir d'ici je pourrait différencier mes TagType et en avoir dans ma collection par exemple un en mode 'text' et l'autre en mode 'select' comme décrit dans l'event form?

    Merci d'avance à ceux qui auront le courage de réfléchir au problème, après avoir eu le courage de lire et d'essayer de comprendre mon exposé

  2. #2
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    725
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 725
    Points : 1 050
    Points
    1 050
    Par défaut
    Bonjour,
    J'ai tout lu mais j'ai du mal à comprendre la finalité de la chose.
    s'agit t'il:
    • d'éviter de la duplication de code
    • d'avoir un select ou un input[text] selon la valeur de l'entité Tag
    • de pouvoir saisir la valeur d'un tag à la fois par select et/ou par input dans le même formulaire


    D'aprés le code de TagType et de TagFieldCreator je n'ai pas l'impression que tu ais besoin d'utiliser les listeners puisque tu n'utilises pas la valeur de $data.
    Ce code donnerait le même résultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    class TagType extends AbstractType
    {
        private $display;
     
        public function __construct($display)
        {
            $this->display = $display;
        }
     
        public function buildForm(FormBuilder $builder, array $options)
        {
            switch($this->display){
               case 'text':
                    $form->add( 'name','text'));
                    break;
               case 'select':
                    $form->add( 'name', 'choice', array(
                        'choices'   => array(
                            'tag1' => 'Tag 1',
                            'tag2' => 'Tag 2',
                            'tag3' => 'Tag 3',
                        )
                    ));
            }
        } 
        public function getName()
        {
            return 'tag';
        }
    }


    Et mon problème dans tout ça, c'est que si je créais un formulaire simple pour un Tag directement depuis le controleur, j'aurais moyen de savoir quel $display je veux envoyer à mon TagType. Ce qui donnerait quelque chose du style :
    Code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $form = $this->createForm(new TagType($display), $tag);
    Qu'est ce qui t'empeche d'avoir un attribut display dans TaskType (transmis par le constructeur également) afin de le transmettre dans TagType?

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Tout d'abord, merci de tenter de m'aider

    La finalité que je veux atteindre, c'est d'avoir, pour une même classe (Entity liée à la bdd), différentes méthodes de saisie.

    L’intérêt serait surtout d'avoir une base propre car au final tout va dans la même table car tous les Tags sont des Tags, seul la méthode de saisie pour l'utilisateur change.

    De plus je veux pouvoir, à terme, pouvoir ajouter des modes de saisie, et ça m’embêterait d'ajouter des tables à chaque fois juste pour ça.

    Enfin pour répondre à ta dernière question, ce qui m'empêche d'ajouter le paramètre display au TagType, c'est qu'il est créé via une fonction dans le builder de la classe TaskType :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $builder->add('tags', 'collection', array('type' => new TagType()));
    Si je trasmets un paramètre ici, puisque tous les TagType sont créés via ce constructeur, il n'y a plus de moyen de différencier les différents TagType dans mon formulaire. Or mon objectif est, je le rappelle, d'afficher plusieurs TagType différemment dans un même formulaire.

    J'espère que mon problème est plus clair...

  4. #4
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    725
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 725
    Points : 1 050
    Points
    1 050
    Par défaut
    Qu'est ce qui détermine qu'un Tag doit s'afficher dans un formulaire de type Text ou de type Select?
    A priori le choix d'utiliser tel ou tel type de saisie dépend d'un ou de plusieurs attribut de l'entité Tag.
    Il faut donc analyser le tag qui est passé au formulaire dans le listener pour savoir quel type de saisie tu veux adopter

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class TagFieldCreator implements EventSubscriberInterface
    {
    /....
        public function preSetData(DataEvent $event)
        {
            $data = $event->getData();/*@var $data Tag*/
            if(!$data){
               return;
            }
            $form = $event->getForm();
     
            switch ($data->getType())
            {
                case 'text':
                    $form->add($this->factory->createNamed('text', 'name'));
                    break;
                case 'select':
                    $form->add($this->factory->createdNamed('choice', 'name', null, array(
                        'choices'   => array(
                            'tag1' => 'Tag 1',
                            'tag2' => 'Tag 2',
                            'tag3' => 'Tag 3',
                        )
                    )));
            }
        }
    }

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    A priori le choix d'utiliser tel ou tel type de saisie dépend d'un ou de plusieurs attribut de l'entité Tag.
    Oui c'est exactement ça.

    Du coup je comprends le principe de ton exemple, je vais essayer ça ce soir.

    Il me semble que j'avais essayé de voir le contenu du resultat de $event->getData(), ça me retournait toujours NULL, mais c'est peut-être moi qui avait mal fait un truc alors.

    Merci pour ta réponse.

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Malheureusement, c'est bien ce qu'il me semblait. Avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $task = new Task();
     
    $configs = $configuration->getConfs();
    foreach ($configs as $config) {
        $tag = new Tag();
        $tag->setConf($config);
        $task->addTag($tag);
    }
     
    $form = $this->createForm(new TaskType(), $task);
    J'ai tout de même le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $data = $event->getData();
    qui est à NULL dans l'EventSubscriber.

    Est-ce moi qui ai mal fait ou oublié quelque chose?

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Finalement j'ai trouvé la solution, c'était dû au fait que j'utilisais l'event pre_set_data. Avec l'event set_data, j'arrive bien à récupérer ma valeur.

    Par contre si quelqu'un pouvait m'expliquer les traitements qui sont effectués entre le pre_set_data, le set_data et le post_set_data, histoire que je sois sûr que ça va faire ce que je veux, ça serait sympa.

    Sinon merci de ton aide arnooo

  8. #8
    Membre du Club
    Inscrit en
    Février 2005
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 47
    Points : 52
    Points
    52
    Par défaut
    Yop je suis tombé sur ce topic très intéressant via une recherche google sur symfony

    du coup pour la différence entre les events tu peux allez voir ici
    http://stackoverflow.com/questions/9...y2-form-events

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [2.x] [Form] Formulaire imbriqué
    Par minouchaimen dans le forum Symfony
    Réponses: 3
    Dernier message: 19/05/2013, 21h55
  2. [2.x] [Form] Validation de formulaire imbriqué
    Par dukoid dans le forum Symfony
    Réponses: 12
    Dernier message: 02/04/2013, 22h36
  3. [2.x] [Form] Formulaire imbriqué avec des uploads
    Par prims dans le forum Symfony
    Réponses: 4
    Dernier message: 14/03/2013, 16h12
  4. [AC-2007] Mise en forme conditionnelle avec image dans sous formulaire
    Par lio33 dans le forum IHM
    Réponses: 2
    Dernier message: 15/01/2013, 18h42
  5. Réponses: 4
    Dernier message: 15/03/2007, 19h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo