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

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.

Lors des derniers articles, nous avons mis en place, le routing, les controllers, les vues sous twig, il nous reste donc à nous pencher sur la logique métier de l’application, c’est la partie Model que nous allons donc voir en utilisant Doctrine2.

Cela impliquera de refactoriser les parties « Vue » et « Controller » en conséquence.

nous verrons également comment insérer des données via les fixtures de doctrine2.

Configuration du model

Chez les développeurs du coeur de Symfony2 nous sommes entrés dans une phase de profonde simplification de la configuration sous Doctrine2.

Alors pour les Preview Release (PR11 dans mon cas) il nous faut configurer Doctrine en rajoutant juste une ligne correspondant à notre bundle :

# Doctrine Configuration
doctrine:
 //...

    orm:
        auto_generate_proxy_classes: %kernel.debug%
        default_entity_manager: default
        entity_managers:
            default:
                mappings:
                    AcmeDemoBundle: ~
                    ApplicationBlogBundle: ~ // ligne à ajouter
  //...

Nous utiliserons la partie ORM de Doctrine2

Attention ! Depuis la Beta1 vous aurez plutôt cela :

# Doctrine Configuration
doctrine:
    //...
    orm:
        auto_generate_proxy_classes: %kernel.debug%
        auto_mapping: true

Dans ces cas la vous n’aurez besoin de rien changer, c’est une configuration en moins grâce à l’auto-mapping: true.

Doctrine 1 utilisait le design pattern active record, quant à la version 2 fortement inspirée d’Hibernate (JAVA) utilise plutôt les Design pattern DataMapper et Unit of Work, nous utiliserons des PPO (Plain PHP Object), on parlera dans Doctrine2 d’entity qui définiront nos objets persistants.

On va éviter de trop rentrer dans la théorie (voir la doc officielle), et nous mettre à l’oeuvre en commençant par créer un répertoire Entity dans src/Application/BlogBundle

La configuration de nos classes va se faire au travers d’annotations, on va définir nos différentes « entities » et y décrire les propriétés via le système d’annotation.

Devant chaque classe type Entity, il est très important d’y mettre l’annotation :

/**
 * @Entity
 */

Mais également ne pas oublier de préfixer chaque description de propriétés par :

/**
 * @orm:
 */

Bon c’est parti, créons nos entities :

// Application/BlogBundle/Entity/Post.php
namespace Application\BlogBundle\Entity;

/**
 * @orm:Entity
 * @orm:Table(name="post")
 * @orm:HasLifecycleCallbacks
 */
class Post
{
    /**
     * @orm:Id
     * @orm:Column(type="integer")
     * @orm:GeneratedValue(strategy="AUTO")
     * 
     * @var integer $id
     */
    protected $id;
    
    /**
     * @orm:Column(type="string", length="255")
     * 
     * @var string $title
     */
    protected $title;
    
    /**
     * @orm:Column(type="string", length="255", nullable=false)
     * 
     * @var string $slug
     */
    protected $slug;
    
    /**
     * @orm:Column(type="text")
     * 
     * @var string $content
     */
    protected $content;
    
    /**
     * @orm:Column(type="datetime", name="created_at")
     * 
     * @var DateTime $createdAt
     */
    protected $createdAt;
    
    /**
     * @orm:Column(type="datetime", name="updated_at", nullable="true")
     * 
     * @var DateTime $updatedAt
     */
    protected $updatedAt;
    
    /**
     * @orm:ManyToOne(targetEntity="Category")
     * @orm:JoinColumn(name="category_id", referencedColumnName="id")
     * 
     * @var Category $category
     */
    protected $category;
    
    /**
     * @orm:OneToMany(targetEntity="Comment", mappedBy="post")
     * 
     * @var Comment $comments
     */
    protected $comments;
    
    /**
     * @orm:ManyToOne(targetEntity="User", inversedBy="posts")
     * @orm:JoinColumn(name="user_id", referencedColumnName="id")
     * 
     * @var User $user
     */
    protected $user;
    
    /**
     * @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;
     
}

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.

// Application/BlogBundle/Entity/User.php

namespace Application\BlogBundle\Entity;

/**
 * @orm:Entity
 * @orm:Table(name="user")
 */
class User
{
    /**
     * @orm:Id
     * @orm:Column(type="integer")
     * @orm:GeneratedValue(strategy="AUTO")
     * 
     * @var integer $id
     */
    protected $id;
    
    /**
     * @orm:Column(type="string", length="255")
     * 
     * @var string $username
     */
    protected $username;
    
    /**
     * @orm:Column(type="string", length="255")
     * 
     * @var string $email
     */
    protected $email;
    
    /**
     * @orm:Column(type="datetime", name="created_at")
     * 
     * @var DateTime $createdAt
     */
    protected $createdAt;
    
    /**
     * @orm:OneToMany(targetEntity="Post", mappedBy="user")
     * @orm:OrderBy({"createdAt" = "DESC"})
     * 
     * @var ArrayCollection $posts
     */
    protected $posts;
    
}

// Application/BlogBundle/Entity/Comment.php

namespace Application\BlogBundle\Entity;

/**
 * @orm:Entity
 * @orm:Table(name="comment")
 */
class Comment
{
    /**
     * @orm:Id
     * @orm:Column(type="integer")
     * @orm:GeneratedValue(strategy="AUTO")
     * 
     * @var integer $id
     */
    protected $id;
    
    /**
     * @orm:ManyToOne(targetEntity="User", inversedBy="comments")
     * @orm:JoinColumn(name="user_id", referencedColumnName="id")
     * 
     * @var User $user
     */
    protected $user;
    
     /**
     * @orm:Column(type="text")
     * 
     * @var string $content
     */
    protected $content;
    
    /**
     * @orm:ManyToOne(targetEntity="Post", inversedBy="comments")
     * @orm:JoinColumn(name="post_id", referencedColumnName="id")
     * 
     * @var Post $post
     */
    protected $post;
    
    /**
     * @orm:Column(type="datetime", name="created_at")
     * 
     * @var DateTime $createdAt
     */
    protected $createdAt;
   
}

// Application/BlogBundle/Entity/Category.php

namespace Application\BlogBundle\Entity;

/**
 * @orm:Entity
 * @orm:Table(name="category")
 */
class Category
{
    /**
     * @orm:Id
     * @orm:Column(type="integer")
     * @orm:GeneratedValue(strategy="AUTO")
     * 
     * @var integer $id
     */
    protected $id;
    
    /**
     * @orm:Column(type="string", length="255")
     * 
     * @var string $name
     */
    protected $name;
    
    /**
     * @orm:Column(type="datetime", name="created_at")
     * 
     * @var DateTime $createdAt
     */
    protected $createdAt;
   
}

// Application/BlogBundle/Entity/Tag.php

namespace Application\BlogBundle\Entity;

/**
 * @orm:Entity
 * @orm:Table(name="tag")
 */
class Tag
{
    /**
     * @orm:Id
     * @orm:Column(type="integer")
     * @orm:GeneratedValue(strategy="AUTO")
     * 
     * @var integer $id
     */
    protected $id;
    
    /**
     * @orm:Column(type="string", length="255")
     * 
     * @var string $name;
     */
    protected $name;
    
    /**
     * @orm:ManyToMany(targetEntity="Post", mappedBy="tags")
     * 
     * @var Post $post
     */
    protected $post;

}

Nous nous sommes contentés de définir les propriétés en utilisant les annotations.

On utilise à la fois les relations OneToOne, OneToMany et ManyToMany, dans ce tutoriel on considérera que le post ne peut être relié qu’à une seule catégorie.

Ensuite on va laisser le soin à Doctrine de générer les accesseurs et les mutateurs (getters et setters). Pour cela, on va taper en ligne de commande :

> php app/console doctrine:generate:entities ApplicationBlogBundle

Si vous êtes sur la PR11 et sous windows, il se peut que vous ayez un message d’erreur « Something went terribly wrong » avec cette ligne de commande, il nous faut pour corriger cela (ce qu’on devrait pas faire en temps normal), manipuler quelque peu le coeur de Symfony2, précisément le bundle de Doctrine2 en remplaçant la méthode findBadPathForBundle() comme suit :

// vendor/symfony/src/Symfony/Bundle/DoctrineBundle/Command/DoctrineCommand.php
// ...
    protected function findBasePathForBundle($bundle)
    {
        $path = str_replace('\\', '/', $bundle->getNamespace());
        $search = str_replace('\\', '/', $bundle->getPath());
        $destination = str_replace('/'.$path, '', $search, $c);

        if ($c != 1) {
            throw new \RuntimeException(sprintf('Can\'t find base path for bundle (path: "%s", destination: "%s").', $path, $destination));
        }

        return $destination;
    }

vous pouvez retenter la ligne de commande, cela devrait désormais passer sans problème.

Voilà, vos « entities » ont été complétées, vous pourrez même apercevoir un contructeur pour les « entities » intégrant des relations « OneToMany » et « ManyToMany » avec l’ajout d’ArrayCollection de doctrine pour la gestion des collections d’objets.

On va ensuite créer notre base, le schema , créer nos tables avec les lignes de commandes qui suivent mais d’abord assurons nous d’avoir bien supprimer les anciens fichiers dans Entity, ceux préfixés par « ~ », faute de quoi vous risquez de tomber sur un message d’erreur.

> php app/console doctrine:database:create
> php app/console doctrine:schema:create

Nous aurions pu partir de fichiers yml pour générer nos entities ou xml, attention, des simplifications sont au programme de la beta2, notamment le répertoire les contenant.

Mais nous aurions pu également passer par une base existante pour créer nos entities en passant au préalable par une conversion yml ou xml, attention tout de même si vous avez des champs utilisant le typage « enum », doctrine2 ne sait pas le gérer (pas encore tout du moins) étonnant d’ailleurs !

Maintenant, il va falloir refactoriser nos parties controller et vues, nous allons voir plusieurs possibilités de mise en oeuvre et surtout comment optimiser quelque peu notre code. La suite dans un prochain article (cela prend un peu plus de temps, nouveau job et emploi du temps chargé ;-) ).


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 4)



Tags: , , , , ,


21 529 commentaires pour le sujet “Créer une application avec Symfony2 et Doctrine2 (étape 3)”

  1. Grég :

    Bonjour,
    Je suis en train de creer une entité un peu sur le même modele que le votre et je voudrai savoir comment vous faites mettre à jour la valeur du champ createdAt.
    Merci par avance.

  2. Emmanuel PEREIRA :

    Oui je vais y venir.
    Mettre à jour createdAt ou updatedAt dans la partie « model » et donc réaliser des « behavior » très simplement.
    Ca peut être fait au travers le constructeur comme au travers des événements de cycle de vie de nos entités.

  3. YannH :

    Bonsoir,
    Cet exemple d’application utilisant symfony2 est le chaînon qu’il me manquait pour passer de la théorie à la pratique. Je commence à réaliser le plein potentiel offert par symfony2 et ça me donne vraiment envie de poursuivre sur cette voie. Je tenais donc à vous remercier pour ces tutos. ;-)

    Au passage, pour ceux qui utilisent la beta3 comme moi, il y a quelques modifications à effectuer :
    – la première est de rajouter « use Doctrine\ORM\Mapping as ORM; » après le « namespace Application\BlogBundle\Entity; » dans chaque entité
    – ensuite, toujours pour les entités, remplacer @orm: par @ORM\
    On doit ces modifications à la nouvelle façon d’annoter les fichiers pour éviter les confusions : http://symfony.com/blog/symfony2-annotations-gets-better
    – remplacer la commande « php app/console doctrine:generate:entities ApplicationBlogBundle » par « php app/console doctrine:generate:entities Application\BlogBundle »

    C’est tout ce que j’ai remarqué.
    En espérant avoir été utile,
    YannH

  4. Emmanuel PEREIRA :

    c’est exact, les annotations ont changé depuis la beta 2, et d’après ce que je peux voir au sujet des discutions des développeurs, il se pourrait que les annotations soient encore modifiés prochainement, à voir….
    Les articles seront mis à jour.

  5. Dam :

    Hello je suis sur la beta3 j’ai donc fait les remplacement proposés par YannH. lorsque j’effectue la commande php app/console doctrine:generate:entities Application\BlogBundle

    J’obtiens l’erreur:

    [Doctrine\Common\Annotations\AnnotationException]
    [Syntax Error] Expected Doctrine\Common\Annotations\DocLexer::T_IDENTIFIER or Doctrine\Common\Annotations\DocLexer::T_TRUE or Doctrine\Common\Annotations\DocLexer::T_FALSE or Doctrine\Common\Annotations\DocLexer::T_NULL, got ‘:’ at position 5.

Laissez un commentaire :

*


created By ooyes.net