• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Symfony2: 30 astuces et bonnes pratiques
 

Symfony2: 30 astuces et bonnes pratiques

on

  • 63,048 views

Avec cette nouvelle version de votre framework préféré, de nouvelles fonctionnalités et de nouveaux usages sont apparus. Vous vous demandez comment structurer vos bundles? Comment organiser votre ...

Avec cette nouvelle version de votre framework préféré, de nouvelles fonctionnalités et de nouveaux usages sont apparus. Vous vous demandez comment structurer vos bundles? Comment organiser votre code source? Comment utiliser correctement l'injecteur de dépendance? Venez découvrir au cours de cette session les bonnes pratiques, et quelques astuces, qui vous aiderons dans la réalisation de vos projets avec Symfony2.

Statistics

Views

Total Views
63,048
Views on SlideShare
53,533
Embed Views
9,515

Actions

Likes
31
Downloads
981
Comments
2

36 Embeds 9,515

http://www.lafermeduweb.net 2835
http://www.sylvaindeloux.com 2337
http://www.developpez.net 1502
http://www.willdurand.fr 718
http://php.developpez.com 590
http://www.symfony.es 353
http://quandonapasdetete.wordpress.com 315
http://blogdwich.fr 153
http://willdurand.fr 147
http://veille.itnetwork.fr 109
http://www.sfexception.com 85
http://www.symfomany.com 68
http://pocky.github.com 62
http://web.developpez.com 50
http://espacepro.click-call.com 47
http://symfony.es 34
http://feeds.feedburner.com 29
http://www.emmanuelpereira.com 15
http://www.pearltrees.com 11
http://www.linkedin.com 11
http://webcache.googleusercontent.com 10
http://pocky.github.io 7
http://sylvaindeloux.com 5
http://www.softwarelibre.net 4
http://a0.twimg.com 3
http://jeteste.phpfogapp.com 2
http://static.slidesharecdn.com 2
https://quandonapasdetete.wordpress.com 2
http://translate.googleusercontent.com 2
http://feedproxy.google.com 1
http://m.lafermeduweb.net 1
https://twitter.com 1
https://si0.twimg.com 1
http://rss.ericquetto.com 1
http://twitter.com 1
http://localhost 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

12 of 2 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Une remarque sur le choix du XML, par rapport au YAML surtout :
    - Beaucoup, beaucoup plus verbeux, il faut être réaliste
    - Bien MOINS simple à comprendre pour un humain normalement constitué (hors geeks absolus à parser XML intégré dans l'oeil)
    - L'autocomplétion n'est pas moins gérable en YAML qu'en XML (au contraire), il faut juste que les éditeurs s'y mettent.

    Mais bonne présentation en tous cas.
    Are you sure you want to
    Your message goes here
    Processing…
  • My Dearest,
    my name is miss favour yak,l read your profile today at (www.slideshare.net)
    and i choosed you as the only one whom i can give my heart as far as love is concern ensuring i bring joy and happiness into your door
    step.lf you are interested in me and want to know more about me and to
    view my pictures,you can contact me
    (favour_buba34@yahoo.co.uk) My dear i want you to understand that there is
    no age,race,colour and religion bar when it comes to true love.only
    what is important is pure and devoted relationship.Hoping to hear from
    you as soon as possible.Thank you
    Miss favour
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Symfony2: 30 astuces et bonnes pratiques Symfony2: 30 astuces et bonnes pratiques Presentation Transcript

    • Symfony2: 30 astuces et bonnes pratiques
    • Noel GUILBERT • Développeur Symfony depuis 2005 • Consultant et formateur à SensioLabs • http://www.noelguilbert.com • http://twitter.com/noelguilbert
    • Avant propos • La version actuelle est en cours de développement • Une version stable est prévue pour bientôt • Les éléments présenté durant cette session peuvent changer
    • RappelLes bonnes pratiques que vous avez appris avec symfony 1 sont bienévidemment toujours dactualité: • Pas de logique métier dans les templates, ni dans les contrôleurs : uniquement dans les classes métier • Gérer la présentation dans les vues : pas dans les contrôleurs ni les classes métier • Ne dupliquez pas de code • Ne modifiez pas directement les classes du framework • ...
    • Here we Go !30 astuces et bonnes pratiques à propos de Symfony2 • Par où commencer ? • Comment organiser votre code ? • Quel moteur de templates choisir ? • Configuration • Gestion des erreurs • Templating • Comment utiliser linjecteur de dépendances ? • Profiling • Debugging • Sécurité • Performances
    • 1) Par où commencer?
    • Par où commencer ? • Documentation: http://docs.symfony-reloaded.org/master/ ◦ Quick Tour: 1h pour prendre en main le framework ◦ Flat PHP application to Symfony2: un autre tutorial pour prendre en main le framework ◦ Guides: http://docs.symfony-reloaded.org/master/guides ◦ Cookbook: http://docs.symfony-reloaded.org/master/cookbook • Sandbox: version prépackagée dune application Symfony2 ◦ Pour le moment, cest la seule méthode recommandée pour démarrer un projet
    • 2) Organisez vos projets!
    • Organisation des projetsProjets • Avec Symfony2, aucune structure nest imposée • La sandbox est une structure possible, respectant les bonnes pratiques • Si vous voulez que vos projets soit facilement repris en main par différents développeurs, gardez le modèle de la sandbox
    • Organisation des applicationsLes applications • Avec Symfony2, vous aurez généralement besoin que dune seule application: ◦ Le système de sécurité permet de cloisonner efficacement chaque fonctionnalité (backend/frontend) ◦ Les classes et services sont chargés uniquement si vous les utilisez: pas dimpact sur les performances
    • Multi applications • Vous pouvez avoir besoin de plusieurs applications: ◦ Projet avec beaucoup de fonctionnalités, et avec un besoin cloisonnement ◦ Séparation importante entre les différentes fonctionnalités • Généralement, vous avez surtout besoin de créer un nouveau projet
    • Organisation en multi-applicationsExemple de projet avec plusieurs applications /application1/ Application1Kernel.php ... /application2/ Application2Kernel.php ... /web/ application1.php application2.php ...
    • Organisation des bundlesLes bundles • Organisez vos bundles en briques logicielles: chaque bundle est responsable dune fonctionnalité: ◦ ForumBundle ◦ BlogBundle ◦ UserBundle ◦ ShopBundle src/Sensio/ Bundle/ UserBundle/ Controller/ UserController.php ShopBundle/ Controller/ OrderController.php
    • 3. Isolez vos classes métiers
    • Isolez vos classes métiersProblématique • Souvent, vous avez des classes qui sont réutilisées dans plusieurs bundles • Ces classes peuvent même être utilisées dans des projets nutilisant pas Symfony2Solution • Les bundles sont uniquement des liens entre votre code métier et le framework • Vous pouvez donc avoir des classes en dehors de vos bundles • Cest le choix darchitecture qui a été fait pour le framework: Bundles vs Components
    • Séparez vos classes métiers desbundlesExemple de structure avec une séparation des classes métiers et desbundles src/Sensio/ Bundle/ UserBundle/ OrderBundle/ Business/ <--------- Classes metiers Form/ User.php Validator/ Order.php Entity/ <--------- Entites Doctrine2 User.php
    • Séparez vos classes métiers desbundlesGrâce à lautoloading, vous pouvez très simplement charger des classes qui ne sont pas dans un bundle. <?php use SymfonyComponentClassLoaderUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( Sensio => __DIR__./../src, )); $loader->register(); # in your application new SensioBusinessFormUser();
    • Spécificité pour les entitésDoctrine2Déclarez les mappingsIl faut indiquer à Doctrine2 où sont les entités, lorsquelles ne sont pas dans un bundle: # app/config/config.yml orm: auto_generate_proxy_classes: %kernel.debug% mappings: Sensio: type: annotation prefix: Sensio dir: %kernel.root_dir%/../src/Sensio/Entity
    • 4: Utilisez votre namespace
    • Utilisez votre propre namespace Gérez votre propre namespace: Vos projets doivent avoir leurs propre namespaces: • nutilisez pas le namespace Sensio de la sandbox! ◦ Sensio ◦ YourCompany ◦ MyProject <?php namespace Sensio; class Product { /* ... */ }
    • 5: Bibliothèque externes
    • Bibliothèques externes • Par défaut, la sandbox est fournie avec toutes les bibliothèques externe quelle supporte: ◦ Symfony2 ◦ Twig ◦ Doctrine ◦ SwiftMailer ◦ Assetic • Retirez les bibliothèques que vous nutilisez pas: ◦ Supprimez les répertoires correspondants ◦ Retirez les de la configuration de lautoloader ◦ Désactivez les bundles associés
    • 6: Ne divulgez plus vos mots de passes
    • Ne divulgez plus vos mots de passes Utilisez des variables denvironnement • Vous pouvez définir des variables denvironnement spécifiques pour vos projets Symfony2: ◦ Les variables doivent être préfixées par SYMFONY_ _ ◦ Vous pouvez ensuite utiliser ces paramètres naturellement dans vos fichiers de configuration
    • Ne divulgez plus vos mots de passes Configuration des variables denvironnement depuis un VirtualHost # VirtualHost configuration <VirtualHost *:80> Servername www.domain.tld # ... SetEnv SYMFONY__DATABASE_USERNAME "sflive" SetEnv SYMFONY__DATABASE_PASSWORD "s3cr3t" </VirtualHost> # Application configuration: app/config/config.yml doctrine: dbal: username: %database_username% password: %database_password%
    • 7: Configuration: le format INI
    • Le format INIGénéralement, nutilisez pas le format INI pour vos projets: • La syntaxe est limité • Pas de validation
    • Le format INI Le format INI peut être utile dans certains cas Si vous souhaitez fournir une application paramétrable à des profils peu techniques, vous pouvez utiliser le format INI. ; blog.ini [parameters] blog.admin.email = noelguilbert@gmail.com blog.admin.name = Noël Importez ce fichier dans la configuration de votre bundle: <container> <imports> <import resource="blog.ini" /> </imports> <services id="blog.notification.email" class="SensioBlogBundleNotificationEmail"> <argument key="admin_email">%blog.admin.email%</argument> <argument key="admin_name">%blog.admin.name%</argument> </services> </container>
    • 8: Utilisez Twig
    • Utilisez Twig • Deux moteurs de templates sont disponibles par défaut avec Symfony2: ◦ PHP ◦ Twig • Twig est le moteur de template recommandé : ◦ Protection XSS ◦ Mode sandbox ◦ Limite la logique métier dans les templates ◦ Utilisable très facilement par les intégrateurs HTML
    • 9: Surchargez les pages derreurs
    • Surcharge des pages derreursPlusieurs solutions sont à votre disposition: • Surcharger uniquement les templates • Surcharger les contrôleurs • Créer un service pour surcharger le comportement du framework
    • Surcharge des pages derreurs • Surchargez les templates: ◦ app/view/FrameworkBundle/error.html.twig ◦ app/view/FrameworkBundle/error.xml.twig ◦ app/view/FrameworkBundle/error.json.twig <!-- app/view/FrameworkBundle/error.html.twig --> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h1>Oops! An Error Occurred</h1> <h2>The server returned a "{{ status_code }} {{ status_text }}".</h2> <div> Something is broken. Please e-mail us at [email] and let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused. </div> </body> </html>
    • Surcharge des pages derreurs • Par défaut, les exceptions sont récupérées par un controller. • Vous pouvez utiliser un autre contrôleur # app/config/config.yml framework: exception_controller: SensioHelloBundleControllerErrorController • Votre contrôleur doit implémenter une méthode showAction <?php namespace SensioHelloBundleController; class ErrorController extends ContainerAware { public function showAction(FlattenException $exception) { // do whatever you want here return new Response(/* ... */); } }
    • Surcharge des pages derreurs • Si vous voulez complètement surcharger le mécanisme dexception de symfony, vous pouvez utiliser un service • Ce service doit écouter lévènement core.exception
    • Surcharge des pages derreursDéclaration du service <service id="sensio.error_handle" class="SensioErrorExceptionHandler"> <tag name="kernel.listener" event="core.exception" method="handleException" priority="-128" /> </service> Implémentation du service <?php namespace SensioError; class ExceptionHandler { public function handleException(EventInterface $event) { $exception = $event->get(exception); // do whatever you want here return new Response(/* ... */); } }
    • 10) Contrôleurs
    • Contrôleurs Les contrôleurs ne doivent pas hériter de la classe Controller du FrameworkBundle. <?php namespace HelloBundleController; use SymfonyBundleFrameworkBundleControllerController; class BadController extends Controller { // your code here }
    • ContrôleursPourquoi ce nest pas conseillé: • Les méthodes fournies par cette classe ne sont que des raccourcis • Surtout utile pour débuter avec le framework • Cette dépendance nest pas obligatoire • Loverhead ajouté napporte aucun bénéfice
    • Contrôleurs Ce contrôleur est correct: <?php # Sensio/HelloBundle/Controller/Controller.php namespace SensioHelloBundle; class SimplestController { /** * @extra:Route("/hello") */ public function hello() { return new Response(Hello World); } }
    • Contrôleurs Oui, les contrôleurs peuvent être de simples objets PHP Avantages: Inconvénients: • Aucune dépendance • Aucun moyen daccéder aux différentes fonctionnalités du framework: request, • Pas doverhead entity_manager, etc. • Très facile à comprendre
    • Contrôleurs Solution 1: Hériter de ContainerAware <?php namespace HelloBundleController; use SymfonyComponentDependencyInjectionContainerAware class GoodController extends ContainerAware { public function indexAction() { $em = $this->container->get(doctrine.orm.entity_manager); } } Avantages: • Plus de dépendances vers Controller • Les mêmes fonctionnalités sont disponibles • Pas doverhead
    • Contrôleurs Solution 2: utiliser des services en tant que controlleurs Avantages: • Vous contrôlez vos dépendances via linjecteur de dépendances • Vous pouvez tester unitairement vos contrôleurs
    • Contrôleurs Définition dun contrôleur via linjecteur de dépendances • Définition du service <!-- HelloBundle/Resources/controllers.xml --> <service id="better_controller" class="HelloBundleControllerServiceController" /> • Configuration du routing my_route: defaults: { _controller: better_controller:index } • Votre contrôleur est toujours un objet PHP classique <?php namespace HelloBundleController; class ServiceController { public function indexAction() { } }
    • Contrôleurs Exemple: un contrôleur ayant accès aux services suivant: • Le service de templating • Lentity manager Configuration du service: # HelloBundle/Resources/controllers.xml <service id="product_controller" class="HelloBundleControllerProductController"> <argument type="service" id="templating" /> <argument type="doctrine.orm.entity_manager" /> </service>
    • Contrôleurs Implémentation du contrôleur: <?php namespace HelloBundleController; class ProductController { public function __construct(EngineInterface $templating, EntityManager $em) { $this->templating = $templating; $this->em = $em; } public function indexAction() { $products = $this->em->getRepository(HelloBundle:Product)->findAll(); return $this->templating->renderResponse( HelloBundle:Product:list.html.twig, array(products => $products) ); } }
    • 11: Inclusion des assets
    • Inclusions des assets Assets avec Symfony2 • Avec Symfony2, il ny a plus de gestionnaire dassets permettant dajouter les styles css à utiliser • Utilisez plutôt les blocs twig pour gérer vos assets. Dans votre layout de base: {# app/views/base.html.twig #} <html> <head> {%block stylesheets %}{% endblock %} </head> <body> {# ... #} {%block javascripts %}{% endblock %} </body> </html>
    • Inclusions des assets Choisissez les assets à utiliser directement dans vos templates: {# HelloBundle/Resources/views/Default/index.html.twig #} {% block stylesheets %} <link href="{{ assets("bundles/hello/css/styles.css") }}" rel="stylesheet" /> {% endblock %} {% block javascripts %} <script src="{{ assets("bundles/hello/js/script.js") }}" type="text/javascript"></scr {% endblock %}
    • 12: Utilisez les macros Twig
    • Twig: Utilisez les macros Cas dutilisation classique: des boutons html personnalisés Le code HTML correspondant pourrait être le suivant: <a href="#" class="button"> <span> <span> <span> Nice Button </span> </span> </span> </a>
    • Twig: Utilisez les macros Réalisez un macro permettant de réutiliser facilement ce code HTML {# HelloBundle/Resources/views/macro.html.twig #} {% macro button(url, text) %} <a href="{{ url }}" class="button"> <span> <span> <span> {{ text }} </span> </span> </span> </a> {% endmacro %} Réutilisez cette macro dans vos templates: {# HelloBundle/Resources/views/Default/index.html.twig #} {% from "HelloBundle::macro.html.twig" import button %} {{ button("Nice Button!") }}
    • 13: Internationalisation
    • Internationalisation Internationalisez vos projets • Parce que vous ne savez pas comment votre projet va évoluer • Parce que limpact en terme de performances est négligeable • Parce que implémenter linternationalisation après coup vous prendra beaucoup de temps
    • Injection de dépendance
    • 14) Apprenez à lutiliser
    • Linjecteur de dépendance est à la base du framework.Domptez-le, et vous aurez le pouvoir de Symfony2 entre vosmains!
    • Apprenez à utiliser linjecteur dedépendancesRessources sur ce sujet: • http://www.slideshare.net/fabpot • http://fabien.potencier.org/article/13/introduction-to-the-symfony-service-container • http://components.symfony-project.org/dependency-injection/
    • 15) Injection de dépendences: règles de base
    • Règles générales: • Les classes doivent être utilisables sans le conteneur • Seul le conteneur connait les dépendances, et pas linverse • Ce nest pas LA solution à tous vos problèmes
    • 16) Utilisez le format XML
    • Définir vos services Utilisez le format xml pour décrire vos services: • Un peu plus verbeux • Mais beaucoup plus simple à appréhender et à comprendre • Autocomplétion dans les éditeurs XML qui le supporte
    • 17) Injecteur de dépendances:
    • Injecteur de dépendances Quand lutiliser? Linjecteur de dépendances doit être utilisés pour les objets métiers qui ont une portée globale: • request • http kernel • entity manager • caching driver (memcache, apc, ...)
    • 18) Quand NE PAS lutiliser?
    • Injecteur de dépendances Quand ne pas lutiliser ? Linjecteur de dépendances ne doit pas être utilisés dans les cas suivants: • Retrouver une instance dun objet métier (i.e. un produit dans une base de données) • Pour un objet nayant pas une portée globle: un objet métier nétant utilisés que dans un controleur, par exemple
    • 19) Ne pas injecter le container
    • Ne pas injecter le container Il ne faut pas injecter le container dans les objets: • Cela crée une dépendance forte avec le conteneur alors que vous avez rarement la nécessité • Vous ne pourrez plus utiliser vos classes sans le conteneur <?php namespace SensioProduct class Manager { public function __construct($container) { $this->dbh = $container->get(doctrine.dbal.default_connection); } }
    • Injecteur de dépendances Injecter directement le service concerné: <?php namespace SensioProduct class Manager { public function __construct($dbh) { $this->dbh = $dbh; } }
    • 21) Sécurité
    • Sécurité Le module de sécurité est une part très spécifique de la configuration de votre projet Vous y définissez: • Comment retrouver vos utilisateurs • A quelles ressources il peuvent accéder • Comment il peuvent accéder à ces resources La bonne pratique est de définir ces informations dans un fichier spécifique
    • SécuritéExemple: # app/config/security.yml security: encoders: SymfonyComponentSecurityCoreUserUser: sha1 providers: main: users: foo: { password: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, roles: ROLE_USER facebook: true firewalls: main: pattern: /.* http-basic: true logout: true access_control: - { path: /admin, role: ROLE_ADMIN } - { path: /public, role: ROLE_ANONYMOUS } - { path: /.*, role: ROLE_USER }
    • 22) Profiling
    • Profiling:Surveillez vos performances: • nombre de requêtes • temps dexécution • mémoire utilisée
    • Profiling:Surveillez également vos redirections: • Les actions réalisant des redirections font très souvent des dizaines de requêtes • En environnement de développement, Symfony2 intercepte ces redirections pour vous permettre danalyser lexécution
    • 23) Profiling en production
    • Profiling:Il arrive parfois quun problème survienne en production sans quevous soyez capable de comprendre le problème. • Avec symfony 1, une des solutions est dactiver le debug le temps de comprendre ce quil se passe. • Avec Symfony2, vous pouvez activer le profiler en production sans activer laffichage des erreurs. Activer le profiling en production: # app/config/config_prod.yml framework: profiler: { only_exceptions: true }
    • Profiling:Importer un dump
    • 24) Utilisez les annotations
    • Utilisez les annotationsLes annotations permettent de définir des comportements, des éléments de configuration, etc... <?php /** * @orm:Entity */ class User { }Ce format de configuration est très pratique: • Il permet de définir des comportements directement dans les classes concernés • Tout est centralisé: vous navez plus à vous rappeler dans quel fichier tel ou tel comportement est défini
    • 25) FrameworkExtraBundle
    • FrameworkExtraBundleLe bundle FrameworkExtraBundle vous donne accès à davantagesdannotations pour configurer: • Le routing • La ou les méthodes HTTP possible pour une règle de routing (GET, POST, ...) • les templates à utiliser • Le cache HTTP • Convertir des paramètres de requêtes (en entité Doctrine, par ex.)
    • FrameworkExtraBundle Exemple de contrôleur: <?php class AwesomeController extends ContainerAware { /** * @extra:Route("/awesome/controller") * @extra:Method("GET") * @extra:Template("SensioHelloBundle:Default:index.html.twig") * @extra:Cache(maxage=600) */ public function indexAction() { } }
    • PerformancesOptimisez vos performances grâce à Symfony2.
    • 26) Optimisez lautoloading
    • Autoloading • Lun des goulot détranglement classique en PHP est lautoloading. • Les performances exceptionnelles de Symfony2 sexpliquent en partie par des solutions visant à optimiser le chargement des classes du framework • Vous pouvez également profiter de ces améliorations pour vos projets, grâce aux extensions de linjecteur de dépendance. <?php namespace SensioUserBundleDependencyInjection; class UserExtension extends Extension { public function load(array $config, ContainerBuilder $container) { /* ... */ $this->addClassesToCompile(array( SensioUserBundleModelUser )); } }
    • AutoloadingVos classes sont "compilées" dans un fichier unique: <?php # app/cache/prod/classes.php /* ... */ namespace SensioUserBundleModel { class User { /* your code */ } } Avantages: • Plus besoin de passer par lautoloader: vos classes sont forcéments chargées à chaque requête HTTP • Moins daccès disque pour charger les classes • Ce fichier est mis en cache par les gestionnaire dopcode (APC, EAccelerator, XCache)
    • AutoloadingLarme secrète de Symfony2 est à votre portée! • Attention : cette fonctionnalité peut avoir leffet inverse si elle est trop utilisée
    • 27) Cache Warmer
    • Cache WarmerLa commande cache:warmup permet de pré-compiler tous les fichiers nécessaire en cache: • Templates • Injecteur de dépendance • Routing • Autoloading $> php symfony cache:warmup
    • 28) Doctrine: vérifier la configuration
    • Doctrine: vérifier la configurationUne commande dédiée vous permet de vérifier la bonneconfiguration de Doctrine2 dans Symfony2: $> php app/console doctrine:ensure-production-settings
    • 29) Routing
    • Routing: Utilisez le router Apache Configurez Symfony pour utiliser le matcher Apache: # app/config/config.yml framework: router: { matcher: apache } Exportez vos règles de routing en RewriteRules: $> php app/console router:dump > rewrite.conf
    • 30) Assets
    • AssetsUtilisez assetic pour de meilleures performances: {# HelloBundle/Resources/views/Default/index.html.twig #} {% block stylesheets %} {% stylesheet filter="yui_css", output="/css/main.css", "@HelloBundle/Resources/public/css/reset.css" "@HelloBundle/Resources/public/css/styles.css" %} <link href="{{ asset_url }}" rel="stylesheet" /> {% endstylesheet %} {% endblock %} {% block javascripts %} {% javascript filter="closure", output="/js/script.js", "@HelloBundle/Resources/public/js/jquery.js" "@HelloBundle/Resources/public/js/hello.js" %} <script src="{{ asset_url }}" type="text/javascript"></script> {% endjavascript %} {% endblock %}
    • Questions ? Merci de votre attention!