Salut à tous, j'ai un petit problème sur symfony 2, je suis en train de créer une application éducatif. J'ai une entité compétence et une entité évaluation. une évaluation contient plusieurs compétence. j'ai dont fait une relation ManyToOne et j'ai utilisé le type de champ entity de symfony pour donner la possibilité de choisir plusieurs compétence à la fois . voici mon code

//entité évaluation
<?php

namespace App\ProfBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Evaluation
 *
 * @ORM\Table(name="evaluation")
 * @ORM\Entity(repositoryClass="App\ProfBundle\Repository\EvaluationRepository")
 */
class Evaluation
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\ProfBundle\Entity\Competence")
     * @ORM\JoinColumn(nullable=false)
     */
    private $competence;

    /**
     * @ORM\ManyToOne(targetEntity="App\AdminBundle\Entity\Classe")
     * @ORM\JoinColumn(nullable=false)
     */
    private $classe;

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

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

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="datedebut", type="date")
     */
    private $datedebut;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dateend", type="date")
     */
    private $dateend;

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

    /**
     * Set nom
     *
     * @param string $nom
     * @return Evaluation
     */
    public function setNom($nom)
    {
        $this->nom = $nom;

        return $this;
    }

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

    /**
     * Set statut
     *
     * @param boolean $statut
     * @return Evaluation
     */
    public function setStatut($statut)
    {
        $this->statut = $statut;

        return $this;
    }

    /**
     * Get statut
     *
     * @return boolean 
     */
    public function getStatut()
    {
        return $this->statut;
    }

    /**
     * Set datedebut
     *
     * @param \DateTime $datedebut
     * @return Evaluation
     */
    public function setDatedebut($datedebut)
    {
        $this->datedebut = $datedebut;

        return $this;
    }

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

    /**
     * Set dateend
     *
     * @param \DateTime $dateend
     * @return Evaluation
     */
    public function setDateend($dateend)
    {
        $this->dateend = $dateend;

        return $this;
    }

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

    /**
     * Set competence
     *
     * @param \App\ProfBundle\Entity\Competence $competence
     * @return Evaluation
     */
    public function setCompetence(\App\ProfBundle\Entity\Competence $competence)
    {
        $this->competence = $competence;

        return $this;
    }

    /**
     * Get competence
     *
     * @return \App\ProfBundle\Entity\Competence 
     */
    public function getCompetence()
    {
        return $this->competence;
    }

    /**
     * Set classe
     *
     * @param \App\AdminBundle\Entity\Classe $classe
     * @return Evaluation
     */
    public function setClasse(\App\AdminBundle\Entity\Classe $classe)
    {
        $this->classe = $classe;
AC
        return $this;
    }

    /**
     * Get classe
     *
     * @return \App\AdminBundle\Entity\Classe 
     */
    public function getClasse()
    {
        return $this->classe;
    }
}
//EvaluationType
<?php

namespace App\ProfBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EvaluationType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nom')
            ->add('statut')
            ->add('datedebut', 'date', ['widget' => 'single_text', 'format' => 'yyyy-MM-dd'])
            ->add('dateend','date', ['widget' => 'single_text', 'format' => 'yyyy-MM-dd'])
            ->add('competence', 'entity', array(
                'class'    => 'AppProfBundle:competence',
                'property' => 'nom',
                'expanded' => true,
                'multiple' => true))
            ->add('classe')
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'App\ProfBundle\Entity\Evaluation'
        ));
    }
}

j'obtiens l'erreur lorsque je soumets le formulaire avec plusieurs compétences sélectionnées

Catchable Fatal Error: Argument 1 passed to App\ProfBundle\Entity\Evaluation::setCompetence() must be an instance of App\ProfBundle\Entity\Competence, instance of Doctrine\Common\Collections\ArrayCollection given, called in C:\wamp64\www\maena\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php on line 556 and defined 

quelqu'un peut-il m'aider svp

12 réponses


nico41
Réponse acceptée

Bonjour,
Il y a plusieurs possiblités à ton problème, une qui se rapproche le plus de ce que je comprend de ce que tu veux faire est une association Many-To-Many , comme si tu voulais ajouter des mots-clefs ( = competences ) à un article ( = evaluation )

 class Evaluation {
    ...
     /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="App\ProfBundle\Entity\Competence", inversedBy="evaluations")
     * @JoinTable(name="evaluations_competences")
     */
    private $competences;
    ...

    public function __construct()
    {
        $this->competences = new ArrayCollection();
    }

 }

 class Competence {
    ...
    /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="App\ProfBundle\Entity\Evaluation", mappedBy="competences")
     */
    private $evaluations;

    ...

    public function __construct()
    {
        $this->evaluations = new ArrayCollection();
    }
 }

documentation de Doctrine : http://docs.doctrine-project.org/en/latest/reference/association-mapping.html

Bonjour.
Pour commencer, tu es déja dans le namespace App\ProfBundle\Entity, il est donc inutile de définir à nouveau le chemin complet du namespace, il te suffit de mettre :

public function setCompetence(Competence $competence)

Surtout que tu avais mis un antislash de trop au début.
Par contre, je ne pense pas que ce soit correct de vouloir faire un set sur une entité complète, les getter et les setter que tu as dans ce fichier sont pour des colonnes et non pour un enregistrement entier.

Bonjour Lartak, merci pour ta reponse mais elle ne réponds pas à ma question, dont le problème démeure

Hello,
Je pense que ton problème vient d'une mauvaise compréhension des relations .
Si j'ai bien compris tu as un formulaire où tu vas pouvoir choisir plusieurs compétences.
Le problème avec ta méthode setCompétence c'est qu'elle prend un objet compétence en paramètre alors que ton formulaire envoi une collection de compétences du cou php te balance une ereur .

Dans ton entité tu as défini une relation many to one :

    /**
     * @ORM\ManyToOne(targetEntity="App\ProfBundle\Entity\Competence")
     * @ORM\JoinColumn(nullable=false)
     */
    private $competence;

Je pense que tu devrais plutôt définir une relation OneToMany

    /**
     * @ORM\OneToMany(targetEntity="App\ProfBundle\Entity\Competence", mappedBy="application")
     * @ORM\JoinColumn(nullable=false)
     */
    private $competences;

et changer ton form avec

          ->add('competences', 'entity', array(
                'class'    => 'AppProfBundle:competence',
                'property' => 'nom',
                'expanded' => true,
                'multiple' => true))

Normalement la relation compétences va être capable de gérer la persistance entre ta collection et la BDD quand tu fera un flush

@Amilti a raison, dans ton cas tu as besoin d’une relation OneToMany.
Dans ta class "Evaluation" ton attribut "competence" doit être un ArrayCollection (du coup têtre ajouter un s à la fin). Ta méthode setCompetences va remplacer toutes la collection de compétences. GetCompetences va te retourner toutes les compétences. En plus, tu ajoutes une méthode addCompetence qui va ajouter une compétence à ta collection et removeCommpetence qui va supprimer une compétence à ta collection.
Du style :

//entité évaluation
<?php

namespace App\ProfBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Evaluation
 *
 * @ORM\Table(name="evaluation")
 * @ORM\Entity(repositoryClass="App\ProfBundle\Repository\EvaluationRepository")
 */
class Evaluation
{
    /**
     * @ORM\OneToMany(targetEntity="App\ProfBundle\Entity\Competence", mappedBy="evaluation")
     * @ORM\JoinColumn(nullable=false)
     */
    private $competences;

    public function __construct()
    {
        $this->competences = new ArrayCollection();
    }
    public function getCompetences()
    {
        return $this->competences;
    }
    public function addCompetence(Competence $competence)
    {
        $competence->setEvaluation($this);
        $this->competences[] = $competence;
        return $this;
    }
    public function removeCompetence(Competence $competence)
    {
        $this->competences->removeElement($competence);
        return $this;
    }
    public function setCompetences($competences)
    {
        $this->competences = $competences;
        return $this;
    }
}

Salut, si je resume
Au niveau de la relation, on a

/**
     * @ORM\OneToMany(targetEntity="App\ProfBundle\Entity\Competence", mappedBy="evaluation")
     * @ORM\JoinColumn(nullable=false)
     */
    private $competences;

j'ai changé application par le nom de l'entité proprietaire qui est évaluation
ensuite on a les getter et setter de $compentences

public function getCompetences()
    {
        return $this->competences;
    }
    public function setCompetences($competences)
    {
        $this->competences = $competences;
        return $this;
    }

ensuite on ajoute la collection dans le constructeur

use Doctrine\Common\Collections\ArrayCollection;
    ......
 public function __construct()
    {
        $this->competences = new ArrayCollection();
    }

dans mon formulaire

->add('competences', 'entity', array(
                'class'    => 'AppProfBundle:competence',
                'property' => 'nom',
                'expanded' => true,
                'multiple' => true))

si c'est ca alors, je n'ai plus d'érreur, cependant, les informations ne sont pas soumises, lorsque je valide le formulaire, je reviens à la page du formulaire avec les données saisies mais rien n'est enregistré en base de données.

Salut,

Tu devrais remplacer setCompetence par addCompetences ;-)

Hello,
Si ça marche toujours pas, peux-tu nous montrer à quoi ressemble la méthode de ton controller pour enregistrer les données ?

Bonjour,

montres nous le code du controller associé, stp.

Et comme le dit @Birzat il te faut plutôt une méthode addCompetence() et je rajouterai une ligne suplémentaire pour set l'évaluation à partir de compétence :

    public function addCompetence(Competence $competence)
    {
        $this->competences = $competence;
        $competence->setEvaluation($this);
        return $this;
    }

Ok, je vous fais le point
j'ai supprimé mon entité evaluation et j'ai recréé

<?php

namespace App\ProfBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Evaluation
 *
 * @ORM\Table(name="evaluation")
 * @ORM\Entity(repositoryClass="App\ProfBundle\Repository\EvaluationRepository")
 */
class Evaluation
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\OneToMany(targetEntity="App\ProfBundle\Entity\Competence", mappedBy="evaluation")
     * @ORM\JoinColumn(nullable=false)
     */
    private $competences;

    /**
     * @ORM\ManyToOne(targetEntity="App\AdminBundle\Entity\Classe")
     * @ORM\JoinColumn(nullable=false)
     */
    private $classe;

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

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="datedebut", type="date")
     */
    private $datedebut;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dateend", type="date")
     */
    private $dateend;

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

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

    /**
     * Set nom
     *
     * @param string $nom
     * @return Evaluation
     */
    public function setNom($nom)
    {
        $this->nom = $nom;

        return $this;
    }

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

    /**
     * Set datedebut
     *
     * @param \DateTime $datedebut
     * @return Evaluation
     */
    public function setDatedebut($datedebut)
    {
        $this->datedebut = $datedebut;

        return $this;
    }

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

    /**
     * Set dateend
     *
     * @param \DateTime $dateend
     * @return Evaluation
     */
    public function setDateend($dateend)
    {
        $this->dateend = $dateend;

        return $this;
    }

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

    /**
     * Set statut
     *
     * @param boolean $statut
     * @return Evaluation
     */
    public function setStatut($statut)
    {
        $this->statut = $statut;

        return $this;
    }

    /**
     * Get statut
     *
     * @return boolean
     */
    public function getStatut()
    {
        return $this->statut;
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->competences = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add competences
     *
     * @param \App\ProfBundle\Entity\Competence $competences
     * @return Evaluation
     */
    public function addCompetence(\App\ProfBundle\Entity\Competence $competences)
    {
        $this->competences[] = $competences;

        return $this;
    }

    /**
     * Remove competences
     *
     * @param \App\ProfBundle\Entity\Competence $competences
     */
    public function removeCompetence(\App\ProfBundle\Entity\Competence $competences)
    {
        $this->competences->removeElement($competences);
    }

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

    /**
     * Set classe
     *
     * @param \App\AdminBundle\Entity\Classe $classe
     * @return Evaluation
     */
    public function setClasse(\App\AdminBundle\Entity\Classe $classe)
    {
        $this->classe = $classe;

        return $this;
    }

    /**
     * Get classe
     *
     * @return \App\AdminBundle\Entity\Classe
     */
    public function getClasse()
    {
        return $this->classe;
    }
}

ensuite j'ai fais un crud

//EvaluationType
<?php

namespace App\ProfBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EvaluationType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nom')
            ->add('datedebut', 'date')
            ->add('dateend', 'date')
            ->add('competences', 'entity', array(
                'class'    => 'AppProfBundle:competence',
                'property' => 'nom',
                'expanded' => true,
                'multiple' => true))
            ->add('statut')
            ->add('classe')
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'App\ProfBundle\Entity\Evaluation'
        ));
    }
}

le controller

<?php

namespace App\ProfBundle\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

use App\ProfBundle\Entity\Evaluation;
use App\ProfBundle\Form\EvaluationType;

/**
 * Evaluation controller.
 *
 */
class EvaluationController extends Controller
{
    /**
     * Lists all Evaluation entities.
     *
     */
    public function indexAction()
    {
        $em = $this->getDoctrine()->getManager();

        $evaluations = $em->getRepository('AppProfBundle:Evaluation')->findAll();

        return $this->render('evaluation/index.html.twig', array(
            'evaluations' => $evaluations,
        ));
    }

    /**
     * Creates a new Evaluation entity.
     *
     */
    public function newAction(Request $request)
    {
        $evaluation = new Evaluation();
        $form = $this->createForm('App\ProfBundle\Form\EvaluationType', $evaluation);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($evaluation);
            $em->flush();

            return $this->redirectToRoute('evaluation_show', array('id' => $evaluation->getId()));
        }

        return $this->render('evaluation/new.html.twig', array(
            'evaluation' => $evaluation,
            'form' => $form->createView(),
        ));
    }

    /**
     * Finds and displays a Evaluation entity.
     *
     */
    public function showAction(Evaluation $evaluation)
    {
        $deleteForm = $this->createDeleteForm($evaluation);

        return $this->render('evaluation/show.html.twig', array(
            'evaluation' => $evaluation,
            'delete_form' => $deleteForm->createView(),
        ));
    }

    /**
     * Displays a form to edit an existing Evaluation entity.
     *
     */
    public function editAction(Request $request, Evaluation $evaluation)
    {
        $deleteForm = $this->createDeleteForm($evaluation);
        $editForm = $this->createForm('App\ProfBundle\Form\EvaluationType', $evaluation);
        $editForm->handleRequest($request);

        if ($editForm->isSubmitted() && $editForm->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($evaluation);
            $em->flush();

            return $this->redirectToRoute('evaluation_edit', array('id' => $evaluation->getId()));
        }

        return $this->render('evaluation/edit.html.twig', array(
            'evaluation' => $evaluation,
            'edit_form' => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        ));
    }

    /**
     * Deletes a Evaluation entity.
     *
     */
    public function deleteAction(Request $request, Evaluation $evaluation)
    {
        $form = $this->createDeleteForm($evaluation);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->remove($evaluation);
            $em->flush();
        }

        return $this->redirectToRoute('evaluation_index');
    }

    /**
     * Creates a form to delete a Evaluation entity.
     *
     * @param Evaluation $evaluation The Evaluation entity
     *
     * @return \Symfony\Component\Form\Form The form
     */
    private function createDeleteForm(Evaluation $evaluation)
    {
        return $this->createFormBuilder()
            ->setAction($this->generateUrl('evaluation_delete', array('id' => $evaluation->getId())))
            ->setMethod('DELETE')
            ->getForm()
        ;
    }
}

Le problème ici maintenant c'est que la clé étrangère competence_id n'existe pas dans ma BD après schema:update --force
je suis noviste, dont désolé si mes questions sont triviales pour certains

Salut Nico, Merci pour ta réponse, après avoir suivi certains tuto hier, j'ai éffectivement envisager une relation manytoomany qui resoud le problème.