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 :

manyToMany avec attributs et repository [2.x]


Sujet :

Symfony PHP

  1. #1
    Membre régulier
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2014
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2014
    Messages : 124
    Points : 71
    Points
    71
    Par défaut manyToMany avec attributs et repository
    Bonjour,

    j'ai 2 tables: advert et skill

    advert

    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
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
     
    <?php
     
    namespace test\tutoBundle\Entity;
     
    use Doctrine\ORM\Mapping as ORM;
    use Gedmo\Mapping\Annotation as Gedmo;
     
     
    /**
     * Advert
     *
     * @ORM\Table()
     * @ORM\Entity(repositoryClass="test\tutoBundle\Entity\AdvertRepository")
     * @ORM\hasLifecycleCallbacks
     */
    class Advert
    {
        /**
         * @var integer
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
     
        /**
         * @var string
         *
         * @ORM\Column(name="title", type="string", length=255)
         */
        private $title;
     
        /**
         * @ORM\OneToMany(targetEntity="test\tutoBundle\Entity\AdvertSkill", mappedBy="Advert")
         */
        private $advertSkills;
     
        /**
         * Get id
         *
         * @return integer 
         */
        public function getId()
        {
            return $this->id;
        }
     
        /**
         * Set title
         *
         * @param string $title
         * @return Advert
         */
        public function setTitle($title)
        {
            $this->title = $title;
     
            return $this;
        }
     
        /**
         * Get title
         *
         * @return string 
         */
        public function getTitle()
        {
            return $this->title;
        }
        /**
         * Constructor
         */
        public function __construct()
        {
            $this->advertSkills = new \Doctrine\Common\Collections\ArrayCollection();
        }
     
        /**
         * Add advertSkills
         *
         * @param \test\tutoBundle\Entity\AdvertSkill $advertSkills
         * @return Advert
         */
        public function addAdvertSkill(\test\tutoBundle\Entity\AdvertSkill $advertSkills)
        {
            $this->advertSkills[] = $advertSkills;
     
            return $this;
        }
     
        /**
         * Remove advertSkills
         *
         * @param \test\tutoBundle\Entity\AdvertSkill $advertSkills
         */
        public function removeAdvertSkill(\test\tutoBundle\Entity\AdvertSkill $advertSkills)
        {
            $this->advertSkills->removeElement($advertSkills);
        }
     
        /**
         * Get advertSkills
         *
         * @return \Doctrine\Common\Collections\Collection 
         */
        public function getAdvertSkills()
        {
            return $this->advertSkills;
        }
    }
    skill

    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
    58
    59
    60
    61
    62
    63
    64
    65
     
    <?php
     
    namespace test\tutoBundle\Entity;
     
    use Doctrine\ORM\Mapping as ORM;
     
    /**
     * Skill
     *
     * @ORM\Table()
     * @ORM\Entity(repositoryClass="test\tutoBundle\Entity\SkillRepository")
     */
    class Skill
    {
        /**
         * @var integer
         *
         * @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;
     
     
        /**
         * Get id
         *
         * @return integer 
         */
        public function getId()
        {
            return $this->id;
        }
     
        /**
         * Set name
         *
         * @param string $name
         * @return Skill
         */
        public function setName($name)
        {
            $this->name = $name;
     
            return $this;
        }
     
        /**
         * Get name
         *
         * @return string 
         */
        public function getName()
        {
            return $this->name;
        }
    }
    mon manytomany AdvertSkill avec attributs soit 2 manyToOne
    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
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
     
    <?php
     
    namespace test\tutoBundle\Entity;
     
    use Doctrine\ORM\Mapping as ORM;
     
    /**
     * AdvertSkill
     *
     * @ORM\Table()
     * @ORM\Entity
     */
    class AdvertSkill
    {
        /**
         * @ORM\ManyToOne(targetEntity="test\tutoBundle\Entity\Advert", inversedBy="advertSkills")
         */
        private $Advert;
     
        /**
         * @ORM\ManyToOne(targetEntity="test\tutoBundle\Entity\Skill")
         */
        private $Skill;
     
        /**
         * @var integer
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
     
        /**
         * @var string
         *
         * @ORM\Column(name="level", type="string", length=255)
         */
        private $level;
     
     
        /**
         * Get id
         *
         * @return integer 
         */
        public function getId()
        {
            return $this->id;
        }
     
        /**
         * Set level
         *
         * @param string $level
         * @return AdvertSkill
         */
        public function setLevel($level)
        {
            $this->level = $level;
     
            return $this;
        }
     
        /**
         * Get level
         *
         * @return string 
         */
        public function getLevel()
        {
            return $this->level;
        }
     
        /**
         * Set Advert
         *
         * @param \test\tutoBundle\Entity\Advert $advert
         * @return AdvertSkill
         */
        public function setAdvert(\test\tutoBundle\Entity\Advert $advert = null)
        {
            $this->Advert = $advert;
     
            return $this;
        }
     
        /**
         * Get Advert
         *
         * @return \test\tutoBundle\Entity\Advert 
         */
        public function getAdvert()
        {
            return $this->Advert;
        }
     
        /**
         * Set Skill
         *
         * @param \test\tutoBundle\Entity\Skill $skill
         * @return AdvertSkill
         */
        public function setSkill(\test\tutoBundle\Entity\Skill $skill = null)
        {
            $this->Skill = $skill;
     
            return $this;
        }
     
        /**
         * Get Skill
         *
         * @return \test\tutoBundle\Entity\Skill 
         */
        public function getSkill()
        {
            return $this->Skill;
        }
    }
    controller
    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
    58
     
    <?php
     
    namespace test\tutoBundle\Controller;
     
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\component\httpFoundation\response;
    use Symfony\component\httpFoundation\request;
    use test\tutoBundle\Entity\Advert;
    use test\tutoBundle\Entity\AdvertSkill;
     
    class DefaultController extends Controller
    {
        // lecture des lignes advertSkill
        public function AdvertsAction()
        {
        	$em = $this->getDoctrine()->getManager();
            $adverts = $em->getRepository("tutoBundle:advert")->getAdvertWithSkill();
            // $skills = $em->getRepository("tutoBundle:AdvertSkill")->findAll();
            return $this->render('tutoBundle:Default:Advert.html.twig', array("adverts"=>$adverts));
        }
     
        // creation d'un advert
        public function AdvertCreateAction(request $request)
        {
        	$em = $this->getDoctrine()->getManager();
        	if($request->isMethod("POST"))
        	{
        		// echo "<pre>".print_r($request->request,true);
        		$advertAdd = new Advert();
        		$advertAdd->setTitle($_POST["title"]);
        		$em->persist($advertAdd);
        		$em->flush();
        		return $this->redirect($this->generateUrl("Adverts"));
        	}
            return $this->render('tutoBundle:Default:AdvertCreate.html.twig');
        }
     
        // creation manytomany avec attributs
        public function AdvertSkillCreateAction(request $request, $id)
        {
            $em = $this->getDoctrine()->getManager();
            $advert = $em->find("tutoBundle:Advert", $id);
            $skills = $em->getRepository("tutoBundle:Skill")->findAll();
     
            foreach ($skills as $key => $skill) {
                $advertSkill = new AdvertSkill;
                $advertSkill->setAdvert($advert);
                $advertSkill->setSkill($skill);
                $advertSkill->setLevel("test");
                $em->persist($advertSkill);
            }
     
            $em->flush();
            return $this->redirect($this->generateUrl("Adverts"));
            // return new response();
        }
    }
    view

    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
     
    <html>
    <body>
    <h1> advert </h1>
     
    	{% for advert in adverts %}
    		<table>
    			<th>Title</th><th>Author</th><th>content</th>
     
    			<tr>
    				<td>{{advert.title}}</td>
    				<td> <a href="{{ path('AdvertSkillCreate', {'id': advert.id}) }}"/> create skill </a>   </td>
    			</tr>
    		</table>
     
    		{% for skill in advert.advertSkills %}
    			{{skill.id}} {{skill.skill.name}} <br>
    		{% endfor %}
    	{% endfor %} <br>
     
    	{#{ladybug_dump(adverts)}}
    	{{kint()}#}
     
     
     
    <a href=" {{ path('AdvertCreate') }} "/> ajouter advert </a><br><br>
    </body>
    </html>
    et mon problème le repository de advert
    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
     
    <?php
     
    namespace test\tutoBundle\Entity;
     
    use Doctrine\ORM\EntityRepository;
     
    class AdvertRepository extends EntityRepository
    {
    	public function getAdvertWithSkill()
    	{
    	  $qb = $this
    	  	->createQueryBuilder('a')
    		->leftJoin('a.advertSkills', 'advskill') 
    	    ->addSelect('advskill')
    	  ;
     
    	  return $qb
    	    ->getQuery()
    	    ->getResult()
    	  ;
    	}
    }

    Le problème est le suivant:

    via mon repository, j'essaye de joindre la lecture de ma table skill pour avoir le name de chaque.

    j'arrive à lire ma table de relation au contraire d'un manytomany classic.

    le soucie est qu'il me crée autant de requêtes que de ligne dans ma table skill

    ex: j'ai 5 skills donc ainsi il me fait 5 requêtes + 1

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    {% for skill in advert.advertSkills %}
    	{{skill.id}} {{skill.skill.name}} <br>
    {% endfor %}
    comment faire pour joindre mon entity skill en relation avec le foreign key de advertskill en une seul requête car j'ai du mal à la joindre.

    je repost le repository

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	  $qb = $this
    	  	->createQueryBuilder('a')
    		->leftJoin('a.advertSkills', 'advskill') 
    	        ->addSelect('advskill')
    	  ;

    Bien à vous,

    Gilles Percheron

  2. #2
    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
    Il te manque un addSelect sur skill : celui que tu as n'est que sur la table intermédiaire. Du coup tu lazy-load les données de skill depuis ton objet advskill.

    La vraie boucle serait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    {% for advertskill in advert.advertSkills %}
    	{{advertskill.id}} {{advertskill.skill.name}} <br>
    {% endfor %}
    C'est le {{advertskill.skill.name}} qui crée les requêtes supplémentaires : parce que skill n'est pas chargée par ton DQL dans ton objet.

  3. #3
    Membre régulier
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2014
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2014
    Messages : 124
    Points : 71
    Points
    71
    Par défaut
    oui bas justement en orm faut penser objets donc comment d'une table intermédiaire qu'à le foreign key d'une autre table, la mettre en join ou leftjoin de advertSkills direct dans le repository.

    J'ai pas tout mis mais j'ai aussi un manytomany classic et une autre table en manytoone bidirectionnelle.

    pour ces 2 cas je join mes attributs pas des tables.

    donc est ce possible dans mon cas de rajouter la table skill ou non car c'est la question.

  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
    Rien ne t'empêche de rajouter ces deux lignes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //...
    ->addSelect('skill')
    ->join('advskill.skill', 'skill')
    //...

  5. #5
    Membre régulier
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2014
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2014
    Messages : 124
    Points : 71
    Points
    71
    Par défaut
    oullala l'ami du web un grand merci à toi.

    je savais que c'était pas grand chose, une mauvaise interprétation de ma part.

    j'avais tenté cela mais avec un attribut devant x. comme pour mon select('a') donc error

    j'en profite avant de fermer le post pour demander qu'elle est la réel différence entre un dql (createQuery) et un createQueryBuilder et dans quelle cas utiliser l'un plutôt que l'autre.


    merci

  6. #6
    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
    Le QueryBuilder possède les méthodes te permettant d'écrire le DQL de ta Query.
    Il n'y a pas de bonne ou de mauvaise solution, ça dépend avec quoi tu es le plus à l'aise.

    Soit tu utilises les méthodes du QueryBuilder parce que la syntaxe et les méthodes te paraissent verbeuses et plus claires, soit tu écris directement le DQL pour obtenir la Query de ton choix. C'est en fonction des préférences de chacun. Tu peux même plus ou moins mixer les deux en passant des petits raccourcis DQL à l'intérieur des méthodes du QueryBuilder.

    Quand tu fais par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $qb = $this->createQueryBuilder();
    //...
    $qb
        ->where('u.id = :user')
        ->setParameter('user', $user)
    ;
    tu utilises les deux, le where est une méthode du QueryBuilder, et ce que tu passes dedans est du DQL.

    Si tu voulais n'utiliser que les méthodes du QueryBuilder tu ferais ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $qb = $this->createQueryBuilder();
    //...
    $qb
        ->where($qb->expr()->eq('u.id', ':user'))
        ->setParameter('user', $user)
    ;
    Ça revient au même et ce n'est pas mieux d'utiliser l'un ou l'autre. C'est juste une affaire de goût... comme la bouffe chinoise !

    La seule différence que je vois se trouve dans certains bundles annexes que j'utilise : notamment pour les formulaires de filtre, ou la méthode de filtre doit s'appliquer sur un objet QueryBuilder. Donc là : pas le choix

  7. #7
    Membre régulier
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2014
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2014
    Messages : 124
    Points : 71
    Points
    71
    Par défaut
    Merci beaucoup nico c'est bien plus claire maintenant.

    j'ai suivi un tuto ou il parle des 2 et mélange les 2 sans savoir quoi est quoi.


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

Discussions similaires

  1. Persist relation ManyToMany avec attributs
    Par Trezegoals dans le forum Doctrine2
    Réponses: 3
    Dernier message: 22/08/2012, 21h55
  2. [2.x] Formulaire relation ManyToMany avec attributs
    Par Trezegoals dans le forum Symfony
    Réponses: 0
    Dernier message: 08/08/2012, 16h00
  3. [2.x] ManyToMany avec attribut, erreur à la création d'une entité
    Par Warnershoot dans le forum Symfony
    Réponses: 5
    Dernier message: 19/06/2012, 14h01
  4. Relation ManyToMany avec attribut
    Par icl1c dans le forum Doctrine2
    Réponses: 0
    Dernier message: 09/03/2012, 11h44
  5. Réponses: 8
    Dernier message: 27/02/2009, 01h37

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