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 :

Formulaire imbriqué simple


Sujet :

Symfony PHP

  1. #1
    Membre à l'essai
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juillet 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Directeur de projet

    Informations forums :
    Inscription : Juillet 2011
    Messages : 34
    Points : 22
    Points
    22
    Par défaut Formulaire imbriqué simple
    Bonsoir à tous,

    J'ai déjà posé cette question sur un autre forum connu, mais personne ne semble être en mesure de m'aider. :/

    Je souhaite réaliser un formulaire imbriqué, la manière la plus simple qu'il soit : j'ai une entité "cabinet", laquelle doit imbriquer une "version". A terme, il y aura plusieurs versions mais ce formulaire la doit n'en ajouter qu'une seule. J'ai donc fait ceci :

    Formulaire Cabinet :

    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
    class CabinetType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('versions', new CabinetVersionType())
                ->add('submit', 'submit', array(
                    'label' => 'Valider'
                ))
            ;
        }
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'LogicielBundle\Entity\Cabinet'
            ));
        }
        public function getName()
        {
            return 'logiciel_cabinet_form';
        }
    }
    Formulaire version :

    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
    class CabinetVersionType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('libelle', 'text', array(
                    'label' => 'Libellé',
                    'max_length' => 55
                ))
            ;
        }
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'LogicielBundle\Entity\CabinetVersion'
            ));
        }
        public function getName()
        {
            return 'logiciel_cabinet_version_form';
        }
    }

    Dès que j'affiche le formulaire, j'ai cette erreur qui est renvoyée : "The form's view data is expected to be an instance of class LogicielBundle\Entity\CabinetVersion, but is an instance of class Doctrine\Common\Collections\ArrayCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\Common\Collections\ArrayCollection to an instance of LogicielBundle\Entity\CabinetVersion."

    Je comprends bien qu'il me demande de mettre data_class à null ; d'ailleurs quand je le fait le formulaire s'affiche, mais dans ce cas je casse la relation à l'entité il me semble. :/

    J'ai regardé sur les forums, certains préconisent d'utiliser un formulaire de type collection + javascript mais ça ne semble pas adapté, puisque je ne souhaite ajouter qu'une seule version, ce serait dommage d'utiliser du javascript pour ça.

    A titre informatif, voici l'entité Cabinet :

    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
    38
    class Cabinet
    {
        /**
         * @var integer
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
     
        /**
         * @ORM\OneToMany(targetEntity="LogicielBundle\Entity\CabinetVersion", mappedBy="cabinet", cascade={"persist"})
         */
        private $versions;
        public function __construct()
        {
            $this->versions = new \Doctrine\Common\Collections\ArrayCollection();
        }
        public function getId()
        {
            return $this->id;
        }
        public function addVersion(\LogicielBundle\Entity\CabinetVersion $versions)
        {
            $this->versions[] = $versions;
            $versions->setCabinet($this);        
            return $this;
        }
        public function removeVersion(\LogicielBundle\Entity\CabinetVersion $versions)
        {
            $this->versions->removeElement($versions);
        }
        public function getVersions()
        {
            return $this->versions;
        }
    }
    Et enfin l'entité CabinetVersion :

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
    class CabinetVersion
    {
     
        use Adresse;
        use DateVersion;
        use DateReference;
        //use Fichier;
     
        /**
         * @var integer
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
     
        /**
         * @ORM\ManyToOne(targetEntity="LogicielBundle\Entity\Cabinet", inversedBy="versions")
         * @ORM\JoinColumn(nullable=false)
         */
        private $cabinet;
     
        /**
         * @var string
         *
         * @ORM\Column(name="libelle", type="string", length=55)
         * @Assert\NotBlank()
         */
        private $libelle;
     
        public function getId()
        {
            return $this->id;
        }
        public function setLibelle($libelle)
        {
            $this->libelle = $libelle;
     
            return $this;
        }
        public function getLibelle()
        {
            return $this->libelle;
        }
        public function setCabinet(\LogicielBundle\Entity\Cabinet $cabinet)
        {        
            $this->cabinet = $cabinet;
     
            return $this;
        }
        public function getCabinet()
        {
            return $this->cabinet;
        }
    }
    Merci beaucoup à ceux qui pourront m'aider / m'éclairer

  2. #2
    Membre éprouvé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2013
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Novembre 2013
    Messages : 739
    Points : 1 022
    Points
    1 022
    Par défaut
    ce que je propose pour ton form CabinetType :
    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
     
     public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
     
            ->add('CabinetVersion', 'entity', array('class' => 'src\nomBundle\Entity\CabinetVersion',     
              'property' => 'title',
              'expanded' => false,
              'multiple' => false,
              'required' => true ))
     
     
              ->add('submit', 'submit', array(
                    'label' => 'Valider' )) ;
        }

  3. #3
    Membre à l'essai
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juillet 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Directeur de projet

    Informations forums :
    Inscription : Juillet 2011
    Messages : 34
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par mehrezlabidimehrez Voir le message
    ce que je propose pour ton form CabinetType :
    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
     
     public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
     
            ->add('CabinetVersion', 'entity', array('class' => 'src\nomBundle\Entity\CabinetVersion',     
              'property' => 'title',
              'expanded' => false,
              'multiple' => false,
              'required' => true ))
     
     
              ->add('submit', 'submit', array(
                    'label' => 'Valider' )) ;
        }
    Salut et merci de ta réponse

    Malheureusement, j'obtiens cette erreur : " Neither the property "CabinetVersion" nor one of the methods "getCabinetVersion()", "cabinetVersion()", "isCabinetVersion()", "hasCabinetVersion()", "__get()" exist and have public access in class "LogicielBundle\Entity\Cabinet". "

    De plus mais je me trompe peut-être, le type "entity" n'est pas pour allé chercher des données pour, par exemple, les afficher dans un Select ?

    Encore merci

  4. #4
    Membre expérimenté Avatar de Nico_F
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2011
    Messages
    728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Avril 2011
    Messages : 728
    Points : 1 310
    Points
    1 310
    Par défaut
    Je comprends bien qu'il me demande de mettre data_class à null ; d'ailleurs quand je le fait le formulaire s'affiche, mais dans ce cas je casse la relation à l'entité il me semble. :/
    Si tu souhaites faire un formulaire qui n'a pas la même structure que ton entité (une seule version alors que ton model en attends plusieurs), il faut bien à un moment lui dire ne pas se baser sur l'entité.

    Donc tu peux effectivement mettre le data_class à null, ce qui veut dire que tu devras toi même construire correctement ton objet au moment du formhandling.

    Autre possibilité, tu fais un formulaire avec une collection, qui correspond donc à ton modèle, et tu ne fais pas de javascript pour rajouter un autre formulaire, comme ça tu as ce que tu veux.

  5. #5
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Septembre 2009
    Messages
    875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Septembre 2009
    Messages : 875
    Points : 1 313
    Points
    1 313
    Par défaut
    Pour info, tu peux tout a fait manipuler des objets php simples (genre DAO/DTO) dans les formulaires si tu veux avoir une structure différente de ta base de données.

  6. #6
    Membre à l'essai
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juillet 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Directeur de projet

    Informations forums :
    Inscription : Juillet 2011
    Messages : 34
    Points : 22
    Points
    22
    Par défaut
    D'accord merci à tous pour vos réponses

    Pourtant dans l'idée, le formulaire est à mes yeux comme dans la base de données : la seule différence est que pour le one-to-many, j'ajoute les éléments une seule fois par une seule fois, donc si on veut deux versions il faut ouvrir le formulaire deux fois (on ajoute une première fois le cabinet et sa première version ; les prochaines fois les autres versions). Je ne pensais pas que ce serait autant galère à gérer pour symfony puisque ça me parait un " cas d'école ". :-S

    Du coup selon vous, il faudrait peut-être se diriger vers quelque chose comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                ->add('version', new CabinetVersionType(), array(
                    'mapped' => false
                ))
    Et ajouter la première version du cabinet dans un prePersist() situé dans l'entité Cabinet ?

    Encore merci

    Encore merci

  7. #7
    Membre expérimenté Avatar de Nico_F
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2011
    Messages
    728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Avril 2011
    Messages : 728
    Points : 1 310
    Points
    1 310
    Par défaut
    Pourtant dans l'idée, le formulaire est à mes yeux comme dans la base de données
    Oublie la base de données, c'est sur des objets qu'il faut focaliser ton attention.
    Tes formulaires ils se basent sur des objets (qu'il s'agisse d'entités doctrine ou de simples objets de classes non mappées).

    Et si ton objet il a une collection, et que ton formulaire il a un seul objet, ton form et ton model sont différents. Donc oui effectivement soit tu passes par un model spécifique à ton form auquel cas la transition form/object se fera sans souci (mais tu devras faire toi même la transition object/entity), soit tu passes par un data_class null ou un champs non mappé (et tu dois faire la transition formdata => entity toi même).

    La meilleure solution est selon moi de garder le principe de collection, ton formulaire peut coller à ton entité : le javascript ne sert que si tu veux ajouter ou supprimer des éléments de cette collection à la volée dans ton formulaire. Si tu sais précisément combien d'éléments de cette collection tu veux autoriser (dans ton cas un seul) tu définis ça en construisant ton formtype de collection et tu précises les options allow_add (false) et allow_delete (false).

    http://symfony.com/fr/doc/current/re...ollection.html

    Tout est sur cette page : fais abstraction de la partie ou on peut ajouter ou retirer des forms embarqués dans la collection et tu as la solution à ta problématique.

  8. #8
    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,

    Pourquoi ne pas utiliser "CabinetVersionType" en tant que formulaire de base ayant un sous-formulaire "CabinetType".
    De cette manière tu restes cohérent avec les cardinalités de tes objets.

    D'ailleurs il n'y a pas de champ particulier dans ton CabinetType, donc autant afficher uniquement le "CabinetVersionType" seul.

  9. #9
    Membre à l'essai
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juillet 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Directeur de projet

    Informations forums :
    Inscription : Juillet 2011
    Messages : 34
    Points : 22
    Points
    22
    Par défaut
    Bonjour à tous et merci pour vos réponses

    Je suis donc effectivement passé par une collection qui est plus logique vu que c'est ce que l'objet attend, merci de votre aide j'ai pas mal appris.

    Voici comment j'ai procédé pour ceux qui se posent la question :

    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
     
            $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
                $cabinet = $event->getData();
                if (empty($cabinet) OR empty($cabinet->getId())) {
                    $cabinet->addVersion(new \LogicielBundle\Entity\CabinetVersion());
                }
            });
            $builder
                ->add('versions', 'collection', array(
                    'type' => new CabinetVersionType(),
                    'allow_add' => false,
                    'allow_delete' => false
                ))
                ->add('submit', 'submit', array(
                    'label' => 'Valider'
                ))
            ;
    Quand à la dernière réponse, car ce ne serait pas "logique" justement, de passer par le côté inverse. Car rien n'indique que Cabinet n'aura pas un jour des champs obligatoires et que je préfère garder la logique métier.

    Encore merci à tous

Discussions similaires

  1. Réponses: 8
    Dernier message: 25/07/2006, 22h49
  2. Réponses: 1
    Dernier message: 25/07/2006, 22h11
  3. Besoin d'aide sur requetes imbriquées simples
    Par Kyti dans le forum Langage SQL
    Réponses: 2
    Dernier message: 01/03/2006, 10h52
  4. [CGI] Formulaire tres simple
    Par needles94000 dans le forum Web
    Réponses: 2
    Dernier message: 08/02/2006, 02h28
  5. formulaire imbriqué
    Par jani dans le forum Langage
    Réponses: 9
    Dernier message: 18/01/2006, 15h40

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