• Aucun résultat trouvé

Remplissons la base de données

* @ORM\Entity */ class ArticleCompetence { /** * @ORM\Id * @ORM\ManyToOne(targetEntity="Sdz\BlogBundle\Entity\Article") */ private $article; /** * @ORM\Id * @ORM\ManyToOne(targetEntity="Sdz\BlogBundle\Entity\Competence") */ private $competence; /** * @ORM\Column() */

private $niveau; // Ici j'ai un attribut de relation « niveau »

// … les autres attributs

// Getter et setter pour l'entité Article

public function setArticle(\Sdz\BlogBundle\Entity\Article $article)

{

$this->article = $article; }

public function getArticle() {

return $this->article; }

// Getter et setter pour l'entité Competence

public function setCompetence(\Sdz\BlogBundle\Entity\Competence $competence)

{

$this->competence = $competence; }

public function getCompetence() {

return $this->competence; }

// On définit le getter/setter de l'attribut « niveau »

public function setNiveau($niveau) {

$this->niveau = $niveau; }

public function getNiveau() {

return $this->niveau; }

// … les autres getters/setters si vous en avez

}

Remplissons la base de données

Comme précédemment, on va d'abord ajouter des compétences en base de données grâce aux fixtures. Pour faire une nouvelle fixture, il suffit de créer un nouveau fichier dans le répertoire DataFixtures/ORM dans le bundle. Je vous invite à créer le

fichier src/Sdz/BlogBundle/DataFixtures/ORM/Competences.php : Code : PHP <?php // src/Sdz/BlogBundle/DataFixtures/ORM/Competences.php namespace Sdz\BlogBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\FixtureInterface; use Doctrine\Common\Persistence\ObjectManager; use Sdz\BlogBundle\Entity\Competence;

class Competences implements FixtureInterface {

public function load(ObjectManager $manager) {

// Liste des noms de compétences à ajouter

$noms = array('Doctrine', 'Formulaire', 'Twig'); foreach($noms as $i => $nom)

{

// On crée la compétence

$liste_competences[$i] = new Competence();

$liste_competences[$i]->setNom($nom);

// On la persiste

$manager->persist($liste_competences[$i]);

} // On déclenche l'enregistrement

$manager->flush(); }

}

Et maintenant, on peut exécuter la commande : Code : Console

C:\wamp\www\Symfony>php app/console doctrine:fixtures:load

Careful, database will be purged. Do you want to continue Y/N ?y > purging database

> loading Sdz\BlogBundle\DataFixtures\ORM\Categories > loading Sdz\BlogBundle\DataFixtures\ORM\Competences

Vous pouvez voir qu'après avoir tout vidé Doctrine a inséré les fixtures Categories puis nos fixtures Competences. Tout est prêt !

Exemple d'utilisation

La manipulation des entités dans une telle relation est un peu plus compliquée, surtout sans la bidirectionnalité. Mais on peut tout de même s'en sortir. Tout d'abord, voici un exemple pour créer un nouvel article contenant plusieurs compétences ; mettons ce code dans la méthode ajouterAction() :

Code : PHP

<?php

// src/Sdz/BlogBundle/Controller/BlogController.php // N'oubliez pas ce use évidemment

use Sdz\BlogBundle\Entity\ArticleCompetence; class BlogController extends Controller {

// …

public function ajouterAction() {

// On récupére l'EntityManager

$em = $this->getDoctrine()

->getManager();

// Création de l'entité Article

$article = new Article();

$article->setTitre('Mon dernier weekend');

$article->setContenu("C'était vraiment super et on s'est bien amusé.");

$article->setAuteur('winzou');

// Dans ce cas, on doit créer effectivement l'article en bdd pour lui assigner un id

// On doit faire cela pour pouvoir enregistrer les ArticleCompetence par la suite

$em->persist($article);

$em->flush(); // Maintenant, $article a un id défini

// Les compétences existent déjà, on les récupère depuis la bdd

$liste_competences = $em

->getRepository('SdzBlogBundle:Competence')

->findAll(); // Pour l'exemple, notre

Article contient toutes les Competences

// Pour chaque compétence

foreach($liste_competences as $i => $competence) {

// On crée une nouvelle « relation entre 1 article et 1

compétence »

$articleCompetence[$i] = new ArticleCompetence;

// On la lie à l'article, qui est ici toujours le même

$articleCompetence[$i]->setArticle($article);

// On la lie à la compétence, qui change ici dans la boucle

foreach

$articleCompetence[$i]->setCompetence($competence);

// Arbitrairement, on dit que chaque compétence est requise

au niveau 'Expert'

$articleCompetence[$i]->setNiveau('Expert');

// Et bien sûr, on persiste cette entité de relation,

propriétaire des deux autres relations

$em->persist($articleCompetence[$i]); } // On déclenche l'enregistrement $em->flush(); // … reste de la méthode } }

Et voici un autre exemple pour récupérer les compétences et leur niveau à partir d'un article donné. Je vous propose de modifier la méthode voirAction() :

<?php

// src/Sdz/BlogBundle/Controller/BlogController.php

class BlogController extends Controller {

// …

public function voirAction($id) {

// On récupère l'EntityManager

$em = $this->getDoctrine()

->getManager();

// On récupère l'entité correspondant à l'id $id

$article = $em->getRepository('SdzBlogBundle:Article') ->find($id);

if ($article === null) {

throw $this->createNotFoundException('Article[id='.$id.']

inexistant.'); }

// On récupère les articleCompetence pour l'article $article

$liste_articleCompetence = $em

->getRepository('SdzBlogBundle:ArticleCompetence')

->findByArticle($article->getId());

// Puis modifiez la ligne du render comme ceci, pour prendre en compte les articleCompetence :

return $this->render('SdzBlogBundle:Blog:voir.html.twig', array(

'article' => $article,

'liste_articleCompetence' => $liste_articleCompetence,

// … et évidemment les autres variables que vous pouvez avoir

)); } }

Et le code de la vue correspondante : Code : HTML & Django

{# src/Sdz/BlogBundle/Resources/views/Blog/voir.html.twig #}

{% extends "SdzBlogBundle::layout.html.twig" %} {% block title %}

Lecture d'un article - {{ parent() }}

{% endblock %}

{% block sdzblog_body %}

<h2>

{# On vérifie qu'une image est bien associée à l'article #}

{% if article.image is not null %}

<img src="{{ article.image.url }}" alt="{{ article.image.alt

}}" />

{% endif %}

{{ article.titre }}

</h2>

<i>Par {{ article.auteur }}, le {{ article.date|date('d/m/Y')

}}</i>

{% if article.categories.count > 0 %}

- Catégories :

{{ categorie.nom }}

{% if not loop.last %} - {% endif %}

{% endfor %} {% endif %} <div class="well"> {{ article.contenu }} </div> {% if liste_articleCompetence|length > 0 %} <div>

Compétences utilisées dans cet article :

<ul>

{% for articleCompetence in liste_articleCompetence %}

<li>{{ articleCompetence.competence.nom }} : {{ articleCompetence.niveau }}</li> {% endfor %} </ul> </div> {% endif %} <p>

<a href="{{ path('sdzblog_accueil') }}" class="btn"> <i class="icon-chevron-left"></i>

Retour à la liste </a>

<a href="{{ path('sdzblog_modifier', {'id': article.id}) }}" class="btn">

<i class="icon-edit"></i> Modifier l'article

</a>

<a href="{{ path('sdzblog_supprimer', {'id': article.id}) }}" class="btn"> <i class="icon-trash"></i> Supprimer l'article </a> </p> {% endblock %}

C'est un exemple simple bien sûr.

Attention, dans cet exemple, la méthode findByArticle() utilisée dans le contrôleur ne sélectionne que les

ArticleCompetence. Donc, lorsque dans la boucle dans la vue on fait {{ articleCompetence.competence }}, en réalité Doctrine va effectuer une requête pour récupérer la Competence associée à cette ArticleCompetence. C'est bien sûr une horreur, car il va faire une requête… par itération dans le for ! Si vous avez 20 compétences attachées à l'article, cela ferait 20 requêtes : inimaginable.

Pour charger les Competence en même temps que les ArticleCompetence dans le contrôleur, et ainsi ne plus faire de requête dans la boucle, il faut faire une méthode à nous dans le repository de ArticleCompetence. On voit tout cela dans le chapitre suivant dédié aux repositories. N'utilisez donc jamais cette technique, attendez le prochain chapitre ! La seule différence dans le contrôleur sera d'utiliser une autre méthode que findByArticle(), et la vue ne changera même pas.

Les relations bidirectionnelles