• Aucun résultat trouvé

Apprendre à créer et stocker un projet Symfony2 dans git

N/A
N/A
Protected

Academic year: 2021

Partager "Apprendre à créer et stocker un projet Symfony2 dans git"

Copied!
287
0
0

Texte intégral

(1)

The Cookbook

for Symfony 2.1 generated on September 1, 2013

(2)

The Cookbook (2.1)

This work is licensed under the “Attribution-Share Alike 3.0 Unported” license (http://creativecommons.org/ licenses/by-sa/3.0/).

You are free to share (to copy, distribute and transmit the work), and to remix (to adapt the work) under the following conditions:

• Attribution: You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

• Share Alike: If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license. For any reuse or distribution, you must make clear to others the license terms of this work.

The information in this book is distributed on an “as is” basis, without warranty. Although every precaution has been taken in the preparation of this work, neither the author(s) nor SensioLabs shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in this work.

If you find typos or errors, feel free to report them by creating a ticket on the Symfony ticketing system (http://github.com/symfony/symfony-docs/issues). Based on tickets and users feedback, this book is continuously updated.

(3)

Contents at a Glance

Comment créer et stocker un projet Symfony2 dans git ...5

Comment créer et stocker un projet Symfony2 dans Subversion ...8

Comment personnaliser les pages d'erreur ...12

Comment définir des contrôleurs en tant que Services...14

Comment forcer les routes à toujours utiliser HTTPS ou HTTP...16

Comment autoriser un caractère « / » dans un paramètre de route ...18

Comment configurer une redirection vers une autre route sans contrôleur personnalisé ...19

Comment utiliser des méthodes HTTP autres que GET et POST dans les routes ...20

Comment utiliser des paramètres du conteneur de services dans vos routes ...22

Comment utiliser Assetic pour gérer vos ressources...24

Comment minifier les JavaScripts et les feuilles de style avec YUI Compressor ...29

Comment utiliser Assetic et les fonctions Twig pour optimiser les images ...31

Comment appliquer un filtre Assetic à une extension de fichier spécifique ...34

Comment gérer les uploads de fichier avec Doctrine...36

Comment utiliser les extensions Doctrine: Timestampable, Sluggable, Translatable, etc...44

Comment enregistrer des listeners (« écouteurs » en français) et des souscripteurs d'évènement...45

Comment utiliser la couche DBAL de Doctrine ...47

Comment générer des Entités à partir d'une base de données existante ...49

Comment travailler avec plusieurs gestionnaires d'entités et connexions ...53

Comment définir des fonctions DQL personnalisées ...56

Comment définir des Relations avec des Classes Abstraites et des Interfaces ...57

Comment implémenter un simple formulaire de création de compte...60

Comment personnaliser le rendu de formulaire...66

Comment utiliser les Convertisseurs de Données ...78

Comment générer dynamiquement des Formulaires en Utilisant les Évènements de Formulaire ...84

Comment imbriquer une Collection de Formulaires...88

Comment Créer un Type de Champ de Formulaire Personnalisé ... 100

Comment créer une extension de type de formulaire ... 105

Comment utiliser l'Option de Champ de Formulaire Virtual ... 111

Comment créer une Contrainte de Validation Personnalisée... 114

Comment Maîtriser et Créer de nouveaux Environnements ... 118

Comment surcharger la structure de répertoires par défaut de Symfony ... 123

Comment configurer les paramètres externes dans le conteneur de services... 126

Comment stocker les sessions dans la base de données grâce à PdoSessionStorage ... 129

Comment utiliser le routeur Apache ... 132

Comment créer un « listener » (« écouteur » en français) d'évènement... 135 PDF brought to you by

(4)

Comment travailler avec les champs d'applications (« scopes » en anglais) ... 138

Comment travailler avec les Passes de Compilation dans les Bundles ... 142

Comment utiliser les bonnes pratiques pour structurer vos Bundles... 143

Comment utiliser l'héritage de bundle pour surcharger certaines parties d'un bundle... 148

Comment surcharger n'importe quelle partie d'un bundle ... 151

Comment exposer une configuration sémantique pour un Bundle ... 154

Comment envoyer un Email ... 163

Comment utiliser Gmail pour envoyer des Emails ... 165

Comment travailler avec les Emails pendant le Développement ... 166

Comment utiliser le « Spool » d'Email... 168

Comment simuler une authentification HTTP dans un Test Fonctionnel ... 170

Comment tester les interactions de multiples clients... 171

Comment utiliser le Profiler dans un test fonctionnel ... 173

Comment tester les dépôts Doctrine ... 175

Comment personnaliser le processus de bootstrap avant les tests... 177

Comment charger les utilisateurs depuis la base de données (le fournisseur d'Entité)... 179

Comment ajouter la fonctionnalité de login « Se souvenir de moi » ... 189

Comment implémenter votre propre Voteur pour ajouter des adresses IP sur une liste noire... 192

Comment utiliser les Access Control Lists (ACLs) (« liste de contrôle d'accès » en français) ... 195

Comment utiliser les concepts d'ACL avancés... 199

Comment forcer HTTPS ou HTTP pour des URLs Différentes ... 203

Comment personnaliser votre formulaire de login ... 204

Comment sécuriser n'importe quel service ou méthode de votre application ... 208

Comment créer un Fournisseur d'Utilisateur personnalisé ... 212

Comment créer un Fournisseur d'Authentification Personnalisé ... 217

Comment changer le comportement par défaut du chemin cible... 226

Comment utiliser Varnish pour accélérer mon site Web ... 228

Comment injecter des variables dans tous les modèles (i.e. Variables Globales)... 230

Comment utiliser PHP plutôt que Twig dans les templates ... 232

Comment écrire une Extension Twig personnalisée... 237

Comment utiliser Monolog pour écrire des Logs ... 240

Comment configurer Monolog pour envoyer les erreurs par Email... 244

Comment loguer des messages dans différents fichiers ... 246

Comment créer une commande pour la Console ... 248

Comment utiliser la Console ... 251

Comment générer des URL avec un hôte personnalisé en ligne de commande ... 253

Comment optimiser votre environnement pour le debuggage ... 255

Comment mettre en place des filtres avant et après un processus donné... 257

Comment étendre une Classe sans utiliser l'Héritage ... 262

Comment personnaliser le Comportement d'une Méthode sans utiliser l'Héritage ... 265

Comment déclarer un nouveau Format de Requête et un Type Mime ... 267

Comment créer un Collecteur de Données personnalisé ... 269

Comment créer des web services SOAP à l'intérieur d'un contrôleur Symfony2 ... 272

En quoi Symfony2 diffère de Symfony1... 276

Déployer une application Symfony2 ... 282

(5)

Listing 1-1

Chapter 1

Comment créer et stocker un projet Symfony2

dans git

Bien que cet article soit spécifique à git, les mêmes principes génériques s'appliqueront si vous stockez votre projet dans Subversion.

Une fois que vous aurez lu La création de pages avec Symfony2 et que vous deviendrez familier avec l'usage de Symfony, vous serez sans aucun doute prêt à démarrer votre propre projet. Dans cet article du Cookbook, vous allez apprendre la meilleure façon qui soit de démarrer un nouveau projet Symfony2 stocké dans le système de gestion de contrôle de source git1.

Configuration Initiale du Projet

Pour démarrer, vous aurez besoin de télécharger Symfony et d'initialiser votre dépôt local git : 1. Télécharger Symfony2 Standard Edition2sans les « vendors ».

2. Dézippez/détarez la distribution. Cela va créer un dossier nommé Symfony avec votre nouvelle structure de projet, les fichiers de configuration, etc. Renommez-le en ce que vous voulez. 3. Créez un nouveau fichier nommé .gitignore à la racine de votre nouveau projet (par exemple

: à côté du fichier composer.json) et coller ce qui suit dedans. Les fichiers correspondants à ces patterns seront ignorés par git :

1 2 3 4 /web/bundles/ /app/bootstrap* /app/cache/* /app/logs/* 1. http://git-scm.com/ 2. http://symfony.com/download PDF brought to you by

(6)

Listing 1-2 Listing 1-3 Listing 1-4 5 6 /vendor/ /app/config/parameters.yml

Vous pouvez aussi avoir un fichier .gitignore qui peut être utilisé sur tout votre système, dans ce cas, vous pourrez trouver plus d'informations ici : Github .gitignore3. De cette manière, vous pouvez exclure les fichiers/dossiers souvent utilisés par votre IDE pour l'ensemble de vos projets. 4. Copiez app/config/parameters.yml vers app/config/parameters.yml.dist. Le fichier

parameters.yml est ignoré par git (voir ci-dessus) afin que les paramètres spécifiques à la machine comme les mots de passe de base de données ne soient pas committés. En créant le fichier parameters.yml.dist, les nouveaux développeurs peuvent rapidement cloner le projet, copier ce fichier vers parameters.yml, l'adapter, et commencer à développer.

5. Initialisez votre dépôt git : 1 $ git init

6. Ajoutez tous les fichiers initiaux dans git : 1 $ git add .

7. Créez un commit initial avec votre nouveau projet : 1 $ git commit -m "Initial commit"

8. Finalement, téléchargez toutes les bibliothèques tierces en exécutant composer. Pour plus de détails, consultez la page Mettre à jour les Vendors

A ce point, vous disposez d'un projet Symfony2 totalement fonctionnel qui est correctement committé sous git. Vous pouvez immédiatement commencer à développer, en committant les nouveaux changements dans votre dépôt git.

Vous pouvez continuer en lisant le chapitre La création de pages avec Symfony2 pour en apprendre plus sur comment configurer et développer votre application en interne.

L'Edition Standard Symfony2 est fournie avec des exemples de fonctionnalités. Pour supprimer le code de démonstration, suivez les instructions du fichier Readme de la Standard Edition4.

Gérer les bibliothèques vendors avec composer.json

Comment ça marche ?

Chaque projet Symfony utilise des bibliothèques tierces regroupées sous l'appellation « vendors ». D'une façon ou d'une autre, le but est de vous permettre de télécharger ces bibliothèques dans le répertoire vendor/ et de pouvoir obtenir pour chacune la version désirée.

3. https://help.github.com/articles/ignoring-files

4. https://github.com/symfony/symfony-standard/blob/master/README.md PDF brought to you by

(7)

Par défaut, ces bibliothèques sont téléchargées en exécutant php composer.phar install. Le fichier binaire composer.phar est une bibliothèque appellé Composer5. Vous pouvez en savoir plus sur son installation dans le chapitre Installation.

Le fichier composer.phar utilise un fichier composer.json situé à la racine de votre projet. Ce fichier au format JSON contient la liste des bibliothèques nécessaires à votre projet, ainsi que leurs versions et bien d'autres informations. Le fichier composer.phar se base également sur un fichier composer.lock, lequel vous permet d'arrêter la version à une révision précise. En faite, si un composer.lock existe, Les versions de ce fichier remplacerons celle dans composer.json. Pour mettre à jour vos bibliothèques, vous devez exécuter php composer.phar update.

Pour en savoir plus sur Composer, visitez GetComposer.org6(en anglais).

Nota bene : ces bibliothèques « vendor » ne sont pas gérées dans votre dépôt; ce sont de simples fichiers installés (et ignorés du dépôt git) dans le répertoire vendor/. Or, puisque toute l'information nécessaire pour télécharger ces fichiers est disponible dans composer.json et composer.lock (qui, eux, sont gérés par votre dépôt), tout autre développeur peut utiliser votre projet, lancer php composer.phar install, et obtenir les mêmes bibliothèques (et version). Vous contrôlez donc exactement le contenu de chaque bibliothèque, sans avoir besoin de le versionner dans votre dépôt.

Ainsi, lorsqu'un développeur veut travailler sur votre projet, il lui suffit de lancer le script php composer.phar install pour s'assurer que toutes les bibliothèques nécessaires soient téléchargées.

Mettre à jour Symfony

Puisque Symfony est une bibliothèque tierce de votre projet et qu'elle est donc gérée entièrement via composer.json et``composer.lock``, mettre à jour Symfony signifie simplement mettre à jour ces deux fichiers afin qu'ils correspondent à la dernière version de l'édition standard de Symfony. Bien sûr, si vous avez ajouté des entrées aux fichiers composer.json ou composer.lock, veillez à ne remplacer que les parties originales afin de ne pas supprimer les entrées supplémentaires.

Vendors et Submodules

Au lieu d'utiliser le fichier composer.json pour gérer les bibliothèques vendor, vous pourriez choisir à la place le système natif git submodules7. Il n'y a rien d'incorrect dans cette approche, bien que le système composer.json soit la manière officielle de résoudre ce problème et qu'il peut être parfois difficile de travailler avec les git submodules.

Stocker votre projet sur un serveur distant

Vous disposez maintenant d'un projet totalement fonctionnel stocké dans git. Cependant, dans la plupart des cas, vous voudrez aussi stocker votre projet sur un serveur distant que ce soit pour des raisons de sauvegardes mais aussi afin que d'autres développeurs puissent collaborer au projet.

La façon la plus facile de stocker votre projet sur un serveur distant est via GitHub8. Les dépôts publics sont gratuits, cependant vous devrez payer un abonnement mensuel pour héberger des dépôts privés. Une autre alternative est de stocker votre dépôt git sur n'importe quel serveur en créant un dépôt barebones9et en « pushant » ce dernier. Une bibliothèque qui aide à gérer ceci est Gitolite10.

5. http://getcomposer.org/ 6. http://getcomposer.org/ 7. http://git-scm.com/book/en/Git-Tools-Submodules 8. https://github.com/ 9. http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository 10. https://github.com/sitaramc/gitolite PDF brought to you by

(8)

Listing 2-1

Chapter 2

Comment créer et stocker un projet Symfony2

dans Subversion

Cette article est spécifique à Subversion et basé sur des principes que vous trouverez dans l'article Comment créer et stocker un projet Symfony2 dans git.

Une fois que vous avez lu La création de pages avec Symfony2 et que vous êtes devenu familier avec l'usage de Symfony, vous serez sans aucun doute prêt à démarrer votre propre projet. La méthode préférée pour gérer des projets Symfony2 est d'utiliser git1 mais certains préfèrent utiliser Subversion2, ce qui ne pose aucun problème! Dans cet article du Cookbook, vous allez apprendre comment gérer votre projet en utilisant svn3de la même manière que si vous l'aviez fait avec git4.

Ceci est une méthode parmi tant d'autres de stocker votre projet Symfony2 dans un dépôt Subversion. Il y a plusieurs manières de faire cela et celle-ci en est simplement une qui fonctionne.

Le Dépôt Subversion

Pour cet article, nous supposerons que votre schéma de dépôt suit la structure standard et répandue : 1 2 3 4 myproject/ branches/ tags/ trunk/ 1. http://git-scm.com/ 2. http://subversion.apache.org/ 3. http://subversion.apache.org/ 4. http://git-scm.com/ PDF brought to you by

(9)

Listing 2-2

Listing 2-3

Listing 2-4

Listing 2-5

La plupart des hébergements subversion devraient suivre cette pratique standard. C'est le schéma recommandé par Contrôle de version avec Subversion5et utilisé par la plupart des hébergements gratuits (voir Solutions d'hébergement Subversion).

Configuration Initiale du Projet

Pour démarrer, vous aurez besoin de télécharger Symfony2 et d'effectuer la configuration basique de Subversion :

1. Téléchargez Symfony2 Standard Edition6avec ou sans les « vendors ».

2. Dézippez/détarez la distribution. Cela va créer un dossier nommé Symfony avec votre nouvelle structure de projet, les fichiers de configuration, etc. Renommez-le en ce que vous voulez. 3. Effectuez un « checkout » du dépôt Subversion qui va héberger ce projet. Disons qu'il est

hébergé sur Google code7et nommé myproject :

1 $ svn checkout http://myproject.googlecode.com/svn/trunk myproject

4. Copiez les fichiers du projet Symfony2 dans le dossier subversion : 1 $ mv Symfony/* myproject/

5. Ecrivons maintenant les patterns pour les fichiers à ignorer. Tout ne doit pas être stocké dans votre dépôt subversion. Quelques fichiers (comme le cache) sont générés et d'autres (comme la configuration de la base de données) sont destinés à être adaptés sur chaque machine. Ainsi, nous utilisons la propriété svn:ignore afin de pouvoir ignorer ces fichiers spécifiques.

1 2 3 4 5 6 7 8 9 10 11 12 $ cd myproject/

$ svn add --depth=empty app app/cache app/logs app/config web $ svn propset svn:ignore "vendor" .

$ svn propset svn:ignore "bootstrap*" app/

$ svn propset svn:ignore "parameters.yml" app/config/ $ svn propset svn:ignore "*" app/cache/

$ svn propset svn:ignore "*" app/logs/ $ svn propset svn:ignore "bundles" web

$ svn ci -m "commit basic symfony ignore list (vendor, app/bootstrap*, app/ config/parameters.yml, app/cache/*, app/logs/*, web/bundles)"

6. Le reste des fichiers peut maintenant être ajouté et committé dans le projet : 1

2

$ svn add --force .

$ svn ci -m "add basic Symfony Standard 2.X.Y"

5. http://svnbook.red-bean.com/ 6. http://symfony.com/download 7. http://code.google.com/hosting/ PDF brought to you by

(10)

7. Copiez app/config/parameters.yml vers app/config/parameters.yml.dist. Le fichier parameters.yml est ignoré par svn (voir ci-dessus) afin que les paramètres spécifiques à la machine comme les mots de passe de base de données ne soient pas committés. En créant le fichier parameters.yml.dist, les nouveaux développeurs peuvent rapidement cloner le projet, copier ce fichier vers parameters.yml, l'adapter, et commencer à développer.

8. Finalement, téléchargez toutes les bibliothèques tierces en exécutant composer. Pour plus de détails, consultez la page Mettre à jour les Vendors

Si vous utilisez des versions « dev », alors git peut être utilisé pour installer ces bibliothèques puisqu'il n'y a pas d'archive disponible à télécharger.

A ce point, vous avez un projet Symfony2 entièrement fonctionnel stocké dans votre dépôt Subversion. Le développement peut démarrer avec des commits dans ce dernier.

Vous pouvez continuer en lisant le chapitre La création de pages avec Symfony2 pour en apprendre plus sur comment configurer et développer votre application en interne.

L'Edition Standard Symfony2 vient avec des exemples de fonctionnalités. Pour supprimer le code de démonstration, suivez les instructions du fichier Readme de la Standard Edition8.

Gérer les bibliothèques vendors avec composer.json

Comment ça marche ?

Chaque projet Symfony utilise des bibliothèques tierces regroupées sous l'appellation « vendors ». D'une façon ou d'une autre, le but est de vous permettre de télécharger ces bibliothèques dans le répertoire vendor/ et de pouvoir obtenir pour chacune la version désirée.

Par défaut, ces bibliothèques sont téléchargées en exécutant php composer.phar install. Le fichier binaire composer.phar est une bibliothèque appellé Composer9. Vous pouvez en savoir plus sur son installation dans le chapitre Installation.

Le fichier composer.phar utilise un fichier composer.json situé à la racine de votre projet. Ce fichier au format JSON contient la liste des bibliothèques nécessaires à votre projet, ainsi que leurs versions et bien d'autres informations. Le fichier composer.phar se base également sur un fichier composer.lock, lequel vous permet d'arrêter la version à une révision précise. En faite, si un composer.lock existe, Les versions de ce fichier remplacerons celle dans composer.json. Pour mettre à jour vos bibliothèques, vous devez exécuter php composer.phar update.

Pour en savoir plus sur Composer, visitez GetComposer.org10(en anglais).

Nota bene : ces bibliothèques « vendor » ne sont pas gérées dans votre dépôt; ce sont de simples fichiers installés (et ignorés du dépôt git) dans le répertoire vendor/. Or, puisque toute l'information nécessaire pour télécharger ces fichiers est disponible dans composer.json et composer.lock (qui, eux, sont gérés par votre dépôt), tout autre développeur peut utiliser votre projet, lancer php composer.phar install, et obtenir les mêmes bibliothèques (et version). Vous contrôlez donc exactement le contenu de chaque bibliothèque, sans avoir besoin de le versionner dans votre dépôt.

Ainsi, lorsqu'un développeur veut travailler sur votre projet, il lui suffit de lancer le script php composer.phar install pour s'assurer que toutes les bibliothèques nécessaires soient téléchargées. 8. https://github.com/symfony/symfony-standard/blob/master/README.md

9. http://getcomposer.org/ 10. http://getcomposer.org/ PDF brought to you by

(11)

Mettre à jour Symfony

Puisque Symfony est une bibliothèque tierce de votre projet et qu'elle est donc gérée entièrement via composer.json et``composer.lock``, mettre à jour Symfony signifie simplement mettre à jour ces deux fichiers afin qu'ils correspondent à la dernière version de l'édition standard de Symfony. Bien sûr, si vous avez ajouté des entrées aux fichiers composer.json ou composer.lock, veillez à ne remplacer que les parties originales afin de ne pas supprimer les entrées supplémentaires.

Solutions d'hébergement Subversion

La plus grosse différence entre git11 et svn12 est que Subversion a besoin d'un dépôt central pour fonctionner. Vous avez donc plusieurs solutions :

• Hébergement par vos soins : créez votre propre dépôt et accédez-y soit grâce au système de fichiers, soit via le réseau. Pour vous aider dans cette tâche, vous pouvez lire Contrôle de version avec Subversion13.

• Hébergement via une entité tierce : il y a beaucoup de solutions d'hébergement gratuites et sérieuses disponibles comme GitHub14, Google code15, SourceForge16 ou Gna17. Certaines d'entre elles offrent aussi des possibilités d'hébergement git.

11. http://git-scm.com/ 12. http://subversion.apache.org/ 13. http://svnbook.red-bean.com/ 14. https://github.com/ 15. http://code.google.com/hosting/ 16. http://sourceforge.net/ 17. http://gna.org/ PDF brought to you by

(12)

Listing 3-1

Chapter 3

Comment personnaliser les pages d'erreur

Lorsqu'une exception quelconque est lancée dans Symfony2, cette dernière est « capturée » par la classe Kernel et éventuellement transmise à un contrôleur spécial, TwigBundle:Exception:show pour qu'il la gère. Ce contrôleur, qui fait partie du coeur de TwigBundle, détermine quelle template d'erreur afficher et le code de statut qui devrait être défini pour l'exception donnée.

Les pages d'erreur peuvent être personnalisées de deux manières différentes, dépendant du niveau de contrôle que vous souhaitez :

1. Personnalisez les templates d'erreur des différentes pages d'erreur (expliqué ci-dessous) ; 2. Remplacez le contrôleur d'exception par défaut TwigBundle::Exception:show par votre

propre contrôleur et gérez le comme vous le désirez (voir exception_controller dans la référence de Twig) ;

La personnalisation de la gestion d'exception est en fait bien plus puissante que ce qui est écrit dans ces lignes. Un évènement interne, kernel.exception, est lancé et permet d'avoir le contrôle complet de la gestion des exceptions. Pour plus d'informations, voir L'évènement kernel.exception.

Tous les templates d'erreur se trouvent dans le TwigBundle. Pour surcharger ces templates, utilisez simplement la méthode standard qui permet de surcharger un template qui se trouve dans un bundle. Pour plus d'informations, voir La Surcharge de templates de Bundle.

Par exemple, pour surcharger le template d'erreur par défaut qui est affiché à l'utilisateur final, créez un nouveau template situé à cet emplacement app/Resources/TwigBundle/views/Exception/ error.html.twig : 1 2 3 4 5 6 7 8 9 <!DOCTYPE html> <html> <head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Une erreur est survenue : {{ status_text }}</title>

</head> <body>

<h1>Oups! Une erreur est survenue</h1>

<h2>Le serveur a retourné une erreur "{{ status_code }} {{ status_text }}".</h2>

PDF brought to you by

(13)

10 11

</body> </html>

Si vous n'êtes pas familier avec Twig, ne vous inquiétez pas. Twig est un moteur de templating simple, puissant et optionnel qui est intégré dans Symfony2. Pour plus d'informations à propos de Twig, voir Créer et utiliser les templates.

En plus de la page d'erreur HTML standard, Symfony fournit une page d'erreur par défaut pour quasiment tous les formats de réponse les plus communs, incluant JSON (error.json.twig), XML (error.xml.twig), et même Javascript (error.js.twig), pour n'en nommer que quelques uns. Pour surcharger n'importe lequel de ces templates, créez simplement un nouveau fichier avec le même nom dans le répertoire app/Resources/TwigBundle/views/Exception. C'est la manière standard de surcharger n'importe quel template qui se trouve dans un bundle.

Personnaliser la page 404 et les autres pages d'erreur

Vous pouvez aussi personnaliser des templates d'erreur spécifiques en vous basant sur le code de statut HTTP. Par exemple, créez un template app/Resources/TwigBundle/views/Exception/ error404.html.twig pour afficher une page spéciale pour les erreurs 404 (page non trouvée).

Symfony utilise l'algorithme suivant pour déterminer quel template utiliser :

• Premièrement, il cherche un template pour le format et le code de statut donné (ex error404.json.twig) ;

• S'il n'existe pas, il cherche un template pour le format donné (ex error.json.twig) ; • S'il n'existe pas, il se rabat sur le template HTML (ex error.html.twig).

Pour voir la liste complète des templates d'erreur par défaut, jetez un oeil au répertoire Resources/ views/Exception du TwigBundle. Dans une installation standard de Symfony2, le TwigBundle se trouve à cet emplacement : vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle. Souvent, la façon la plus facile de personnaliser une page d'erreur est de la copier depuis le TwigBundle vers le dossier app/Resources/TwigBundle/views/Exception, puis de la modifier.

Les pages d'exception aidant au débuggage qui sont montrées au développeur peuvent aussi être personnalisées de la même manière en créant des templates comme exception.html.twig pour la page d'exception HTML standard ou exception.json.twig pour la page d'exception JSON.

PDF brought to you by

(14)

Listing 4-1

Listing 4-2

Chapter 4

Comment définir des contrôleurs en tant que

Services

Dans le Book, vous avez appris comment un contrôleur peut facilement être utilisé lorsqu'il étend la classe de baseController1. Bien que ceci fonctionne très bien, les contrôleurs peuvent aussi être définis en tant que services.

Pour faire référence à un contrôleur qui est défini en tant que service, utilisez la notation avec deux-points (:). Par exemple, supposons que vous ayez défini un service nommé my_controller et que vous voulez le transmettre à une méthode appelée indexAction() à l'intérieur du service:

1 $this->forward('my_controller:indexAction', array('foo' => $bar));

Vous devez utiliser la même notation quand vous définissez la valeur de la route _controller : 1

2 3

my_controller: pattern: /

defaults: { _controller: my_controller:indexAction }

Pour utiliser un contrôleur de cette manière, il doit être défini dans la configuration du conteneur de services. Pour plus d'informations, voir le chapitre Service Container.

Lorsque vous utilisez un contrôleur défini en tant que service, il ne va pas étendre la classe de base Controller dans la plupart des cas. Au lieu de se reposer sur ses méthodes « raccourcis », vous allez intéragir directement avec les services dont vous avez besoin. Heureusement, cela est généralement très facile et la classe de base Controller elle-même est une formidable source d'inspiration quant à comment effectuer de nombreuses tâches usuelles.

1. http://api.symfony.com/2.1/Symfony/Bundle/FrameworkBundle/Controller/Controller.html PDF brought to you by

(15)

Listing 4-3

Spécifier un contrôleur en tant que service demande un petit plus de travail. L'avantage premier est que le contrôleur en entier ou tout service passé au contrôleur peut être modifié via la configuration du conteneur de services. Cela est spécialement utile lorsque vous développez un bundle open-source ou tout autre bundle qui va être utilisé dans beaucoup de projets différents. Donc, même si vous ne spécifiez pas vos contrôleurs en tant que services, vous allez probablement voir ceci effectué dans quelques bundles Symfony2 open-source.

Utiliser les annotations de routage

Lorsque vous utilisez les annotations pour définir le routage dans un contrôleur défini comme service, vous devrez votre service comme suit:

1 2 3 4 5 6 7 /** * @Route("/blog", service="my_bundle.annot_controller") * @Cache(expires="tomorrow") */

class AnnotController extends Controller {

}

Dans cet exemple, my_bundle.annot_controller devrait l'id de l'instance du AnnotController définie dans le conteneur de services. Cette partie est documentée dans le chapitre @Route et @Method.

PDF brought to you by

(16)

Listing 5-1

Listing 5-2

Chapter 5

Comment forcer les routes à toujours utiliser

HTTPS ou HTTP

Quelquefois, vous voulez sécuriser certaines routes et être sûr qu'on y accède toujours via le protocole HTTPS. Le composant « Routing » vous permet de forcer le système de l'URI via la condition requise _scheme : 1 2 3 4 5 secure: pattern: /secure

defaults: { _controller: AcmeDemoBundle:Main:secure } requirements:

_scheme: https

La configuration ci-dessus force la route nommée secure à toujours utiliser HTTPS.

Pendant la génération de l'URL de secure, et si le système actuel est HTTP, Symfony va automatiquement générer une URL absolue avec HTTPS comme « scheme » :

1 2 3 4 5 6 7

{# Si le « scheme » actuel est HTTPS #} {{ path('secure') }}

{# génère /secure

{# Si le « scheme » actuel est HTTP #} {{ path('secure') }}

{# génère https://example.com/secure #}

La condition requise est aussi forcée pour les requêtes entrantes. Si vous essayez d'accéder au chemin /secure avec HTTP, vous serez automatiquement redirigé à la même URL, mais avec le « scheme » HTTPS.

Les exemples ci-dessus utilisent https en tant que _scheme, mais vous pouvez aussi forcer une URL à toujours utiliser http.

PDF brought to you by

(17)

Le composant Security fournit une autre façon d'imposer HTTP ou HTTPS via le paramètre requires_channel. Cette méthode alternative est mieux adaptée pour sécuriser une « zone » de votre site web (toutes les URLs dans la zone /admin) ou pour sécuriser les URLs définies dans un bundle tiers.

PDF brought to you by

(18)

Listing 6-1

Chapter 6

Comment autoriser un caractère « / » dans un

paramètre de route

Parfois, on a besoin de construire des URLs avec des paramètres qui peuvent contenir un slash /. Prenons par exemple la route classique /hello/{name}. Par défaut, /hello/Fabien va correspondre à cette route mais pas /hello/Fabien/Kris. Cela est dû au fait que Symfony utilise ce caractère comme séparateur entre les parties de la route.

Ce guide explique comment vous pouvez modifier une route afin que /hello/Fabien/Kris corresponde à la route /hello/{name}, où {name} équivaut à Fabien/Kris.

Configurer la Route

Par défaut, les composants de routage de Symfony requièrent que les paramètres correspondent au pattern de regex suivant : [^/]+. Cela veut dire que tous les caractères sont autorisés sauf /.

Vous devez explicitement autoriser le caractère / à faire partie de votre paramètre en spécifiant un pattern de regex plus permissif.

1 2 3 4 5 _hello: pattern: /hello/{name}

defaults: { _controller: AcmeDemoBundle:Demo:hello } requirements:

name: ".+"

C'est tout ! Maintenant, le paramètre {name} peut contenir le caractère /.

PDF brought to you by

(19)

Listing 7-1

Chapter 7

Comment configurer une redirection vers une

autre route sans contrôleur personnalisé

Ce guide explique comment configurer une redirection d'une route vers une autre sans utiliser de contrôleur spécifique.

Supposez qu'il n'existe pas de contrôleur par défaut pour l'URL / de votre application et que vous voulez rediriger ces requêtes vers /app.

Votre configuration ressemblerait à ceci : 1 2 3 4 5 6 7 8 9 10 11 AppBundle: resource: "@App/Controller/" type: annotation prefix: /app root: pattern: / defaults: _controller: FrameworkBundle:Redirect:urlRedirect path: /app permanent: true

Dans cet exemple, vous configurez une route pour le chemin / et laissez la classeRedirectController1 la gérer. Ce contrôleur est fourni avec Symfony et propose deux actions pour rediriger les requêtes :

• urlRedirect redirige vers un autre chemin. Vous devez spécifier le paramètre path pour qu'il contienne le chemin vers la ressource vers laquelle vous voulez rediriger.

• redirect (pas montré ici) redirige vers une autre route. Vous devez définir le paramètre route avec le nom de la route vers laquelle vous voulez rediriger.

Le paramètre permanent indique aux deux méthodes de retourner un code de statut HTTP 301 au lieu du code 302 par défaut.

1. http://api.symfony.com/2.1/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.html PDF brought to you by

(20)

Listing 8-1

Listing 8-2

Chapter 8

Comment utiliser des méthodes HTTP autres

que GET et POST dans les routes

La méthode HTTP d'une requête est l'un des prérequis qui peuvent être vérifiés pour valider si une route correspond ou pas. Cela est abordé dans le chapitre sur le routage du Book « Routage » avec des exemples qui utilisent les méthodes GET et POST. Vous pouvez également utiliser d'autres méthodes HTTP de la même manière. Par exemple, si vous avez un billet de blog, alors vous pourriez utiliser le même schéma d'URL pour l'afficher, le modifier et le supprimer grâce aux méthodes GET, PUT et DELETE.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 blog_show: pattern: /blog/{slug}

defaults: { _controller: AcmeDemoBundle:Blog:show } requirements:

_method: GET blog_update:

pattern: /blog/{slug}

defaults: { _controller: AcmeDemoBundle:Blog:update } requirements:

_method: PUT blog_delete:

pattern: /blog/{slug}

defaults: { _controller: AcmeDemoBundle:Blog:delete } requirements:

_method: DELETE

Malheureusement, la vie n'est pas toujours si simple puisque plusieurs navigateurs ne supportent pas l'envoi de requêtes PUT et DELETE. Heureusement, Symfony2 vous fournit de manière simple de contourner cette limitation. En incluant le paramètre _method dans la chaîne de caractères de la requête, ou dans les paramètres d'une requête HTTP, Symfony l'utilisera comme méthode pour trouver une route correspondante. Cela peut être fait très facilement dans les formulaires grâce à un champ caché. Supposons que vous ayez un formulaire pour éditer un billet de blog :

PDF brought to you by

(21)

Listing 8-3 1 2 3 4 5

<form action="{{ path('blog_update', {'slug': blog.slug}) }}" method="post"> <input type="hidden" name="_method" value="PUT" />

{{ form_widget(form) }}

<input type="submit" value="Update" /> </form>

La requête soumise correspondra maintenant à la route blog_update et l'action updateAction sera utilisée pour traiter le formulaire.

De la même manière, le formulaire de suppression peut être modifié pour ressembler à ceci : 1

2 3 4 5

<form action="{{ path('blog_delete', {'slug': blog.slug}) }}" method="post"> <input type="hidden" name="_method" value="DELETE" />

{{ form_widget(delete_form) }}

<input type="submit" value="Delete" /> </form>

Alors, la route blog_delete sera utilisée.

PDF brought to you by

(22)

Listing 9-1

Listing 9-2

Listing 9-3

Chapter 9

Comment utiliser des paramètres du conteneur

de services dans vos routes

New in version 2.1: La possibilité d'utiliser ces paramètres dans vos routes est une nouveauté de Symfony 2.1.

Parfois, vous pouvez trouver utile de rendre certaines parties de vos routes configurables de façon globale. Par exemple, si vous construisez un site internationalisé, vous commencerez probablement pas une ou deux locales. Vous ajouterez certainement un prérequis dans vos routes pour empêcher l'utilisateur d'accéder à une autre locale que celles que vous supportez.

Vous pourriez coder en dure votre prérequis _locale dans toutes vos routes. Mais une meilleure solution sera d'utiliser un paramètre configurable du conteneur de services dans la configuration de votre routage :

contact:

pattern: /{_locale}/contact

defaults: { _controller: AcmeDemoBundle:Main:contact } requirements:

_locale: %acme_demo.locales%

Vous pouvez maintenant contrôler et définir le paramètre acme_demo.locales quelque part dans votre conteneur : 1 2 3 # app/config/config.yml parameters: acme_demo.locales: en|es

Vous pouvez aussi utiliser un paramètre pour définir votre schéma de route (ou une partie de votre schéma) :

PDF brought to you by

(23)

1 2 3

some_route:

pattern: /%acme_demo.route_prefix%/contact

defaults: { _controller: AcmeDemoBundle:Main:contact }

Tout comme dans les fichiers de configuration classiques du conteneur, si vous avez besoin d'un % dans votre route, vous pouvez échapper le signe popurcentage en le doublant. Par exemple, /score-50%% deviendra /score-50%.

PDF brought to you by

(24)

Listing 10-1

Listing 10-2

Chapter 10

Comment utiliser Assetic pour gérer vos

ressources

Assetic associe deux concepts majeurs : les ressources et les filtres. Les ressources sont des fichiers comme les feuilles de style, les JavaScript et les images. Les filtres peuvent être appliqués à ces fichiers avant qu'ils soient servis au navigateur. Cela permet de gérer séparément les fichiers ressources qui sont stockés par l'application des fichiers qui sont réellement présentés à l'utilisateur.

Sans Assetic, vous servez directement les fichiers qui sont stockés dans votre application : 1 <script src="{{ asset('js/script.js') }}" type="text/javascript" />

Mais avec Assetic, vous pouvez manipuler ces ressources de la manière dont vous le désirez (ou les charger où vous le voulez) avant de les servir. Cela signifie que vous pouvez :

• Minifier et combiner toutes vos CSS ou vos fichiers JavaScript

• Exécuter tous (ou juste une partie) vos fichiers CSS ou JS en passant par des compilateurs comme LESS, SASS ou CoffeeScript.

• Optimiser vos images

Ressources

Utiliser Assetic plutôt que servir les fichiers directement offre de nombreux avantages. Les fichiers n'ont pas besoin d'être stockés là où il seront servis, et peuvent provenir de plusieurs sources, notamment d'un bundle : 1 2 3 4 5 {% javascripts '@AcmeFooBundle/Resources/public/js/*' %}

<script type="text/javascript" src="{{ asset_url }}"></script>

{% endjavascripts %}

PDF brought to you by

(25)

Listing 10-3

Listing 10-4

Listing 10-5

Listing 10-6

Pour inclure une feuille de style, vous pouvez utiliser le même procédé que

ci-dessus, sauf que vous utiliserez le tag stylesheets :

1 2 3 4 5 {% stylesheets '@AcmeFooBundle/Resources/public/css/*' %}

<link rel="stylesheet" href="{{ asset_url }}" /> {% endstylesheets %}

Dans cet exemple, tous les fichiers du répertoire Resources/public/js/ du bundle AcmeFooBundle seront chargés et servis depuis un autre répertoire. La balise réellement générée pourrait ressembler à ceci :

1 <script src="/app_dev.php/js/abcd123.js"></script>

C'est un point essentiel : une fois que vous laissez Assetic gérer vos ressources, les fichiers sont servis depuis différents emplacements. Cela peut poser des problèmes avec les CSS qui utilisent des images référencées par des chemins relatifs. Pourtant, ce problème peut être résolu en utilisant le filtre cssrewrite qui met à jour les chemins dans les fichiers CSS pour prendre en compte leur nouvel emplacement.

Combiner des ressources

Vous pouvez aussi combiner plusieurs fichiers en un seul. Cela aide à réduire le nombre de requêtes HTTP, ce qui est très important pour les performances. Cela vous permet aussi de maintenir les fichiers plus facilement en les découpants en petites parties faciles à gérer. Cela peut être un plus pour la réusabilité de votre projet puisque vous pouvez facilement séparer les fichiers spécifiques au projet des fichiers qui peuvent être réutilisés dans d'autres applications, mais toujours les servir comme un fichier unique : 1 2 3 4 5 6 7 {% javascripts '@AcmeFooBundle/Resources/public/js/*' '@AcmeBarBundle/Resources/public/js/form.js' '@AcmeBarBundle/Resources/public/js/calendar.js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

En environnement de dev, chaque fichier est toujours servi individuellement pour que vous puissiez débugguer plus facilement. Cependant, en environnement de prod, ils seront affichés dans une unique balise script.

Si vous découvrez Assetic et essayez d'utiliser votre application en environnement de prod (en utilisant le contrôleur app.php), vous verrez probablement que vos CSS et JS plantent. Pas de panique ! C'est fait exprès. Pour plus de détails sur l'utilisation d'Assetic en environnement de prod, lisez Exporter les ressources.

Et combiner les fichiers ne s'applique pas uniquement à vos fichiers. Vous pouvez aussi utiliser Assetic pour combiner les ressources tierces, comme jQuery, à vos fichiers dans un fichier unique :

PDF brought to you by

(26)

Listing 10-7 Listing 10-8 Listing 10-9 1 2 3 4 5 6 {% javascripts '@AcmeFooBundle/Resources/public/js/thirdparty/jquery.js' '@AcmeFooBundle/Resources/public/js/*' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

Filtres

Une fois qu'elles sont gérées par Assetic, vous pouvez appliquer des filtres à vos ressources avant qu'elles soient servies. Cela inclut les filtres qui compressent vos ressources pour réduire la taille des fichiers (pour de meilleures performances). D'autres filtres peuvent compiler des fichiers CoffeeScript en JavaScript ou convertir vos fichiers SASS en CSS. En fait, Assetic possède une longue liste de filtres.

Plusieurs de ces filtres ne font pas le travail directement, mais utilisent des bibliothèques tierces pour faire le gros du travail. Cela signifie que vous devrez souvent installer une bibliothèque tierce pour utiliser un filtre. Le grand avantage d'utiliser Assetic pour faire appel à ces bibliothèques (plutôt que de les utiliser directement) est qu'au lieu de les exécuter à la main après avoir modifié les fichiers, Assetic prendra tout en charge pour vous, et supprimera définitivement cette étape du processus de développement et de déploiement.

Pour utiliser un filtre, vous aurez d'abord besoin de le spécifier dans la configuration d'Assetic. Ajouter un filtre dans la configuration ne signifie pas qu'il est utilisé, mais juste qu'il est prêt à l'être (vous allez l'utiliser ci-dessous).

Par exemple, pour utiliser le JavaScript YUI Compressor, la configuration suivante doit être ajoutée : 1 2 3 4 5 # app/config/config.yml assetic: filters: yui_js: jar: "%kernel.root_dir%/Resources/java/yuicompressor.jar"

Maintenant, pour vraiment utiliser le filtre sur un groupe de fichiers, ajoutez le dans votre template : 1 2 3 4 5 6 {% javascripts '@AcmeFooBundle/Resources/public/js/*' filter='yui_js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

Vous pouvez trouver un guide plus détaillé sur la configuration et l'utilisation des filtres Assetic ainsi que des informations sur le mode debug d'Assetic en lisant Comment minifier les JavaScripts et les feuilles de style avec YUI Compressor.

Contrôler l'URL utilisée

Si vous le voulez, vous pouvez contrôler les URLs générées par Assetic. Cela se fait dans le template, et le chemin est relatif par rapport à la racine publique :

PDF brought to you by

(27)

Listing 10-10 Listing 10-11 1 2 3 4 5 6 {% javascripts '@AcmeFooBundle/Resources/public/js/*' output='js/compiled/main.js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

Symfony contient également une méthode pour le cache busting (technique empêchant la mise en cache), où l'URL générée par Assetic contient un paramètre qui peut être incrémenté, via la configuration, à chaque déploiement. Pour plus d'informations, lisez l'option de configuration assets_version.

Exporter les ressources

En environnement de dev, Assetic génère des chemins vers des fichiers CSS et JavaScript qui n'existent pas physiquement sur votre ordinateur. Mais ils sont néanmoins affichés car un contrôleur interne de Symfony ouvre les fichiers et sert leur contenu (après avoir exécuté tous les filtres).

Cette manière dynamique de servir des ressources traitées est géniale car cela signifie que vous pouvez immédiatement voir les modifications que vous apportez à vos fichiers. Mais l'inconvénient et que cela peut parfois être un peu plus lent. Si vous utilisez beaucoup de filtres, cela peut être carrément frustrant. Heureusement, Assetic fournit une méthode pour exporter vos ressources vers des fichiers réels au lieu de les générer dynamiquement.

Exporter les ressources en environnement de

prod

En environnement de prod, vos fichiers JS et CSS sont représentés chacun par une balise unique. En d'autres termes, plutôt que de voir chacun des fichiers JavaScript que vous incluez dans votre code source, vous verrez probablement quelque chose comme ceci :

1 <script src="/app_dev.php/js/abcd123.js"></script>

De plus, ce fichier n'existe pas vraiment et n'est pas non plus affiché dynamiquement par Symfony (car les ressources sont en environnement de dev). C'est fait exprès : laisser Symfony générer ces fichiers dynamiquement en production serait tout simplement trop lent.

Au lieu de cela, chaque fois que vous exécutez votre application dans l'environnement de prod (et par conséquent, chaque fois que vous déployez), vous devriez lancer la commande suivante :

1 $ php app/console assetic:dump --env=prod --no-debug

Cela génèrera physiquement et écrira chaque fichier dont vous avez besoin (ex /js/abcd123.js). Si vous mettez à jour vos ressources, vous aurez besoin de relancer cette commande pour regénérer vos fichiers.

Exporter les ressources en environnement de

dev

Par défaut, chaque chemin de ressource généré en environnement de dev est pris en charge dynamiquement par Symfony. Cela n'a pas d'inconvénient (vous pouvez voir vos changements immédiatement), sauf que les ressources peuvent être chargées plus lentement. Si vous trouvez que vos ressources sont chargés trop lentement, suivez ce guide

PDF brought to you by

(28)

Listing 10-12

Listing 10-13

Listing 10-14

Listing 10-15

Premièrement, dites à Symfony de ne plus essayer de traiter ces fichiers dynamiquement. Apportez les modifications suivantes dans le fichier config_dev.yml :

1 2 3 # app/config/config_dev.yml assetic: use_controller: false

Ensuite, puisque Symfony ne génère plus ces fichiers pour vous, vous aurez besoin de les exporter manuellement. Pour ce faire, lancez la commande suivante :

1 $ php app/console assetic:dump

Elle écrit physiquement tous les fichiers de ressource dont vous avez besoin pour l'environnement de dev. Le gros inconvénient est que vous devrez faire cela chaque fois que vous modifiez une ressource. Heureusement, en passant l'option --watch, la commande regénèrera automatiquement les ressources modifiées :

1 $ php app/console assetic:dump --watch

Lancer cette commande en environnement de dev peut générer un florilège de fichiers. Pour conserver votre projet bien organisé, il peut être intéressant de mettre les fichiers générés dans un répertoire séparé (ex /js/compiled) : 1 2 3 4 5 6 {% javascripts '@AcmeFooBundle/Resources/public/js/*' output='js/compiled/main.js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

PDF brought to you by

(29)

Listing 11-1

Chapter 11

Comment minifier les JavaScripts et les feuilles

de style avec YUI Compressor

Yahoo! fournit un excellent utilitaire pour minifier les JavaScripts et les feuilles de style pour qu'elles soient plus rapides à charger, YUI Compressor1. Grâce à Assetic, vous pourrez tirer profit de cet outil très facilement.

Téléchargez le JAR YUI Compressor

YUI Compressor est écrit en Java est distribué sous forme de JAR. Téléchargez le JAR2 sur le site de Yahoo! et enregistrez le sous app/Resources/java/yuicompressor.jar.

Configurez les filtres YUI

Maintenant vous devez configurer les deux filtres Assetic dans votre application, l'un pour minifier les JavaScripts avec YUI Compressor et l'autre pour minifier les feuilles de style :

1 2 3 4 5 6 7 8 # app/config/config.yml assetic: # java: "/usr/bin/java" filters: yui_css: jar: "%kernel.root_dir%/Resources/java/yuicompressor.jar" yui_js: jar: "%kernel.root_dir%/Resources/java/yuicompressor.jar" 1. http://developer.yahoo.com/yui/compressor/ 2. http://yuilibrary.com/projects/yuicompressor/ PDF brought to you by

(30)

Listing 11-2

Listing 11-3

Listing 11-4

Les utilisateurs de Windows ne doivent pas oublier de mettre à jour la location de Java. Dans Windows8 x64 bit, il s'agit de C:\Program Files (x86)\Java\jre6\bin\java.exe par défaut

Vous avez maintenant accès aux deux nouveaux filtres Assetic dans votre application : yui_css et yui_js. Ils utiliseront YUI Compressor pour minifier respectivement les feuilles de style et les JavaScripts.

Minifiez vos Ressources

Maintenant YUI Compressor est configuré, mais rien ne se passera tant que vous n'appliquez pas ces filtres à une ressource (asset). Puisque vos ressources font partie de la couche Vue, ce travail doit être fait dans vos templates :

1 2 3

{% javascripts '@AcmeFooBundle/Resources/public/js/*' filter='yui_js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

L'exemple ci-dessus part du principe que vous avez un bundle appelé AcmeFooBundle et que vos fichiers JavaScript se trouvent dans le répertoire Resources/public/js dans votre bundle. Ce n'est, en fait, pas très important car vous pouvez inclure vos fichiers JavaScript où vous le voulez. En rajoutant le filtre yui_js à la ressource ci-dessus, vous devriez voir que les JavaScripts minifiés sont chargés beaucoup plus rapidement. Le même procédé peut être utilisé pour minifier vos feuilles de style.

1 2 3

{% stylesheets '@AcmeFooBundle/Resources/public/css/*' filter='yui_css' %}

<link rel="stylesheet" type="text/css" media="screen" href="{{ asset_url }}" />

{% endstylesheets %}

Désactiver la minification en Mode Debug

Les JavaScripts et feuilles de styles minifiés sont très difficiles à lire; et encore moins à débugguer. Pour palier cela, Assetic vous permet de désactiver un filtre lorsque votre application est en mode debug. Vous pouvez faire cela en préfixant le nom du filtre dans votre template par un point d'interrogation : ?. Cela indique à Assetic de n'appliquer les filtres que si le mode debug n'est pas actif.

1 2 3

{% javascripts '@AcmeFooBundle/Resources/public/js/*' filter='?yui_js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

Plutôt que d'ajouter le filtre à la balise asset, vous pouvez aussi l'activer de façon globale en ajoutant l'attribut apply-to à la configuration du filtre, par exemple apply_to: "\.js$" pour le filtre yui_js. Pour que le filtre ne s'applique qu'en production, ajoutez le au fichier config_prod au lieu du fichier de configuration commun. Pour plus de détails sur comment appliquer des filtres en fonction des extensions de fichiers, lisez Filtrer en se basant sur les extensions.

PDF brought to you by

(31)

Listing 12-1

Listing 12-2

Chapter 12

Comment utiliser Assetic et les fonctions Twig

pour optimiser les images

Parmi ses nombreux filtres, Assetic possède quatre filtres qui peuvent être utilisés pour optimiser les images à la volée. Cela vous permet de tirer profit de tailles de fichiers réduites sans utiliser d'éditeur d'image pour réduire chaque image. Les résultats sont mis en cache et peuvent être réutilisés en production pour qu'il n'y ait pas d'impact sur les performances pour vos utilisateurs finaux.

Utiliser Jpegoptim

Jpegoptim1est un utilitaire pour optimiser les fichiers JPEG.Pour l'utiliser avec Assetic, ajoutez le bout de code suivant à votre configuration Assetic :

1 2 3 4 5 # app/config/config.yml assetic: filters: jpegoptim: bin: path/to/jpegoptim

Notez que pour utiliser jpegoptim, il faut qu'il soit déjà installé sur votre système. L'option bin pointe vers le fichier binaire compilé.

Il peut maintenant être utilisé dans un template : 1

2 3

{% image '@AcmeFooBundle/Resources/public/images/example.jpg' filter='jpegoptim' output='/images/example.jpg'

%}

1. http://www.kokkonen.net/tjko/projects.html PDF brought to you by

(32)

Listing 12-3 Listing 12-4 Listing 12-5 Listing 12-6 Listing 12-7 4 5

<img src="{{ asset_url }}" alt="Example"/>

{% endimage %}

Supprimer toutes les données EXIF

Par défaut, appliquer ce filtre ne supprime que certaines meta-informations du fichier. Les données EXIF et les commentaires ne sont pas supprimés, mais vous pouvez les supprimer en utilisant l'option strip_all : 1 2 3 4 5 6 # app/config/config.yml assetic: filters: jpegoptim: bin: path/to/jpegoptim strip_all: true

Réduire la qualité maximum

Le niveau de qualité du JPEG n'est pas modifié par défaut. Vous pouvez réduire un peu la taille des images en définissant un niveau de qualité maximum plus bas que le niveau actuel. Cela se fera évidemment au détriment de la qualité de l'image :

1 2 3 4 5 6 # app/config/config.yml assetic: filters: jpegoptim: bin: path/to/jpegoptim max: 70

Fonctions Twig : syntaxe courte

Si vous utilisez Twig, il est possible de faire tout ceci avec une syntaxe raccourcie en activant et en utilisant les fonctions spéciales Twig. Commencez par ajouter la configuration suivante :

1 2 3 4 5 6 7 8 # app/config/config.yml assetic: filters: jpegoptim: bin: path/to/jpegoptim twig: functions: jpegoptim: ~

Le template Twig peut maintenant être modifié comme suit : 1

2

<img src="{{ jpegoptim('@AcmeFooBundle/Resources/public/images/example.jpg') }}" alt="Example"/>

Vous pouvez spécifier le répertoire cible dans la configuration de la manière suivante :

PDF brought to you by

(33)

1 2 3 4 5 6 7 8 # app/config/config.yml assetic: filters: jpegoptim: bin: path/to/jpegoptim twig: functions:

jpegoptim: { output: images/*.jpg }

PDF brought to you by

(34)

Listing 13-1

Listing 13-2

Chapter 13

Comment appliquer un filtre Assetic à une

extension de fichier spécifique

Les filtres Assetic peuvent être appliqués à des fichiers individuels, à des groupes de fichiers ou même, comme vous allez le voir ici, à des fichiers qui ont une extension spécifique. Pour vous montrer comment gérer chaque cas, supposons que vous ayez le filtre Assetic CoffeeScript qui compile les fichiers CoffeeScript en JavaScript.

La configuration principale contient juste les chemins vers coffee et node. Leurs valeurs respectives par défaut sont /usr/bin/coffee et /usr/bin/node:

1 2 3 4 5 6 # app/config/config.yml assetic: filters: coffee: bin: /usr/bin/coffee node: /usr/bin/node

Filtrer un fichier unique

Vous pouvez maintenant compiler un fichier unique CoffeeScript en JavaScript depuis vos templates : 1

2 3

{% javascripts '@AcmeFooBundle/Resources/public/js/example.coffee' filter='coffee'%}

<script src="{{ asset_url }}" type="text/javascript"></script>

{% endjavascripts %}

C'est tout ce dont vous avez besoin pour compiler ce fichier CoffeeScript et le servir comme JavaScript compilé.

PDF brought to you by

(35)

Listing 13-3

Listing 13-4

Listing 13-5

Filtrer des fichiers multiples

Vous pouvez aussi combiner plusieurs fichiers CoffeeScript en un unique fichier en sortie : 1 2 3 4 5 6 {% javascripts '@AcmeFooBundle/Resources/public/js/example.coffee' '@AcmeFooBundle/Resources/public/js/another.coffee' filter='coffee' %}

<script src="{{ asset_url }}" type="text/javascript"></script>

{% endjavascripts %}

Les deux fichiers seront maintenant délivrés comme un unique fichier compilé en JavaScript.

Filtrer en se basant sur les extensions

Un des plus grands avantages d'Assetic est de pouvoir réduire le nombre de fichiers de ressources pour réduire le nombre de requêtes HTTP. Dans le but d'en tirer le plus grand avantage possible, il pourrait être intéressant de combiner tous vos fichiers CoffeeScript et JavaScript ensembles puisqu'ils seront finalement délivrés comme JavaScript. Malheureusement, se contenter d'ajouter les fichiers JavaScript aux fichiers à combiner ne fonctionnera pas car le JavaScript ne passera pas la compilation CoffeeScript. Ce problème peut être évité en ajoutant l'option apply_to à la configuration, ce qui vous permettra de spécifier qu'un filtre devra toujours être appliqué à une extension de fichier particulière. Dans ce cas, vous pouvez spécifier que le filtre Coffee s'applique à tous les fichiers .coffee :

# app/config/config.yml assetic: filters: coffee: bin: /usr/bin/coffee node: /usr/bin/node apply_to: "\.coffee$"

Avec cela, vous n'avez plus besoin de spécifier le filtre coffee dans le template. Vous pouvez aussi lister les fichiers JavaScript classique, chacun d'eux sera combiné et délivré en un unique fichier JavaScript (avec les fichiers .coffee seulement qui passeront à travers le filtre CoffeeScript) :

1 2 3 4 5 6 {% javascripts '@AcmeFooBundle/Resources/public/js/example.coffee' '@AcmeFooBundle/Resources/public/js/another.coffee' '@AcmeFooBundle/Resources/public/js/regular.js' %}

<script src="{{ asset_url }}" type="text/javascript"></script>

{% endjavascripts %}

PDF brought to you by

(36)

Listing 14-1

Chapter 14

Comment gérer les uploads de fichier avec

Doctrine

Gérer les uploads de fichier avec les entités Doctrine n'est en rien différent de gérer n'importe quel autre upload. En d'autres termes, vous êtes libre de déplacer le fichier via votre contrôleur après avoir géré la soumission du formulaire. Pour voir des exemples, référez-vous à la page de référence du type fichier. Si vous le choisissez, vous pouvez aussi intégrer l'upload de fichier dans le cycle de vie de votre entité (c-a-d création, mise à jour et suppression). Dans ce cas, lorsque votre entité est créée, mise à jour et supprimée de Doctrine, les processus d'upload et de suppression du fichier se feront de manière automatique (sans avoir besoin de faire quoi que ce soit dans votre contrôleur).

Pour que cela fonctionne, vous allez avoir besoin de prendre en compte un certain nombre de détails qui vont être couverts dans cet article du Cookbook.

Installation basique

Tout d'abord, créez une classe Entité Doctrine simple avec laquelle nous allons travailler: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // src/Acme/DemoBundle/Entity/Document.php namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity */ class Document { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") PDF brought to you by

(37)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 */ public $id; /** * @ORM\Column(type="string", length=255) * @Assert\NotBlank */ public $name; /**

* @ORM\Column(type="string", length=255, nullable=true) */

public $path;

public function getAbsolutePath() {

return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path; }

public function getWebPath() {

return null === $this->path ? null : $this->getUploadDir().'/'.$this->path; }

protected function getUploadRootDir() {

// le chemin absolu du répertoire où les documents uploadés doivent être sauvegardés

return __DIR__.'/../../../../web/'.$this->getUploadDir(); }

protected function getUploadDir() {

// on se débarrasse de « __DIR__ » afin de ne pas avoir de problème lorsqu'on affiche

// le document/image dans la vue. return 'uploads/documents'; }

}

L'entité Document a un nom et est associée à un fichier. La propriété path stocke le chemin relatif du fichier et est persistée dans la base de données. La méthode getAbsolutePath() est un moyen pratique de retourner le chemin absolu du fichier alors que la méthode getWebPath() permet de retourner le chemin web, qui lui peut être utilisé dans un template pour ajouter un lien vers le fichier uploadé.

Si vous ne l'avez pas déjà fait, vous devriez probablement lire la documentation du type fichier en premier afin de comprendre comment le processus de base de l'upload fonctionne.

Si vous utilisez les annotations pour spécifier vos régles de validation (comme montré dans cet exemple), assurez-vous d'avoir activé la validation via les annotations (voir configuration de la validation).

Pour gérer l'upload de fichier dans le formulaire, utilisez un champ « virtuel » file. Par exemple, si vous construisez votre formulaire directement dans un contrôleur, cela ressemblerait à quelque chose comme ça:

PDF brought to you by

(38)

Listing 14-2 Listing 14-3 Listing 14-4 1 2 3 4 5 6 7 8 9 10 11

public function uploadAction() {

// ...

$form = $this->createFormBuilder($document) ->add('name')

->add('file') ->getForm(); // ...

}

Ensuite, créez cette propriété dans votre classe Document et ajoutez quelques règles de validation: 1 2 3 4 5 6 7 8 9 10 11 12 // src/Acme/DemoBundle/Entity/Document.php // ... class Document { /** * @Assert\File(maxSize="6000000") */ public $file; // ... }

Comme vous utilisez la contrainte File, Symfony2 va automatiquement deviner que le champ du formulaire est un champ d'upload de fichier. C'est pourquoi vous n'avez pas eu à le spécifier explicitement lors de la création du formulaire ci-dessus (->add('file')).

Le contrôleur suivant vous montre comment gérer le processus en entier: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 use Acme\DemoBundle\Entity\Document; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; // ... /** * @Template() */

public function uploadAction() {

$document = new Document();

$form = $this->createFormBuilder($document) ->add('name')

->add('file') ->getForm() ;

if ($this->getRequest()->isMethod('POST')) { $form->bind($this->getRequest()); if ($form->isValid()) {

$em = $this->getDoctrine()->getManager(); $em->persist($document);

PDF brought to you by

(39)

Listing 14-5 Listing 14-6 Listing 14-7 23 24 25 26 27 28 29 30 $em->flush();

$this->redirect($this->generateUrl(...)); }

}

return array('form' => $form->createView()); }

Lorsque vous écrivez le template, n'oubliez pas de spécifier l'attribut enctype : <h1>Upload File</h1>

<form action="#" method="post" {{ form_enctype(form) }}> {{ form_widget(form) }}

<input type="submit" value="Upload Document" /> </form>

Le contrôleur précédent va automatiquement persister l'entité Document avec le nom soumis, mais elle ne va rien faire à propos du fichier et la propriété path sera vide.

Une manière facile de gérer l'upload de fichier est de le déplacer juste avant que l'entité soit persistée et ainsi spécifier la propriété path en conséquence. Commencez par appeler une nouvelle méthode upload() sur la classe Document que vous allez créer dans un moment pour gérer l'upload de fichier:

1 2 3 4 5 6 7 8 9 10 if ($form->isValid()) {

$em = $this->getDoctrine()->getManager(); $document->upload();

$em->persist($document); $em->flush();

$this->redirect(...); }

La méthode upload() va tirer parti de l'objetUploadedFile1, qui correspond à ce qui est retourné après qu'un champ file ait été soumis:

1 2 3 4 5 6 7 8 9 10 11 12 13

public function upload() {

// la propriété « file » peut être vide si le champ n'est pas requis if (null === $this->file) {

return; }

// utilisez le nom de fichier original ici mais // vous devriez « l'assainir » pour au moins éviter // quelconques problèmes de sécurité

// la méthode « move » prend comme arguments le répertoire cible et // le nom de fichier cible où le fichier doit être déplacé

1. http://api.symfony.com/2.1/Symfony/Component/HttpFoundation/File/UploadedFile.html PDF brought to you by

(40)

Listing 14-8 Listing 14-9 14 15 16 17 18 19 20 21 22

$this->file->move($this->getUploadRootDir(), $this->file->getClientOriginalName()); // définit la propriété « path » comme étant le nom de fichier où vous

// avez stocké le fichier

$this->path = $this->file->getClientOriginalName();

// « nettoie » la propriété « file » comme vous n'en aurez plus besoin $this->file = null;

}

Utiliser les callbacks du « cycle de vie » (lifecycle)

Même si cette implémentation fonctionne, elle souffre d'un défaut majeur : que se passe-t-il s'il y a un problème lorsque l'entité est persistée ? Le fichier serait déjà déplacé vers son emplacement final même si la propriété path de l'entité n'a pas été persistée correctement.

Pour éviter ces problèmes, vous devriez changer l'implémentation afin que les opérations sur la base de données et le déplacement du fichier deviennent atomiques : s'il y a un problème en persistant l'entité ou si le fichier ne peut pas être déplacé, alors rien ne devrait se passer.

Pour faire cela, vous devez déplacer le fichier aussitôt que Doctrine persiste l'entité dans la base de donnés. Ceci peut être accompli en s'interférant dans le cycle de vie de l'entité via un callback:

1 2 3 4 5 6 7 /** * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Document { }

Ensuite, réfactorisez la classe Document pour tirer parti de ces callbacks: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 use Symfony\Component\HttpFoundation\File\UploadedFile; /** * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Document { /** * @ORM\PrePersist() * @ORM\PreUpdate() */

public function preUpload() {

if (null !== $this->file) {

// faites ce que vous voulez pour générer un nom unique

$this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension(); }

} /**

* @ORM\PostPersist()

PDF brought to you by

Références

Documents relatifs

La  description  détaillée  du  protocole  de  recherche,  dans  le  cadre  de  cahiers  de  laboratoire‐ou  de  tout  autre  support, 

Pour importer un fichier qui a été enregistré localement sur votre machine (par exemple un fichier texte créé avec MS Word), il suffit de cliquer sur ‘NOUVEAU’, puis ‘Importer

• On peut imaginer que le projet permette à Sofiane de s’approprier les notions en lien avec sa question de grand oral :. o Critères de choix

Gestion du tag Public : tout fichier avec ce tag doit pouvoir ˆ etre vu par les autres utilisateurs sur le mˆ eme r´ eseau : un ls Public devra donner la liste des fichiers ´

Au fil du temps, j’ai ainsi compris qu’être auxiliaire de recherche attitrée à la coordination d’une collecte de données de recherche-action, c’est faire respecter un

Avec l’utilisation des scripts de lancement, comme les versions des exécutables prisent par défaut sont soit OK soit BETA, le développeur ou tout autre personne, qui désire utiliser

Démarche d’amélioration progressive de la qualité sanitaire des logements et cela avec la contribution des occupants. Un nouveau métier hybride, ultime brique

● Transformer GitTravail en dépôt Git, inclure dans le dépôt hello.c, créer un commit, puis un clone sur GitHub, contrôler systématiquement l’état du dépot. ●