Symfony2 checklist de déploiement

Assurez-vous que votre serveur de production utilise une clé secrète personnalisée. Vérifiez dans votre fichier app/config/parameters.yml :

secret:  please_use_a_real_secret_here

Par défaut la clé secrète n'est pas vraiment secrète, vous devez la remplacer par une autre générée de façon aléatoire.

Avant de déployer votre application, vous devez vous assurer que votre serveur de production est prêt pour l'exécuter.

Pour tester votre serveur, vous avez le choix entre trois méthodes :

  1. Exécuter manuellement php app/check.php pour voir quoi résoudre ;
  2. Accéder au fichier config.php avec votre navigateur, ce fichier est situé dans le répertoire web ;
  3. Si vous n'avez pas encore accès à votre serveur (vous prévoyez de le prendre), vous pouvez toujours visiter la page de référence dans la documentation

Symfony2 est un framework flexible et puissant... ce qui évidemment entraîne des temps d'exécution relativement lent. Bien sûr, l'environnement de production est bien plus rapide que l'environnement de développement que vous avez l'habitude d'utiliser, mais ce n'est pas suffisant.

Pour booster les performances de votre application en production, il est très recommandé d'installer un accélérateur PHP comme APC.

Sur un serveur dédié

Sous Linux

Pour installer APC sur une distribution basée sur Debian, exécutez simplement :

apt-get install php-apc

Adaptez la commande à votre distribution.

Sous Windows

Décommentez la ligne concernée dans votre php.ini :

extension=php_apc.dll

Dans tous les cas

Après l'installation, vous devez activer l'extension. Cela se fait en ajoutant cette ligne à la fin de votre php.ini :

[APC]
apc.enabled=1

Sur un hébergement mutualisé

Si vous êtes en hébergement mutualisé, vous n'avez certainement pas d'accès SSH. Dans ce cas, la meilleure solution est de contacter votre administrateur. Dites-lui qu'un accélérateur PHP est bon pour ses serveurs (car diminue la charge CPU).

Le composant générant les logs de votre application sont indispensables pour la gestion de votre plate-forme web. Symfony2 embarque le composant Monolog dédié à cette tâche.

Si la configuration par défaut convient pour l'environnement de développement, elle est un peu légère pour la production. Les modifications à apporter répondent à deux objectifs :

  • Envoyer à l'administrateur du site les erreurs par email (logs de niveau "error") ;
  • Enregistrer toutes les authentifications, car ce sont des logs de niveaux "info" qui ne sont pas loguées par défaut.

Allons configurer Monolog via le fichier config_prod.yml (et non config.yml pour ne pas impacter l'environnement de développement) :

monolog:
    handlers:
        main:
            type:               fingers_crossed
            action_level:       error
            handler:            grouped
        grouped:
            type:               group
            members:            [streamed, swift]
        streamed:
            type:               stream
            path:               "%kernel.logs_dir%/%kernel.environment%.log"
            level:              debug
        swift:
            type:               swift_mailer
            from_email:         FQN@foo.com
            to_email:           webmaster@company.com
            subject:            "OOps"
            level:              debug
        login:
            type:               stream
            path:               "%kernel.logs_dir%/auth.log"
            level:              info
            channels:           security

C'est tout !

Le composant Form de Symfony2 génère et valide automatiquement un jeton CSRF pour vous.

Assurez vous juste de bien personnaliser la clé secrète, qui est utilisé pour la génération des jetons, dans votre fichier app/config/parameters.yml :

secret:  utilisez_un_vrai_secret_ici

De plus, vous pouvez rendre unique le jeton pour chaque formulaire, ce qui est encore mieux. Pour cela, définissez l'option intention dans vos formulaires :

namespace Acme\DemoBundle\Form;

use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class TaskType extends AbstractType
{
    // ...

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            // Ici, une clé unique par formulaire pour la génération du jeton CSRF
            'intention' => 'task_form',
        ));
    }

    // ...
}

Par défaut, composer génére un autoloader qui n'est pas entièrement optimisé. En effet, lorsque vous avez de nombreuses classes, la génération de l'autoloader peut prendre un temps considérable..

En environnement de production, vous voulez que l'autoloader soit rapide. Composer peut générer un autoloader optimisé qui convertit les arborescences / espace de nom normalisés via PSR-0 en un fichier classmap, améliorant les performances.

Pour utiliser un autoloader optimisé, ajoutez juste l'option --optimize à la commande dump-autoload.

Commande composer :

php composer.phar dump-autoload --optimize

Bien sûr, cette option rend la commande un peu plus longue. C'est pourquoi par défaut elle est désactivée.

Si vous êtes habitués aux pages d'erreur de l'environnement "dev", ce n'est heureusement pas ce que vos visiteurs vont rencontrer en cas d'erreur sur votre site en production. Ainsi, vous devez impérativement personnaliser les différentes pages d'erreur, afin de les intégrer à votre layout. En effet, une page d'erreur hors du temps fera fuir très loin vos visiteurs.

Heureusement, personnaliser les pages d'erreur est quelque chose de très simple. Les vues de ces pages se situent en réalité dans le bundle TwigBundle, ce qui vous donne la clé pour les remplacer par les vôtres. Les vues que vous devez créer sont : Exception/errorXXX.html.twig, où XXX est le numéro de l'erreur rencontrée. Il est fortement conseillé de personnaliser a minima les erreurs 404 et 500.

Pour utiliser vos propres vues il y a deux solutions possibles :

  1. Soit vous créez un bundle qui hérite de TwigBundle et vous mettez les vues dans le répertoire Resources/views/Exception/errorXXX.html.twig. Cela vous permet de les réutiliser dans différents projets car elles sont dans un bundle à part ;
  2. Soit vous mettes les vues simplement dans le répertoire app/Resources/TwigBundle/views/Exception/errorXXX.html.twig. Si vos vues sont spécifiques au projet en cours, cela vous évite de créer un bundle juste pour cela.

Utiliser un favicons personnalisé et non celui de base fournit par Symfony2. Vous ne voulez pas que le logo Symfony apparaissent sur le navigateur de vos visiteurs. C'est pourquoi vous devez remplacer l'icône par défaut par le vôtre avant la mise en production.

Vous avez juste à remplacer le fichier : web/favicon.ico.

Pour créer un favicons, vous pouvez :

  • Utiliser des outils en ligne comme favicon.cc afin de générer des fichiers .ico
  • Utiliser une icône PNG. Dans ce cas vous devez définir un link dans votre code HTML : <link rel="icon" type="image/png" href="yourFavIcon.png">

En environnement de production, il est très recommandé d'utiliser le cache Doctrine. Il y a deux types de cache.

Cache de requête et de metadata

  • Le Query Cache met en cache la transformation d'une requête DQL dans sa représentation SQL. En production, vos requêtes ne vont pas changer toutes seules, alors profitons-en pour les mettre en cache.
  • Le Metadata Cache met en cache les informations metadata parsées depuis différentes sources, comme YAML, XML, Annotations, etc.

Mettre en cache ces informations se fait en définissant quelques paramètres dans votre fichier de configuration de production config_prod.yml :

doctrine:
    orm:
        auto_mapping: true
        query_cache_driver:    apc
        metadata_cache_driver: apc

Cache de résultat

Le résultat de vos requêtes peut être mis en cache, afin de ne pas interroger la base de données encore et encore. Comme c'est une mise en place assez fine, il n'y a pas de paramétrage complet pour toute votre application. Vous pouvez juste définir quel pilote utiliser, comme précédemment :

doctrine:
    orm:
        auto_mapping: true
        result_cache_driver: apc

Mais ensuite, vous devez expliciter comment utiliser ce cache pour toutes vos requêtes sensibles. Cela se fait en définissant un nom et une durée de vie à chacune de vos requêtes cachées. Voir la documentation Doctrine sur le cache de résultat (en).