Initialisation d'un projet Symfony 2.1 avec un dépôt Git et Composer

Je suppose que de plus en plus de projet vont démarrer avec Symfony 2 et en particulier avec la nouvelle version 2.1. Cette version introduit le support de Composer pour la gestion des dépendances. L'initialisation d'un projet est pour moi toujours une tache un peu délicate que je fais assez rarement. Pour ma première fois, c'est l'occasion de capitaliser l'information dans cet article tout comme on l'a déjà fait pour l'initialisation d'un projet Symfony 1.4.

Au programme de cette installation, Symfony 2.1 récupèré sur Github, l'ORM Propel 1.6 pour remplacer Doctrine 2, Composer pour gérer les dépendances et un dépot Git privé pour gérer le projet. J'effectue toutes les commandes sur mon serveur de développement qui tourne sur Debian et est inclus dans mon réseau locale (192.168.0.xxx). Je vous renvoie à mon article sur l'installation de Git et d'un dépot privé si besoin.

1. Symfony 2.1 sur Github

On commence par faire un clone de Symfony Standard Edition dans un dossier à part.

 
~/> mkdir sf2
~/> cd sf2/
~/sf2> git clone https://github.com/symfony/symfony-standard.git

On obtient dans le dossier symfony-standard un clone de la branche master qui est la version 2.1 en cours de développement. Personnellement, je ne travaille jamais avec les versions de dev, beaucoup trop instable à mon goût. Je me suis déjà retrouvé bloqué quelques jours car un commit sur le master provoquait un bug. Actuellement Symfony 2.1 est en Beta4, je vais donc utiliser le tag beta4 pour mon projet.

 
~/sf2> cd symfony-standard
~/sf2/symfony-standard> git checkout v2.1.0-BETA4
 
retour de la commande git: HEAD is now at 1e2d97e... updated VENDORS for 2.1.0-BETA4

Prenons quelques minutes pour analyser le contenu du dossier.

 
~/sf2/symfony-standard> ls -l
total 44
drwxrwxr-x 6 ulrich www-data 4096 aoû 10 15:52 app
-rw-rw-r-- 1 ulrich www-data 1784 aoû 10 15:56 composer.json
-rw-rw-r-- 1 ulrich www-data 5425 aoû 10 15:56 composer.lock
-rw-rw-r-- 1 ulrich www-data 1065 aoû 10 15:52 LICENSE
-rw-rw-r-- 1 ulrich www-data 5912 aoû 10 15:56 README.md
drwxrwxr-x 3 ulrich www-data 4096 aoû 10 15:52 src
-rw-rw-r-- 1 ulrich www-data 7857 aoû 10 15:56 UPGRADE.md
drwxrwxr-x 2 ulrich www-data 4096 aoû 10 15:52 web
 

On a la structure complète pour démarrer un projet Symfony 2 à l'exception du dossier vendor/ et de son contenu. Pour les personnes qui ont fait du Symfony 1, on a l'équivalent de la task generate:project.
Tous les fichiers que l'on vient de "checkouter" sont les fichiers que je vais vouloir inclure  à mon dépôt privé. Je supprime le lien avec github et je bouge tous les fichiers dans mon projet. Attention à ne pas oublier le fichier .gitignore

 
~/sf2/symfony-standard> rm -Rf .git
~/sf2/symfony-standard> cd
~/> git clone git@localhost:mon-projet.git
~/> cp -R sf2/symfony-standard/* sf2/symfony-standard/.gitignore mon-projet/
 

A ce stade, je fais un premier commit pour avoir la structure de départ. Dans le fichier .gitignore fournis, les dossiers app/cache et app/logs sont présent. Il faut commenter ces lignes si on souhaite que ces dossiers existent dans le dépôt. Je les décommentera plus tard. Cette manip évitera de devoir créer les dossiers à la main lors d'un nouveau clone.

 
~/> cd mon-projet
~/mon-projet> vim .gitignore
 
Puis je commente:
 
web/bundles/
app/bootstrap.php.cache
#app/cache/*
#app/logs/*
build/
vendor
composer.phar
 

Il ne reste plus qu'à faire un add et à commiter

 
~/mon-projet> git add .
~/mon-projet> git commit -m "init sf2.1"

Il faut penser à décommenter les lignes du fichier .gitignore et commiter les modifications. Sinon le contenu du cache et des logs viendront polluer le depôt git.

 
~/mon-projet> vim .gitignore
 
Puis je décommente
 
web/bundles/
app/bootstrap.php.cache
app/cache/*
app/logs/*
build/
vendor
composer.phar
 
~/mon-projet> git commit  .gitignore -m "ajout cache et log dans gitignore"

2. Composer et les dépendances

Composer se présente sous la forme d'une archive PHP: phar qui est éxecutable en ligne de commande. Composer se base sur les fichiers composer.json et composer.lock pour télécharger de façon récursive toutes les dépendances d'un projet et générer l'autoload.

 
~/mon-projet> curl -s https://getcomposer.org/installer | php
~/mon-projet> php composer.phar install

La première commande permet de télécharger Composer. A l'issue de la deuxième commande j'obtiens  un dossier vendor/ à la racine du projet.

3. Vérification de Symfony

Etant donné que je n'utilise pas un serveur de développement en local, je dois éditer les fichiers web/config.php et web/app_dev.php pour y accèder dans un navigateur.

 
<?php
 
if (!isset($_SERVER['HTTP_HOST'])) {
    exit('This script cannot be run from the CLI. Run it from a browser.');
}
 
if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
    '127.0.0.1',
    '::1',
))
&& !preg_match('#^192\.168\.0\.\d{1,3}$#', @$_SERVER['REMOTE_ADDR'])  // <--  cette ligne là
) {
    header('HTTP/1.0 403 Forbidden');
    exit('This script is only accessible from localhost.');
}
 

J'ai ajouté en "white list" les IPs de mon réseau local: 192.168.0.xxx .Pour vérifier que le serveur est correctement configuré pour Symfony 2, je lance dans le navigateur le fichier config.php. Ce script fournis toutes les infos pour faire tourner sf2 sur le serveur.

Depuis que j'utilise Symfony 2, j'ai beaucoup de problème avec le cache que je ne peux pas vider par manque de droit utilisateur.

 
~/mon-projet> php app/console cache:clear

Si la commande échoue, il faut supprimer le contenu du cache avec les droits de l'utilisateur root. Puis décommenter la ligne umask(0000) du fchier app_dev.php.

 
<?php
 
use Symfony\Component\HttpFoundation\Request;
 
// If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
umask(0000); // <--  cette ligne là
 
// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !in_array(@$_SERVER['REMOTE_ADDR'], array(
        '127.0.0.1',
        '::1',
    ))
&& !preg_match('#^192\.168\.0\.\d{1,3}$#', @$_SERVER['REMOTE_ADDR'])
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
 
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppKernel.php';
 
$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
 

Cette fois j'ai un Symfony pret à l'emploi, je pense qu'un commit dans Git s'impose.

4. Ajout de Propel

Hors de question d'alimenter la guerre entre Propel et Doctrine, je ne justifierai pas mon choix.
L'ajout d'un nouveau Bundle se fait en éditant le fichier composer.json

 
{
    "name": "symfony/framework-standard-edition",
    "description": "The \"Symfony Standard Edition\" distribution",
    "autoload": {
        "psr-0": { "": "src/" }
    },
    "require": {
       .....
        "propel/propel-bundle": "1.1.2"
    },
    .......

Ensuite il faut mettre à jour les dépendances. La commande install de Composer ne lit que le fichier composer.lock s'il est présent. Il faut utiliser la commande update pour mettre à jour le fichier composer.lock d'après le fichier composer.json.

 
~/mon-projet> php composer.phar update  propel/propel-bundle

Après la fonction update, j'ai nommé le bundle que je veux mettre à jour. C'est très important sinon Composer va mettre à jour toutes les dépendances et je ne pointerai plus sur le tag beta4 de symfony mais sur dev-master.

MAJ 10/02/2013

Composer a évolué, il est maintenant possible d'jaouter un nouveau bundle sans avoir à éditer le fichier composer.json. La fonction "require" permet d'ajouter plusieurs bundles à Symfony2.

 
> php composer.phar require propel/propel-bundle


Il faut encore ajouter le bundle Propel au fichier app/AppKernel.php, l'autoload est géré par Composer.

 
<?php
 
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
 
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
            new Symfony\Bundle\SecurityBundle\SecurityBundle(),
            new Symfony\Bundle\TwigBundle\TwigBundle(),
            new Symfony\Bundle\MonologBundle\MonologBundle(),
            new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
            new Symfony\Bundle\AsseticBundle\AsseticBundle(),
            //new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
            new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
            new JMS\AopBundle\JMSAopBundle(),
            new JMS\DiExtraBundle\JMSDiExtraBundle($this),
            new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(),
            new Propel\PropelBundle\PropelBundle(),                                           // <-- cette ligne
        );
 
 

Symfony 2 étant prévu pour fonctionner avec Doctrine il faut modifier le nom du driver dans le fichier app/config/parameters.yml. Doctrine et Propel utilisent tous les deux PDO pour mysql mais la déclaration est différente, "pdo_mysql" pour Doctrine et "mysql" pour Propel. Du coup il faut absolument commenter le bloc de configuration de Doctrine dans les fichiers app/config/config*.yml.

 
####app/config/parameters.yml
parameters:
    database_driver:   mysql
 

Configuration de Propel à ajouter dans les fichiers app/config/config_dev.php et app/config/config_prod.php

 
propel:
    dbal:
        driver:     %database_driver%
        user:       %database_user%
        password:   %database_password%
        dsn:        %database_driver%:host=%database_host%;dbname=%database_name%;charset=%database_charset%

Et pour finir la création du fichier app/config/propel.ini

 
# Enable full use of the DateTime class.
# Setting this to true means that getter methods for date/time/timestamp
# columns will return a DateTime object when the default format is empty.
propel.useDateTimeClass = true
 
# Specify a custom DateTime subclass that you wish to have Propel use
# for temporal values.
propel.dateTimeClass = DateTime
 
# These are the default formats that will be used when fetching values from
# temporal columns in Propel. You can always specify these when calling the
# methods directly, but for methods like getByName() it is nice to change
# the defaults.
# To have these methods return DateTime objects instead, you should set these
# to empty values
propel.defaultTimeStampFormat =
propel.defaultTimeFormat =
propel.defaultDateFormat =
 
# A better Pluralizer
propel.builder.pluralizer.class = builder.util.StandardEnglishPluralizer
 
# MySQL config
propel.mysql.tableType = InnoDB
 
# Behaviors come below
propel.behavior.default = timestampable
 


Un dernier commit avant de faire un push.
L'initialisation de symfony est maintenant terminée, il ne reste plus que la partie fun: coder le projet.

Il y a 4 commentaires

  • Renaud08-27-2012 16:11:17

    Sinon, on peut récupérer composer
    curl -s https://getcomposer.org/installer | php

    et lancer l'installation directement depuis composer:
    php composer.phar create-project symfony/framework-standard-edition path/

    Ensuite, on reprend à l'étape 3

  • Ulrich08-27-2012 16:26:16

    Merci pour cette info, je ne connaissais pas cette commande.

  • Raphaël06-19-2013 18:09:39

    Il y a quand même une différence entre les deux commandes:

    - "install" rapatrie les dépendances dans vendor, mais n'installe pas les dossiers annexes de type app, web etc.

    - "create-project" installe ces dossiers annexes également, mais place le tout dans un sous dossier (path), et pas dans le dossier vendor qui se trouve à la racine du projet. Il place également d'autres fichiers comme les mentions légales et le composer.json du framework, qui ne pourraient pas se trouver à la racine du projet.

    Bref, je ne sais pas trop quelle organisation de fichiers adopter...

  • Muriel06-19-2013 22:00:19


    @Raphaël la commande composer create-project remplace la première étape qui consiste à faire un git clone de symfony-standard et le checkout du tag ou de la branche que l'on veut utiliser.