8768 sujets

Développement web côté serveur, CMS

Bonsoir à tous,

J'ai déjà posé cette question sur deux autres forum connu, mais personne ne semble être en mesure de m'aider alors que ce problème me semble basique, limite " cas d'école ". Smiley ohwell

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, la première. J'ai donc fait ceci :

Formulaire Cabinet :
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 :

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. Smiley ohwell

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 :

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 :


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 Smiley smile
Modifié par Gaylord.P (03 Aug 2015 - 14:29)
Bonjour,

Est-ce que tu souhaites ajouter une version déjà existante sans modification, ou créer une version, à chaque fois que tu créé un cabinet, qui lui sera associée ?
Selon la réponse cela ne se gère pas de la même façon. Smiley smile
Modifié par Raphi (03 Aug 2015 - 14:37)
Salut et merci de ta réponse Smiley smile

En fait la première fois, on ajoute le cabinet avec la première version, c'est que j'essaie de faire la. Smiley smile

Les fois suivante, on ajoutera d'autres versions pour le même cabinet, mais la ce sera un autre formulaire qui ne fera appel qu'au "CabinetVersionType" avec l'id du cabinet déjà dedans, donc ce sera plus simple je pense cette seconde partie.

Encore merci de ton aide Smiley smile
Gaylord.P a écrit :
En fait la première fois, on ajoute le cabinet avec la première version, c'est que j'essaie de faire la.

Mais cette version, elle est déjà existante ? Ou bien tu dois en créer une nouvelle à chaque fois que tu créé un cabinet ?
Modifié par Raphi (03 Aug 2015 - 14:43)
La créer à chaque fois. Smiley smile

Lorsqu'on crée un cabinet, on crée donc le cabinet et la première version et seulement la première (donc c'est pas une collection avec javascript par exemple - à mes yeux c'est théoriquement plus simple). Smiley smile
Ok je vois.
Alors le soucis c'est que soit tu pars du principe que c'est du OneToOne dans ta relation, ce qui te permet d'utiliser ->add('versions', new CabinetVersionType()) dans la création de ton formulaire.
Soit tu utilises du ManyToOne, mais là tu es obligé d'utiliser une collection.
Par contre je ne suis pas certain qu'il te faut du js pour gérer ta collection.
Tu dois, en théorie, pouvoir interpréter le prototype de ta collection en utilisant quelque chose comme ceci dans ta vue :
{{ (form_widget(form.leNomDeTaCollection.vars.prototype)|replace({"__name__": "1"})|raw }}


Je t'avoue que je n'ai absolument pas testé ce code. S'il ne marche pas (ce qui est fort possible), enlève le replace, mais garde raw.
Modifié par Raphi (03 Aug 2015 - 15:29)
Tu as encore une autre solution.
Tu peux garder ton formulaire imbriqué, mais il faut le "détacher" de ton objet comme ceci :
->add('versions', new CabinetVersionType(), array('mapped' => false));

Ensuite, dans ton controller tu dois récupérer le contenu de ton élément de formulaire comme ceci :
$version = $form->get('versions')->getData();

Et ensuite tu dois enregistrer, cette version en faisant un persist et flush, puis venir l'ajouter via un addVersion($version), à ton objet cabinet.
Puis tu peux persister et flusher ton objet cabinet, et tout sera enregistré correctement (en théorie Smiley langue ).
Modifié par Raphi (03 Aug 2015 - 15:24)
Merci beaucoup pour tes réponses Smiley smile

De fil en aiguille, je suis arrivé à un résultat très satisfaisant en passant effectivement par une collection, et en créant une version vide à la création.

Voici comment pour ceux qui se posent la question :


        $builder->addEventListener(FormEvents: [langue]RE_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'
            ))
        ;


Encore merci Smiley smile