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.yml et app/config/config_prod.yml
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.
Réponse de Muriel le 19 juin 2013