Créer une application avec Symfony2 et Doctrine2 (étape 4)

Your ads will be inserted here by

Easy Plugin for AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

Dans la continuité de l’article précédent concernant la partie « model » soit Doctrine2, dans lequel nous avons vu comment générer nos « Entities », nous allons désormais compléter ces derniers et insérer des données via les fixtures, puis refactoriser notre controller et notre vue.

Ameliorer nos « Entities »

Si vous avez déjà utiliser symfony (version 1), vous avez surement utiliser le « behavior » Timestampable, gérant automatiquement nos champs « created_at » et « updated_at ».

Cette façon de procéder n’existe plus dans Doctrine2, mais ces comportements peuvent être mis en place assez simplement, c’est ce que nous allons voir.

On va modifier quelque peu nos « entities » générées afin d’y ajouter la gestion des dates.

Le champ « created_at » sera géré par notre constructeur.

    // Application/BlogBundle/Entity/post.php
    public function __construct()
    {
        //...
        $this->createdAt = new \DateTime(); // ligne à ajouter
    }

Faire de même pour les autres « entities » Category, User et Comment, donc rajouter un constructeur si il n’existe pas déjà.

Nous devons également gérer un champs date « updated_at » de notre « Entity » Post.

Pour cela, nous allons utiliser les « callbacks » de doctrine, qui permettent l’utilisation de commandes avant ou après un événement du cycle de vie de nos objets, pour ce faire nous devons le spécifier à doctrine par une annotation, c’est ce que nous avons déjà fait pour l’entity « Post » :

// Application/BlogBundle/Entity/Post.php
 /**
 //...
 * @orm:HasLifecycleCallbacks
 */
class Post

Pour le choix de l’événement à utiliser nous devons nous poser la question : A quel moment vais-je devoir insérer une date dans mon champ « updated_at » ?

Ce sera avant une mise à jour de notre table, nous allons donc procéder de cette façon :

// Application/BlogBundle/Entity/Post.php
   //...
   /**
    * @orm:PreUpdate
    */
    public function preUpdate()
    {
        $this->updatedAt = new \DateTime();
    }

Maintenant si les « behaviors » vous manquent et vous souhaitez utiliser des comportements tel que « Timestampable », « Sluggable », « Translatable » etc.. qui sont bien souvent, pour ne pas dire toujours, très utiles vous pouvez télécharger le bundle DoctrineExtensions. Ce bundle fonctionne également sur le modèle d’annotations.

De façon paradoxale, il faut bien avouer que Symfony2 et Doctrine2 nous obligent parfois à réinventer la roue, des besoins d’utilisation de comportements tels que le « Sluggable » sont presque inévitables, il nous faut soit, les créer ou recréer, ou utiliser des bundles tiers.

Plus d’infos sur les évènements de doctrine2 sur le site officiel.

Note :vous avez remarqué que lors de la création de nos tables une table nommée « post_tag » a été créée donc 5 « entities » pour 6 tables, ce qui n’est pas du tout anormal puisqu’une « Entity » est différente d’une table.

C’est un des changements par rapport à symfony (version 1) où on aurait défini de façon explicite cette table qui est issue d’une relation de type Many to Many.

Cette relation de type Many to Many a en fait bien été définie dans notre « Entity » Post comme suit :

// Application/BlogBundle/Entity/Post.php
    /**
     * @orm:ManyToMany(targetEntity="Tag")
     * @orm:JoinTable(name="post_tag",
     *     joinColumns={@orm:JoinColumn(name="post_id", referencedColumnName="id")},
     *     inverseJoinColumns={@orm:JoinColumn(name="tag_id", referencedColumnName="id")}
     * )
     *
     * @var ArrayCollection $tags
     */
    protected $tags;

A noter donc :

// Application/BlogBundle/Entity/Post.php
     /**
     //...
     * @orm:JoinTable(name="post_tag", //...
     //...
     */

Nous avions, précédemment, créé notre base de données et nos tables, mais pour afficher quelque chose, il nous faut des données, on va donc générer un jeu de données en utilisant les « fixtures ».

Générer des données avec les fixtures

Dans un premier temps, nous devons télécharger la librairie data-fixtures qui n’est pas fournie avec Doctrine2.

Si vous téléchargez au travers de ce lien et non pas en utilisant la ligne de commande de github, renommez le dossier doctrine-fixtures et placez le dans le répertoire vendor.

Il nous reste plus qu’à définir le namespace associé via l’autoload.php

// app/autoload.php
$loader->registerNamespaces(array(
    'Doctrine\\Common\\DataFixtures'    => __DIR__.'/../vendor/doctrine-fixtures/lib',
    //...

Attention ! Veillez à bien l’ajouter AVANT ‘Doctrine\\Common’ (même principe que le routing), où il risque de chercher la librairie dans ce dernier répertoire.

Your ads will be inserted here by

Easy Plugin for AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

Il nous faut, pour commencer, créer un nouveau répertoire dédié aux fixtures dans Application/BlogBundle/ nous devons le nommer « DataFixtures » et à l’intérieur un autre répertoire que nous devons nommer « ORM », et dans ce nouveau répertoire on va créer un fichier qu’on choisira de nommer « DataLoader.php » qui va implémenter l’interface FixtureInterface, nous devrons donc redéfinir la méthode load() de l’interface et y insérer notre jeu de données.

// Application/BlogBundle/DataFixtures/ORM/DataLoader.php
namespace Application\BlogBundle\DataFixtures\ORM;
 
use Doctrine\Common\DataFixtures\FixtureInterface;

use Application\BlogBundle\Entity\Post;
use Application\BlogBundle\Entity\Category;
use Application\BlogBundle\Entity\Comment;
use Application\BlogBundle\Entity\Tag;
use Application\BlogBundle\Entity\User;
 
class FixtureLoader implements FixtureInterface
{
    public function load($manager)
    {
        // Users
        $user = new User();
        $user->setUserName('Emmanuel PEREIRA');
        $user->setEmail('contact@emmanuelpereira.com');
        $manager->persist($user);
        
        // Tags
        foreach(array('tag 1', 'tag 2', 'tag 3') as $value) {
            $tag = new Tag();
            $tag->setName($value);
            $manager->persist($tag);
            $tags_list[] = $tag;
        }
 
        // Categories
        foreach(array('Category 1', 'Category 2', 'Category 3') as $value) {
            $cat = new Category();
            $cat->setName($value);
            $manager->persist($cat);
            $cats_list[] = $cat;
        }
        
        // Posts 
        for ( $i = 1; $i <= 20; ++$i )
        {    
            $post = new Post();
            $post->setCategory($cats_list[rand(0, count($cats_list)-1)]);
            $post->setUser($user);
            $post->setTitle('Post ' . $i);
            $post->setSlug('post-' . $i);
            $post->setContent(
                'Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
                Maecenas placerat congue tristique. Aliquam non turpis quis 
                quam malesuada pretium ac id nunc. Nullam suscipit lacinia erat nec commodo. 
                Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 
                Duis bibendum justo sit amet neque tincidunt quis vulputate orci venenatis. 
                Aliquam eget eros nulla. Etiam nec eros vitae mauris tincidunt vulputate mollis a erat. 
                Curabitur nec risus ac mi tristique convallis sed vitae urna. Quisque id magna sit amet velit accumsan mattis. 
                Integer vestibulum mattis augue, a euismod erat tincidunt in. 
                Pellentesque rhoncus purus adipiscing tellus mattis commodo feugiat eros scelerisque. 
                Cras vel suscipit eros. Praesent sapien nisi, rutrum in lacinia vitae, ultricies non mi. 
                Sed eu nisl sed lorem dapibus scelerisque vitae non sem. Duis consequat elementum orci ac ullamcorper. 
                Maecenas vehicula enim suscipit quam congue vel sagittis ligula hendrerit. 
                Mauris tempor, urna quis ultricies blandit, elit tellus adipiscing odio, id lacinia velit dui a turpis.'
            );
            
            // ajout de tags au post de façon aléatoire
            foreach($tags_list as $tag) {
                if(rand(0,1)) {
                    $post->addTags($tag);
                }
            }
 
            $manager->persist($post);
            
            // Comments
            for($j=1; $j<5 ; $j++){
                if(rand(0, 1)){
                    $comment = new Comment();
                    $comment->setUser($user);
                    $comment->setContent('comment about '.$post->getTitle());
                    $comment->setPost($post);
                    $manager->persist($comment);
                }
            }
            
        }
        
        // on sauvegarde le tout dans la base de données
        $manager->flush();
    }
}

[edit] Pour charger notre jeu de données dans la base il nous faut taper la ligne de commande suivante :

> php app/console doctrine:data:load

Suivant la version, si cette dernière ne fonctionne pas, tapez :

> php app/console doctrine:fixtures:load

Vous pouvez vérifier dans votre base de données, vous devriez avoir un jeu de données pour chaque table, il va donc falloir les afficher, ce qui nécessite donc de refactoriser nos parties « controller » et « vues ».

Controller : récupérer des données

Nous avons nos « entities » fonctionnelles et nos données dans notre base de données, on va donc établir une liaison en utilisant l’entity manager de doctrine, au travers le container de service, et y récupérer nos données à afficher et les envoyer à la vue.

On retourne donc dans notre partie « controller ».

// Application/BlogBundle/Controller/BlogController.php
// ...
    public function indexAction()
    {    
        $em = $this->get('doctrine.orm.entity_manager');
        $posts = $em->getRepository('ApplicationBlogBundle:Post')->findAll();
        
        return $this->render('ApplicationBlogBundle:Blog:index.html.twig', array('posts' => $posts));
    }

Attention avec les nombreux changements survenus à la beta 2, si vous êtes sur la beta 2 ou supérieure le code est quelque peu différent.

        // $em = $this->get('doctrine.orm.entity_manager');
        $em = $this->get('doctrine')->getEntityManager();

L’ « entity repository » encapsule les requêtes de Doctrine2, nous avons d’office pour toutes nos « entities » des méthodes communes, tels que find(), findAll(), findOneBy(), findBy() et nous pouvons evidemment en rajouter d’autres en créant des méthodes personnalisées c’est ce que nous allons voir lors du prochain article.

Il nous reste donc la vue à refactoriser afin d’afficher nos données.

La vue : afficher nos données

// Application/BlogBundle/Resources/views/Blog/index.html.twig
{% extends "ApplicationBlogBundle::layout.html.twig" %}

{% block title %}
    symfony2 Blog Tutoriel | Accueil
{% endblock %}

{% block content %}

    
    {% for post in posts %}
        

{{ post.title }}

{{ post.content }}

{% endfor %} {% endblock %}

vous avez devinez que le filtre « length » permet d’utiliser la fonction count(), vous pouvez utiliser du conditionnel, des boucles et même des opérateurs ternaires (ce que nous avons fait pour faire apparaître ou pas le « s » du mot « commentaire »), l’utilisation des dates « DateTime », malheureusement il n’a pas de filtre pour gérer l’internationalisation « Intl » des dates selon l’utilisateur (ce qu’on tentera d’ajouter prochainement).

Il y a quelques filtres utiles qui n’existe pas (pas encore du moins) dans Twig, mais nous pouvons l’étendre afin de créer de nouveaux filtres, ce que nous verrons prochainement…

Bon alors, voyons un peu le résultat en rechargeant notre page « app_dev.php ».

Voila qui est pas mal du tout, nous avons nos « Posts », « Comments », « User », « Tags » et « Categories », le tout géré et affiché selon leurs propres relations.

Mais en regardant de plus près, nous pouvons voir qu’il a fallu 45 requêtes à doctrine, ce n’est pas très optimisé pour le moment, ça sera le sujet du prochain article…


Créer une application avec symfony2 et doctrine2 (étape 1)

Créer une application avec symfony2 et doctrine2 (étape 2)
Créer une application avec symfony2 et doctrine2 (étape 3)

Tags: , , , , ,


5 commentaires pour le sujet “Créer une application avec Symfony2 et Doctrine2 (étape 4)”

  1. Sébastien :

    Bonjour,

    Très bon tutos. Comment fais t-on pour charger les fixtures ?

  2. Emmanuel PEREIRA :

    Effectivement, il manque une ligne de commande, je l’ajoute de suite ;)

  3. YannH :

    Avec la beta3 (et avec les versions précédentes aussi, sûrement), quand on installe les fixtures manuellement, il faut aussi récupérer ce dossier : https://github.com/symfony/DoctrineFixturesBundle

    Il faut ensuite l’appeler « DoctrineFixturesBundle » et le placer dans « vendor/bundles/Symfony/Bundle/ ». Après cela, il faut enregistrer le bundle dans AppKernel.php en ajoutant la ligne :
    new Symfony\Bundle\DoctrineFixturesBundle\DoctrineFixturesBundle(),
    dans la function registerBundles().

    Après ces opérations, on a enfin accès à la commande « php app/console doctrine:fixtures:load ». :)

    Bonne soirée !

  4. Emmanuel PEREIRA :

    Exact, depuis la beta1 il me semble, donc beta1 et supérieure voir ici pour l’installation : http://symfony.com/doc/current/cookbook/doctrine/doctrine_fixtures.html.
    Les articles seront mis à jour prochainement.

  5. nadou :

    bjr,
    svp qui a une idée et peu m’aider a propos installation configuration et utilisation du sfFeedbundle et merci bcp

Laissez un commentaire :

*


created By ooyes.net