Symfony2 - Les bundles et la structure des fichiers

Dans ce 2ème chapitre nous allons aborder un nouveau concept dans Symfony2: Les Bundles.
Nous verrons aussi comment sont organisés les fichiers et répertoires dans la nouvelle version du framework.




Qu'est-ce qu'un bundle Symfony ?


Dans cette nouvelle version de Symfony, nous ne parlerons plus de plugins ni de modules. A présent tout est Bundle !

Un Bundle est, pour faire simple, un ensemble de fichiers et répertoires permettant d'implémenter une ou des fonctionnalités (si possible réutilisables dans divers projets). Ils sont assez similaires au plugins dans Symfony 1.x, sauf que tout le code est stocké dans ces derniers: vues, actions, modèles, config...



Ainsi, nous pourrions avoir un bundle "CmsBundle" qui permet de gérer un système de CMS sur notre site web (Articles, commentaires, utilisateurs...) ou un bundle "ClassifiedBundle" qui pourrait gérer un système de petites annonces.

Vous l'aurez compris, un Bundle est donc une sorte de package comprenant toutes les couches métiers permettant de répondre à un besoin (grosse fonctionnalité).

J'espère que la définition est assez claire...


Bonnes pratiques et règles de nommage


Les bundles Symfony2 doivent être nommés, vous vous en doutez, d'une façon précise.

Les namespaces


Les namespaces apparaissent avec PHP 5.3


Dans Symfony2, toutes les classes sont référencées dans des namespace comme par exemple Novaway\CmsBundle\Entity qui pourrait référencer une entité (classe métier/modèle) de notre Bundle Cms (CmsBundle) créé par Novaway.
Un namespace est toujours composé de la même façon:
  • 1) Le nom du créateur/fournisseur (vendor segment en anglais). Dans notre exemple Novaway (On utilisera Wmd dans notre tutoriel).
  • 2) Un ou plusieurs répertoire vers le fichier référencé. Dans notre exemple CmsBundle\Entity.

Ainsi chaque classe devra spécifiée à quel namespace elle appartient en ajoutant la ligne suivante en début de page:
Code php:
namespace VotreOrganisation\VotreBundle\Repertoires;

Et il sera ensuite possible d'utiliser les classes d'un namespace dans une autre classe, ainsi:
Code php:
use VotreOrganisation\VotreBundle\Repertoires;

Les namespaces permettent l'interopérabilité de plusieurs Bundle développés par différentes personnes. Ils permettent de nommer explicitement ses classes de façon quasi uniques.

Nommage des Bundles


Les bundles peuvent être situés dans différents niveaux de répertoires, mais ils doivent répondre à un nom spécifique. Il est possible de créer un Bundle avec un namespace comme Wmd\Bundle\WatchMyDesk ou encore Wmd\WatchMyDeskBundle mais dans les deux cas, le nom de la classe sera: WmdWatchMyDeskBundle.
Les bundles sont toujours suffixé par "Bundle".

Les Bundles et classes doivent suivre la règle de nommage en CamelCase.

Passons maintenant à la pratique pour illustrer cette théorie.



Création de notre Bundle WatchMyDeskBundle


Passons maintenant à la création de notre bundle WatchMyDesk.

Comme dans Symfony 1.x, nous disposons de lignes de commande bien pratiques qui vont nous éviter de recréer à la main toute l'arborescence de notre bundle.
Notre code résidera essentiellement dans notre Bundle Wmd\Bundle\WatchMyDeskBundle.

Ouvrez votre console ssh et tapez la ligne de commande suivante:
php app/console generate:bundle


Suivez les instructions et saisissez les infos suivantes:
Génération du nouveau Bundle Symfony2


Bundle namespace: Entrez Wmd/WatchMyDeskBundle (On aurait pu mettre Wmd/Bundle/WatchMyDeskBundle, qui est plus dans la convention si on souhaitait diffuser notre bundle. Mais faisons plus simple pour le tuto).

Bundle Name: WmdWatchMyDeskBundle (Validez le choix par défaut)

Target directory: Il faut que le bundle soit créé dans votre répertoire src/

Configuration format: annotation (Plus pratique à utiliser)

Génération du nouveau Bundle Symfony2


Générer les répertoires complets: Oui, cela nous permettra d'avoir une structure de base.

Confirmez la génération du bundle.

Ajouter le bundle dans le kernel: Oui
Mettre à jour le routing: Oui

Et voilà, notre Bundle est désormais créé !

Si l'on déroule le répertoire src/, voici ce que l'on obtient:
Arborescence des fichiers de notre Bundle généré


C'est dans ce répertoire que nous allons ensuite créer nos classes métiers, nos actions, nos vues etc.
Pour mieux comprendre la structure d'un projet Symfony2, n'hésitez pas à faire un tour sur la doc officielle.

Un Bundle doit toujours être référencé dans AppKernel.php pour pouvoir être utilisé dans notre projet. Vérifiez que vous avez bien la ligne suivante dans votre fichier app/AppKernel.php:
Code php:
$bundles = array(
            //...
            new Wmd\WatchMyDeskBundle\WmdWatchMyDeskBundle(),
        );


Vous pouvez aussi vérifier que votre bundle a bien été installé en regardant dans votre Symfony profiler:

Bundles actifs dans le profiler Symfony




Ajout de bundles Symfony2 tiers dans notre application


Il est très simple et recommandé d'utiliser des Bundles déjà développés par d'autres entreprises ou développeurs afin de gagner du temps.
De nombreux bundles Symfony2 sont disponibles sur Github, n'hésitez pas à y faire un tour.

Bundles Symfony2 sur Github


En plus des bundles par défaut dans la Standard Edition de sf2, nous allons utiliser plusieurs Bundles tiers dans notre application:


Pour installer ces bundles tiers (dans vendor/bundles/), il suffit de renseigner l'adresse de leur répository GIT dans le fichier deps à la racine du projet. Ajoutez les lignes suivantes à la fin du fichier deps:
Code:
[doctrine-fixtures]
    git=http://github.com/doctrine/data-fixtures.git
    
[DoctrineFixturesBundle]
    git=http://github.com/symfony/DoctrineFixturesBundle.git
    target=/bundles/Symfony/Bundle/DoctrineFixturesBundle

[Pagerfanta]
    git=http://github.com/whiteoctober/Pagerfanta.git
    target=/pagerfanta

[WhiteOctoberPagerfantaBundle]
    git=http://github.com/whiteoctober/WhiteOctoberPagerfantaBundle.git
    target=/bundles/WhiteOctober/PagerfantaBundle

[SonataIntlBundle]
    git=http://github.com/sonata-project/SonataIntlBundle.git
    target=/bundles/Sonata/IntlBundle

[GravatarBundle]
    git=http://github.com/ornicar/GravatarBundle.git
    target=/bundles/Ornicar/GravatarBundle


Nous allons à présent utiliser l'executable bin/vendors pour réinstaller les bundles externes. Lancez la commande suivante:

bin/vendors install --reinstall


Vos fichiers vont se mettre à jour et les nouveaux packages vont être installés.
L'exécution de la commande peut prendre plusieurs minutes suivant votre connexion.

Comme pour notre Bundle, nous allons devoir référencer ces nouveaux packages dans notre application. Cette fois, c'est dans le fichier autoload.php que nous allons devoir apporter quelques modifications.
En effet, nous allons devoir enregistrer les namespaces de ces nouveaux bundles tiers pour pouvoir les utiliser.
Modifiez la méthode registerNamespaces du fichier app/autoload.php comme ceci:

Code php:
$loader->registerNamespaces(array(
    'Symfony'                           => array(__DIR__.'/../vendor/symfony/src', __DIR__.'\..\vendor\bundles'),
    'Sensio'                            => __DIR__.'/../vendor/bundles',
    'JMS'                               => __DIR__.'/../vendor/bundles',
    'Doctrine\\Common'                  => __DIR__.'/../vendor/doctrine-common/lib',
    'Doctrine\\Common\\DataFixtures'    => __DIR__.'/../vendor/doctrine-fixtures/lib',
    'Doctrine\\DBAL'                    => __DIR__.'/../vendor/doctrine-dbal/lib',
    'Doctrine'                          => __DIR__.'/../vendor/doctrine/lib',
    'Monolog'                           => __DIR__.'/../vendor/monolog/src',
    'Assetic'                           => __DIR__.'/../vendor/assetic/src',
    'Metadata'                          => __DIR__.'/../vendor/metadata/src',
    'WhiteOctober\PagerfantaBundle'     => __DIR__.'/../vendor/bundles',
    'Pagerfanta'                        => __DIR__.'/../vendor/pagerfanta/src',
    'Sonata'                            => __DIR__.'/../vendor/bundles',
    'Ornicar'                           => __DIR__.'/../vendor/bundles',
));


Maintenant que les namespaces sont ajoutés, il faut intégrer les bundles dans notre fichier app/AppKernel.php:

Code php:
        $bundles = array(
            //...
            new Sonata\IntlBundle\SonataIntlBundle(),
            new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
            new Ornicar\GravatarBundle\OrnicarGravatarBundle(),
            new Wmd\WatchMyDeskBundle\WmdWatchMyDeskBundle(),
        );


Ajoutez les 3 lignes juste avant la déclaration de notre Bundle WatchMyDesk.

Il reste le bundle DoctrineFixturesBundle à intégrer pour pouvoir charger facilement des jeux de données en mode développement. Étant donné que nous allons utiliser ce bundle uniquement lorsque nous développerons, nous allons le définir uniquement dans les environnement de test et développement.

Toujours dans le fichier AppKernel.php, ajoutez la ligne suivante avant l'accolade de la condition du test d'environnement:
Code php:
        if (in_array($this->getEnvironment(), array('dev', 'test'))) {
            // ...
            $bundles[] = new Symfony\Bundle\DoctrineFixturesBundle\DoctrineFixturesBundle();
        }


Il ne nous reste plus qu'à tester ! Rendez-vous dans votre profiler:
Vérification du chargement de nos bundles


Nos bundles sont prêts à être utilisés, et nous avons créé le bundle de notre projet, prochaine étape: Début du développement !






Rechercher sur la Ferme du web