Le blog de Noël GUILBERT

Aller au contenu Aller au menu

dimanche, février 21 2010

Utiliser Doctrine 2 avec Symfony

Pour ceux qui souhaitent tester Symfony 2, il faut savoir que Doctrine 2 est également fournit avec le framework, et déjà pré-configuré. Il n'y a donc presque rien à faire pour que ça fonctionne.

Activer l'ORM

Dans le fichier config.yml de votre projet, ajoutez la configuration suivante:

doctrine.orm: ~

doctrine.dbal:
  dbname:    blogdb
  username: bloguser
  password:  s3cr3t

Charger les entités

Pour charger les entités, il faut utiliser le ClassLoader de Doctrine, et celui-ci à besoin de savoir où sont stockés les entités :

# /path/to/your/Bundle/Bundle.php

<?php

namespace Bundle\BlogBundle;

use Symfony\Foundation\Bundle\Bundle as BaseBundle;
use Symfony\Components\DependencyInjection\ContainerInterface;
use Doctrine\Common\ClassLoader;

class Bundle extends BaseBundle
{

  public function boot(ContainerInterface $container)
  {
    $entitiesClassLoader = new ClassLoader('Entities', __DIR__.'/model/Entities');
    $entitiesClassLoader->register();
  }
}

Créez un répertoire Entities dans le bundle, et ajoutez-y quelques entités:

<?php

namespace Bundle\BlogBundle\Model\Entities;

/**
 * @Entity
 * @Table(name="blog_post")
 */

class BlogPost {
    /**
     * @Id @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     */

    private $id;
    /** @Column(type="string", length=255) */
    private $title;

    /** @Column(type="string", length=255) */
    private $slug;
   
    /** @Column(type="string") */
    private $body;
}

Ensuite, utiliser le conteneur de service pour récupérer l'EntityManager et manipuler vos objets:

class BlogController extends Controller
{
  public function showAction($slug)
  {
    $em   = $this->container->getService('doctrine.orm.manager');
    $post = $em->getRepository('Bundle\BlogBundle\Model\Entities\BlogPost')->findOneBy(array('slug' => $slug));

    return $this->render('BlogBundle:Blog:show', array('post' => $post));
  }
}

Symfony 2, comment ça fonctionne ?

Symfony 2

Attention : la version actuelle du Symfony 2 est une "preview" : les choses vont changer. Cette article est donc une découverte du framework tel qu'il a été présenté lors du Symfony Live 2010.

Lors du Symfony Live 2010, Fabien Potencier a révélé la toute nouvelle version du framework : Symfony 2 (avec un "S" majuscule la v2).

Pour l'occasion, j'ai pu essayer et mettre en place quelques briques de code, notamment une version adaptée du tutorial "Easy-Ajax" de symfony (avec un "s" minuscule pour les version 1.x).

Il est donc temps de vous raconter comment Symfony fonctionne. Dans ce billet, j'utiliserai le code de l'application Shopping Cart, disponible sur github : http://github.com/noelg/symfony-demo.

Structure

Avec symfony 1.x, la structure d'un projet est assez riche : apps, cache, data, config, lib, plugins, web. Avec Symfony 2, c'est beaucoup plus simple:

  • app : le répertoire pour l'application, et le nom n'as pas d'importance. Par exemple, dans l'application "Shopping Cart", ce répertoire s'appelle "cart"
  • src : l'ensemble du code de l'application
  • web : le répertoire public du projet, avec la même fonction qu'avec symfony 1, il contient doc naturellement le(s) front-controller(s)

Le front controller

Dans l'application "Shopping Cart", nous trouvons deux front-controllers dans le répertoire web/ :

  • index_dev.php
  • index.php

Comme avec symfony 1, ils contiennent le code nécessaire pour initialiser le framework:

<?php

require_once __DIR__.'/../cart/CartKernel.php';

$kernel = new CartKernel('dev', true);
$kernel->run();

Le code est assez simple :

  1. On récupère le "kernel" de notre application Cart
  2. On instancie le susdit kernel, en lui passant deux paramètres : l'environnement (ici "dev"), et l'activation du mode débug (ici, "true")
  3. Enfin, l'application est lancée à l'appel de la méthode "run" du kernel

Le Kernel

Le Kernel, avec Symfony 2, est l'endroit où l'ensemble de l'application est configurée :

  • autoloading
  • enregistrement des bundles (nous y reviendrons plus tard)
  • configuration de l'injection de dépendance et du routing

Autoloading

L'autoloading est simplement chargé grâce au fichier autoload.php prévu à cet effet :

<?php

require_once __DIR__.'/../src/autoload.php';

Ce fichier est lui-même assez simple à comprendre:

<?php

require_once __DIR__.'/vendor/symfony/src/Symfony/Foundation/UniversalClassLoader.php';

use Symfony\Foundation\UniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
  'Symfony'     => __DIR__.'/vendor/symfony/src',
  'Application' => __DIR__,
  'Bundle'      => __DIR__,
  'Doctrine'    => __DIR__.'/vendor/doctrine/lib',
));
$loader->registerPrefixes(array(
  'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes',
  'Zend_'  => __DIR__.'/vendor/zend/library',
));
$loader->register();

// for Zend Framework & SwiftMailer
set_include_path(__DIR__.'/vendor/zend/library'.PATH_SEPARATOR.__DIR__.'/vendor/swiftmailer/lib'.PATH_SEPARATOR.get_include_path());

On utilise ici la classe UniversalClassLoader, qui est une implémentation permettant de charger les classes respectant:

Deux méthodes sont appellées :

  • l'enregistrement des namespaces, avec registerNamespace()
  • L'enregistrement des prefix PEAR, avec registerPrefixes()

Si vous voulez ajouter des bibliothèques, vous devrez sans doute modifier ce fichier.

L'enregistrement des bundles

Dans Symfony 2, un bundle est l'équivalent de "plugin" avec symfony 1. Les bundles utilisés par l'application sont définis par la méthode registerBundles():

<?php

/* ... */

class CartKernel extends Kernel
{
  /* ... */

  public function registerBundles()
  {
    return array(
      new Symfony\Foundation\Bundle\KernelBundle(),
      new Symfony\Framework\WebBundle\Bundle(),
      new Symfony\Framework\ZendBundle\Bundle(),
      new Symfony\Framework\SwiftmailerBundle\Bundle(),
      new Symfony\Framework\DoctrineBundle\Bundle(),
      new Bundle\CartBundle\Bundle(),
    );
  }
}

Dans cette application, plusieurs bundles sont utilisés:

  • les bundles du framework
  • le bundle CartBundle, qui est le code de l'application "ShoppingCart"

Configuration de l'injecteur de dépendance et du routing

Deux autres méthodes sont définies pour configurer le routing et l'injecteur de dépendances :

public function registerContainerConfiguration()
{
  $loader = new ContainerLoader($this->getBundleDirs());

  return $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}

public function registerRoutes()
{
  $loader = new RoutingLoader($this->getBundleDirs());

   return $loader->load(__DIR__.'/config/routing.yml');
}

Encore une fois, le code est facile à comprendre, il n'y a rien de magique : on charge les fichiers config_*.yml et routing.yml. Et comme leur noms l'indiquent, ils permettent de configurer l'application et le routing.

config.yml

kernel.config: ~
web.web: ~
web.templating: ~
web.user:
  class: Bundle\CartBundle\User

Avec symfony 1, les fichiers de configuration sont plus nombreux (settings.yml, app.yml, factories.yml, filters.yml, etc), et nécessitent un peu de connaissance dès lors qu'on souhaite les customiser. Avec Symfony 2, un seul fichier : config.yml.

routing.yml

homepage:
  pattern:  /
  defaults: { _bundle: WebBundle, _controller: Default, _action: index }

cart:
  resource: CartBundle/Resources/config/routing.xml

Le fichier routing.yml est similaire à ce que l'on trouve dans symfony 1. La seule différence est dans le nommage des paramètres. Une fonctionnalité supplémentaire est de pouvoir charger un fichier de routing externe. C'est le cas ici, où l'on charge le fichier de routing du bundle CartBundle.

Les bundles

Un bundle, je l'ai dis plus tôt, est un "plugin". La différence majeure avec symfony 1, c'est qu'ils ont une place de premier choix dans Symfony 2 : tout est bundle, et tout doit être dans un implémenté dans un bundle. Plusieurs types de bundles sont possibles :

  • les bundles du framework : le code du framework
  • les bundles externes : typiquement, un brique logicielle autonome, et réutilisable dans différents projets
  • les bundles privés : une brique logicielle exclusivement développée pour une application

Structure

La structure d'un bundle est la suivante:

  • Bundle.php : la classe d'initialisation
  • Controller/ : le répertoire pour les contrôleurs
  • Model/ : le répertoire des classes du modèle
  • Resources/ : les ressources du bundle, à savoir la configuration, les templates et les ressources publiques (images, css, js, etc.)

Configuration

Rappelez-vous, les bundles sont initialisés dans le kernel :

<?php

/* ... */

class CartKernel extends Kernel
{
  /* ... */

  public function registerBundles()
  {
    return array(
      /* ... */
      new Bundle\CartBundle\Bundle(),
    );
  }
}

Avec Symfony 2, tout est explicite. La configuration du bundle se fait donc dans cette classe. Par exemple, le bundle "WebBundle" de Symfony implémente une méthode buildContainer() pour étendre l'injecteur de dépendance :

# src/vendor/symfony/src/Symfony/Framework/WebBundle/Bundle.php

class Bundle extends BaseBundle
{
  public function buildContainer(ContainerInterface $container)
  {
    Loader::registerExtension(new WebExtension());

    $dirs = array('%kernel.root_dir%/views/%%bundle%%/%%controller%%/%%name%%%%format%%.php');
    foreach ($container->getParameter('kernel.bundle_dirs') as $dir)
    {
      $dirs[] = $dir.'/%%bundle%%/Resources/views/%%controller%%/%%name%%%%format%%.php';
    }
    $container->setParameter('templating.loader.filesystem.path', $dirs);
  }
}

MVC

Symfony est un framework MVC (enfin, presque). On trouve donc plusieurs éléments :

  1. Le modèle
  2. Les contrôleurs
  3. les vues
Les contrôleurs

Les contrôleurs doivent être placés das le répertoire Controllers du bundle, et les méthodes d'action doivent être suffixées par "Action". Avec symfony 1, elles sont préfixées par "execute".

Voici un extrait du contrôleur CartController du bundle CartBundle:

# src/Bundle/CartBundle/Controller/CartController.php

namespace Bundle\CartBundle\Controller;

use Symfony\Framework\WebBundle\Controller;
use Bundle\CartBundle\Model\Product;

class CartController extends Controller
{
  public function indexAction()
  {
    return $this->render('CartBundle:Cart:index', array(
      'products' => Product::findAll(),
      'cart' => $this->getUser()->getCart()
    ));
  }
 /* ... */
}
Les ressources

Dans le répertoire "Resources" d'un bundle, on peut avoir plusieurs répertoires:

  • config/ : la configuration du bundle. Dans CartBundle, il y a la configuration du routing (routing.xml)
  • views/ : les templates associés aux contrôleurs
  • public : les ressources publiques du bundle : CSS, JS et images.

Conclusion

Une attention particulière a été apporté sur la facilité d'approche du framework. Pour cela, beaucoup de choses "magiques" avec symfony 1, sont désormais explicites : l'appréhension d'une application Symfony est donc beaucoup plus facile. De plus, grâce à ce tutorial, vous pourrez apprendre à l'utiliser en quelques dizaines de minutes. Je vous invite également à jeter un oeil au code de l'application Shopping Cart.

mardi, février 16 2010

Symfony Live 2010 : résumé de la première journée

Aujourd'hui avait lieu la permière journée du symfony live 2010. Plus de 300 personnes étaient présentes aujourd'hui, et plus de 30 nationalités étaient représentées.

Nous avons pu assister à plusieurs conférences autour de symfony:

  • Internationalization par Thomas Rabaix
  • Working with the admin-generator apr John Cleveley
  • Cloud and evolution of the Microsoft platform par Microsoft
  • Symfony Internals par Geoffrey Bachelet
  • Using Doctrine migrations and lime testing
  • Une présentation de Doctrine 2 par Jonathan Wage
  • An offline admin generator with HTML 5 and Gears, par Thomas Parisot
  • The symfony community - How you can (get) help, par Stefan Koopmanschap
  • Questions to the Core Team

La conférence la plus importante était sans conteste la présentation de Doctrine 2 par Jonathan Wage : les différentes fonctionnalités ont été présentées, et cette nouvelle version semble vraiment prometteuse, et beaucoup plus simple d'utilisation.

Demain, une dizaine de conférence sont prévues, dont la présentation officielle de Symfony 2, pour clôturer la journée. Le soir, un pot est organisé par GitHub et Sensio Labs au Patricks Irish Pub, au 33 rue de Montreuil à Paris, venez nombreux!

- page 2 de 7 -