Activité : Doctrine et les relations [possibilité] - SimplonReunion/developpeur-web GitHub Wiki

Rappel

énoncé.

Une des solutions

Tout d'abord on crée les entités Equipe,Joueur et Match et leurs relations.

Entité Joueur

On commence par l'entité Joueur :

<?php
//src/SimplonReunion/Playground/Entity
namespace SimplonReunion\PlaygroundBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Joueur
 *
 * @ORM\Table(name="joueur")
 * @ORM\Entity(repositoryClass="SimplonReunion\PlaygroundBundle\Repository\JoueurRepository")
 */
class Joueur
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

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

    /**
    * @ORM\ManyToOne(targetEntity="Equipe", inversedBy="joueurs")
    */
    private $equipe;

    /**
     * @ORM\Column(name="numero_joueur", type="integer")
     */
    private $numeroJoueur;


    public function getNumeroJoueur(){
      return $this->numeroJoueur;
    }

    public function setNumeroJoueur($numeroJoueur){
      $this->numeroJoueur = $numeroJoueur;

      return $this;
    }


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

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

        return $this;
    }

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

    /**
     * Set prenom
     *
     * @param string $prenom
     *
     * @return Joueur
     */
    public function setPrenom($prenom)
    {
        $this->prenom = $prenom;

        return $this;
    }

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

    /**
     * Set equipe
     *
     * @param \SimplonReunion\PlaygroundBundle\Entity\Equipe $equipe
     *
     * @return Joueur
     */
    public function setEquipe(\SimplonReunion\PlaygroundBundle\Entity\Equipe $equipe = null)
    {
        $this->equipe = $equipe;

        return $this;
    }

    /**
     * Get equipe
     *
     * @return \SimplonReunion\PlaygroundBundle\Entity\Equipe
     */
    public function getEquipe()
    {
        return $this->equipe;
    }
}

On sait que l'on doit avoir une relation entre Joueur et Equipe de type ManyToOne. Plusieurs joueurs font parti que d'une seule équipe et une équipe peut avoir un ou plusieurs joueurs.

Pour que Doctrine crée cette relation il faut le lui dire, d'où l'utilisation de l'annotation au-dessus de la propriété $equipe :

    /**
    * @ORM\ManyToOne(targetEntity="Equipe", inversedBy="joueurs")
    */
    private $equipe;

Entité Equipe

On créé l'entité Equipe :

<?php

namespace SimplonReunion\PlaygroundBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Equipe
 *
 * @ORM\Table(name="equipe")
 * @ORM\Entity(repositoryClass="SimplonReunion\PlaygroundBundle\Repository\EquipeRepository")
 */
class Equipe
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * @ORM\OneToMany(targetEntity="Joueur", mappedBy="equipe",cascade={"persist"})
     */
    private $joueurs;

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

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

        return $this;
    }

    /**
     * Get nom
     *
     * @return string
     */
    public function getNom()
    {
        return $this->nom;
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->joueurs = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add joueur
     *
     * @param \SimplonReunion\PlaygroundBundle\Entity\Joueur $joueur
     *
     * @return Equipe
     */
    public function addJoueur(\SimplonReunion\PlaygroundBundle\Entity\Joueur $joueur)
    {
        $this->joueurs[] = $joueur;

        return $this;
    }

    /**
     * Remove joueur
     *
     * @param \SimplonReunion\PlaygroundBundle\Entity\Joueur $joueur
     */
    public function removeJoueur(\SimplonReunion\PlaygroundBundle\Entity\Joueur $joueur)
    {
        $this->joueurs->removeElement($joueur);
    }

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

De même, on sait que la relation qui lie Equipe à Joueur est de type OneToMany. Une équipe peut avoir plusieurs Joueur, d'où l'annotation sur la propriété joueurs

     /**
     * @ORM\OneToMany(targetEntity="Joueur", mappedBy="equipe")
     */
    private $joueurs;

Comme l'équipe peut avoir plusieurs joueurs vous vous doutez bien que joueurs ressemble plus à un tableau. J'écris "ressemble" car plus exactement c'est plutôt un ArrayCollection. Retenez juste que c'est un tableau amélioré pour Doctrine.

Par conséquent, lors de la construction de l'entité (lorsqu'on fait un new) il le faut définir explicitement. Dans le constructeur de Equipe on ajoutera donc :

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->joueurs = new \Doctrine\Common\Collections\ArrayCollection();
    }

Entité Match

Il ne reste plus que l'entité Match à créer

<?php

namespace SimplonReunion\PlaygroundBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Matchs
 *
 * @ORM\Table(name="matchs")
 * @ORM\Entity(repositoryClass="SimplonReunion\PlaygroundBundle\Repository\MatchsRepository")
 */
class Matchs
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * @ORM\ManyToMany(targetEntity="Equipe",mappedBy="matchs",cascade={"persist"})
     */
    private $equipes;


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

    /**
     * Set lieu
     *
     * @param string $lieu
     *
     * @return Matchs
     */
    public function setLieu($lieu)
    {
        $this->lieu = $lieu;

        return $this;
    }

    /**
     * Get lieu
     *
     * @return string
     */
    public function getLieu()
    {
        return $this->lieu;
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->equipes = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add equipe
     *
     * @param \SimplonReunion\PlaygroundBundle\Entity\Equipe $equipe
     *
     * @return Matchs
     */
    public function addEquipe(\SimplonReunion\PlaygroundBundle\Entity\Equipe $equipe)
    {
        $this->equipes[] = $equipe;

        return $this;
    }

    /**
     * Remove equipe
     *
     * @param \SimplonReunion\PlaygroundBundle\Entity\Equipe $equipe
     */
    public function removeEquipe(\SimplonReunion\PlaygroundBundle\Entity\Equipe $equipe)
    {
        $this->equipes->removeElement($equipe);
    }

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

Un match peut se faire en plusieurs équipes et les équipes peuvent faire plusieurs matchs. C'est donc une relation de plusieurs à plusieurs : ManyToMany.

    /**
     * @ORM\ManyToMany(targetEntity="Equipe",mappedBy="matchs",cascade={"persist"})
     */
    private $equipes;

Le match s'attends à avoir plusieurs équipes. On va encore retrouver un ArrayCollection initialiser dans le constructeur de notre entité.

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->equipes = new \Doctrine\Common\Collections\ArrayCollection();
    }

Nos entités sont créés. N'oubliez pas de mettre à jour le schéma de la base de données :

bin/console doctrine:schema:update --force

Si vous avez un doute sur la validité des annotations de Doctrine vous pouvez utiliser la commande :

bin/console doctrine:schema:validate

Insérer dans la base

On crée un controller JeuController qui va gérer la création des 12 joueurs, 2 équipes et 1 match. On va tout mettre dans la même action.

<?php

namespace SimplonReunion\PlaygroundBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use SimplonReunion\PlaygroundBundle\Entity\Joueur;
use SimplonReunion\PlaygroundBundle\Entity\Matchs;
use SimplonReunion\PlaygroundBundle\Entity\Equipe;

class JeuController extends Controller
{
    /**
     * @Route("/jeu/massif")
     */
    public function massifAction()
    {
        $joueur1 = $this->creerJoueur('Fleury', 'Antoine', 5);
        $joueur2 = $this->creerJoueur('ZUIDBERG', 'Chris', 7);
        $joueur3 = $this->creerJoueur('HENNO', 'Hubert', 8);
        $joueur4 = $this->creerJoueur('SIECKER', 'Julien', 15);
        $joueur5 = $this->creerJoueur('LOMBARD', 'Vincent', 1);
        $joueur6 = $this->creerJoueur('BOEL', 'Yves Alexandre', 3);

        $joueur7 = $this->creerJoueur('FREDERIC', 'Malick', 2);
        $joueur8 = $this->creerJoueur('JUHKAMI', 'Martti', 10);
        $joueur9 = $this->creerJoueur('KOPRIVICA', 'Lazar', 9);
        $joueur10 = $this->creerJoueur('NEVOT', 'Tanguy', 15);
        $joueur11 = $this->creerJoueur('RAGONDET', 'Vincent', 1);
        $joueur12 = $this->creerJoueur('AH-KONG', 'Rodney Ken', 3);

        $equipe1 = new Equipe();
        $equipe1->setNom('Tour Volley-Ball');

        $equipe2 = new Equipe();
        $equipe2->setNom('Rennes Volley-Ball');

        $equipe1->addJoueur($joueur1)
        ->addJoueur($joueur2)
        ->addJoueur($joueur3)
        ->addJoueur($joueur4)
        ->addJoueur($joueur5)
        ->addJoueur($joueur6)
        ;

        $equipe2->addJoueur($joueur7)
        ->addJoueur($joueur8)
        ->addJoueur($joueur9)
        ->addJoueur($joueur10)
        ->addJoueur($joueur11)
        ->addJoueur($joueur12)
        ;

        $match = new Matchs();
        $match->setLieu('Paris');
        $match->addEquipe($equipe1)
        ->addEquipe($equipe2);

        $em = $this->getDoctrine()->getManager();
        //On peut persist uniquement match car dans mes relations on a explicitement
        //demandé que les persist soient fait en cascade
        //Donc quand on persist un Match, comme c'est en cascade, ça va aussi persist Equipe
        //et Joueur
        $em->persist($match);
        $em->flush();

        return $this->render('SimplonReunionPlaygroundBundle:Jeu:massif.html.twig', array(
            // ...
        ));
    }

    /**
     * Créer un joueur.
     *
     * @param string $nom
     * @param string $prenom
     * @param string $numeroJoueur
     *
     * @return Joueur
     */
    protected function creerJoueur($nom, $prenom, $numeroJoueur)
    {
        $joueur = new Joueur();
        $joueur->setNom($nom)
               ->setPrenom($prenom)
               ->setNumeroJoueur($numeroJoueur)
      ;

        return $joueur;
    }
}

Comme vous avez pu le remarquer, on ne fait qu'un seul persist $em->persist($match); c'est parce que sur mes relation j'ai défini des persist en cascade.

    //Equipe
    //...
    /**
     * @ORM\OneToMany(targetEntity="Joueur", mappedBy="equipe",cascade={"persist"})
     */
    private $joueurs;
    //...
    //Match
    //...
    /**
     * @ORM\ManyToMany(targetEntity="Equipe",mappedBy="matchs",cascade={"persist"})
     */
    private $equipes;
    //...

Aller plus loin

La relation entre Joueur et Equipe est une relation bi-directionnelle. À partir d'Equipe on peut accéder aux Joueur (grâce à la propriété joueurs) et à partir de Joueur on peut accéder à Equipe (grâce à la propriété equipe).

Par contre, la relation entre Match et Equipe est unidirectionnel. Depuis Match on peut accéder aux Equipe mais pas l'inverse.

Vous pouvez tout à fait la rendre bidirectionnelle.