Anúncio
Anúncio

Mais conteúdo relacionado

Anúncio

Similar a Introduction à Symfony2(20)

Anúncio

Introduction à Symfony2

  1. Introduction à Symfony2
  2. •  Hugo HAMON (@hhamon) •  Responsable des formations Sensio Labs •  Secrétaire Général de l’AFUP •  10 ans de développement web dont 8 avec PHP •  Coauteur d’ouvrages Eyrolles •  Apprendre-PHP.com / HugoHamon.com
  3. Qu’est-ce que Symfony2 ?
  4. Un framework web
  5. PHP 5.3
  6. Objectifs ?
  7. •  Développer plus vite et mieux •  Faciliter le travail en équipe •  Pérenniser les applications •  Simpli er la maintenance et les évolutions •  Se concentrer sur la logique métier •  Ne pas réinventer la roue !
  8. Symfony2 intègre les meilleurs outils Open-Source PHP
  9. Symfony Components Dependency Injection Container Request Handler Event Dispatcher Console YAML …
  10. Zend Framework PHPUnit Doctrine2 Swift Mailer Twig
  11. Différences avec symfony 1.x ?
  12. Même philosophie, Même outillage, Moins de concepts, Plus de exibilité Performances accrues 
  13. Où en est-on aujourd’hui ?
  14. •  Version ALPHA •  Briques logicielles manquantes •  Documentation incomplète •  L’API peut encore beaucoup évoluer •  Version stable repoussée à début Mars 2011
  15. Je veux tester Symfony2 ! git clone http://github.com/symfony/symfony-sandbox.git http://www.symfony-reloaded.org
  16. Je veux développer un projet client maintenant avec Symfony2 ? A ta place, je ne ferai pas ça…
  17. Quel outillage ?
  18. •  Sécurité •  Extensibilité •  Architecture MVC •  I18N & L10N •  URLs élégantes •  Authenti cation et ACLs •  DBAL & ORM •  Tests unitaires •  Outils de débogage •  Tests fonctionnels •  Formulaires •  Cache •  Con guration •  Admin Generator
  19. Architecture d’un projet Symfony2
  20. Un Projet Symfony2 est un répertoire qui se compose d’une Application, d’un jeu de Bundles et de librairies.
  21. . |-- LICENSE |-- README |-- app/ | |-- AppCache.php | |-- AppKernel.php Répertoire  de  l’Applica0on   | |-- cache/ | |-- config/ | |-- console | |-- logs/ | |-- phpunit.xml.dist | `-- views/ |-- bin/ | |-- create_sandbox.sh | |-- install_vendors.sh | |-- prepare_vendors.sh | `-- update_vendors.sh |-- src/ | |-- Application/ | |-- Bundle/ Code  de  l’Applica0on  +     | |-- autoload.php Bundles  +     | `-- vendor/ Librairies  externes   `-- web/ |-- bundles/ |-- check.php |-- index.php Dossier  public   `-- index_dev.php
  22. Une Application est un répertoire qui contient la con guration pour un jeu de Bundles donné.
  23. Structure d’une application app/ |-- AppCache.php |-- AppKernel.php The  AppKernel  class  is  the   |-- cache/  main  class  of  the  applica0on   |-- config/ | |-- config.yml | |-- config_dev.yml | |-- config_test.yml | |-- routing.yml Configura0on  files   | `-- routing_dev.yml |-- console |-- logs/ | `-- dev.log |-- phpunit.xml.dist Logs  and  applica0on  templates   `-- views/ |-- layout.php
  24. Un Bundle est un ensemble structuré et cohérent de chiers qui implémentent une fonctionnalité (un blog, un forum, …) et qui peut facilement être partagé avec d’autres développeurs.
  25. symfony 1.x => Plugins Symfony 2.x => Bundles
  26. + BlogBundle/ Code  source  du  bundle  :  contrôleurs   |-- Controller/ | `-- BlogController.php modèles,  formulaires…   |-- Entity/ | `-- Post.php |-- Form/ | `-- PostForm.php Le  fichier  BlogBundle.php  est   |-- BlogBundle.php |-- Model/ obligatoire  et  con0ent  la  classe  qui   | `-- PostRepository.php déclare  le  bundle.   |-- Resources/ | |-- config/ | | `-- routing.yml | |-- views/ | | `-- Blog/ Un  bundle  peut  contenir  de  la   | | |-- showPost.php configura0on,  des  templates  et  des   | | `-- listPost.php ressources  web.   | `-- public/ | `-- css/ | `-- blog.css `-- Tests/ Un  bundle  peut  aussi  contenir   `-- Controller/ `-- BlogControllerTest.php des  scripts  de  tests  PHPUnit.  
  27. Sécurité
  28. XSS CSRF SQL Injections
  29. Le dossier web/ du projet est le seul accessible depuis un navigateur web
  30. Routage et URLs
  31. Le système de routage a pour rôle de convertir une URL en une réponse web.
  32. Elles sont propres et élégantes a n d’exposer des informations pertinentes et de masquer l’implémentation technique… http://www.domain.com/blog/2010/09/15/symfony2-rocks
  33. Con guration des URLs en YAML # src/Bundle/BlogBundle/Resources/config/routing.yml post_details: pattern: /blog/:year/:month/:day/:slug defaults: { _controller: BlogBundle:Blog:showPost } Exemple d’URL générée http://www.domain.com/blog/2010/09/15/symfony2-rocks
  34. Association URL et Code ?
  35. # src/Application/HelloBundle/Resources/config/routing.yml hello: pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index } # src/Application/HelloBundle/Controller/HelloController.php namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  36. # src/Application/HelloBundle/Resources/config/routing.yml hello: Nom  du  Bundle   pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index } # src/Application/HelloBundle/Controller/HelloController.php namespace ApplicationHelloBundleController; class HelloController extends Controller Un  dossier  /  namespace   { public function indexAction($name) { // ... } }
  37. # src/Application/HelloBundle/Resources/config/routing.yml hello: Nom  du  contrôleur   pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index } # src/Application/HelloBundle/Controller/HelloController.php namespace ApplicationHelloBundleController; class HelloController extends Controller Une  classe   { public function indexAction($name) { // ... } }
  38. # src/Application/HelloBundle/Resources/config/routing.yml hello: Nom  de  l’ac0on   pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index } # src/Application/HelloBundle/Controller/HelloController.php namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } Une  méthode   }
  39. # src/Application/HelloBundle/Resources/config/routing.yml hello: pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index } # src/Application/HelloBundle/Controller/HelloController.php namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  40. Les paramètres peuvent être passés dans un ordre arbitraire post_details: pattern: /blog/:year/:month/:day/:slug defaults: { _controller: BlogBundle:Blog:showPost } namespace ApplicationBlogBundleController; class BlogController extends Controller { public function showPostAction($slug, $year) { // ... } }
  41. Architecture MVC
  42. •  Séparation du code en trois couches – Logique métier dans le Modèle – Logique applicative dans le Contrôleur – Affichage dans la Vue (templates) •  Modularité et découplage du code •  Maintenance simpli ée sur le code source •  Code testable unitairement et plus robuste
  43. Les actions pour la logique applicative. Elles se situent dans les Contrôleurs.
  44. ๏  Une action est accessible depuis une URL # src/Application/BlogBundle/Resources/config/routing.yml post_show: pattern: /blog/article/:id/show defaults: { _controller: BlogBundle:Blog:show }
  45. # src/Application/BlogBundle/Controller/BlogController.php namespace ApplicationBlogBundleController; use SymfonyBundleFrameworkBundleControllerController; class BlogController extends Controller { public function showAction($id) Paramètres  de  l’url   { // find the article by its id $post = ...; // render the view return $this->render('BlogBundle:Blog:show', array('post' => $post)); } } Template  à  rendre   Variables  du  template  
  46. Les templates constituent la couche de présentation des données, la vue.
  47. ๏  Syntaxe alternative de PHP ๏  Quelques brèves instructions PHP (echo, if, foreach…) ๏  Echappement automatique des variables # src/Application/BlogBundle/Resources/views/Blog/show.php <?php $view->extend('::layout') ?> Layout  de  décora0on   <h2><?php echo $post->getTitle() ?></h2> <p> <?php echo $post->getContent() ?> </p> Variables  échappées  =>  pas  de  XSS  !!!  
  48. Héritage de Vues
  49. # src/Application/HelloBundle/Resources/views/Hello/index.php <?php $view->extend('::layout') ?> Hello <?php echo $name ?>! étend # app/views/layout.php <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> <?php $view['slots']->output('title', 'Hello Application') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
  50. Héritage de Vues layout.php _content Hello Hugo! index.php
  51. # src/Application/HelloBundle/Resources/views/Hello/index.php <?php $view->extend('HelloBundle::layout') ?> Hello <?php echo $name ?>! # src/Application/HelloBundle/Resources/views/layout.php <?php $view->extend('::layout') ?> <h1>Hello Application</h1> <div> <?php $view['slots']->output('_content') ?> </div> # app/views/layout.php <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> <?php $view['slots']->output('title', 'Hello Application') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
  52. Héritage multiple ::layout.php HelloBundle::layout.php _content Hello Hugo! _content index.php
  53. Les Slots sont des fragments dé nis dans un template et affichés dans un layout décorant ce dernier.
  54. # src/Application/HelloBundle/Resources/views/Hello/index.php <?php $view['slots']->set('title', 'Hello World app') ?> # app/views/layout.php <html> <head> <title> <?php $view['slots']->output('title', 'Hello Application') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
  55. Symfony fournit des mécanismes simples pour évaluer et inclure des templates dans un autre # src/Application/HelloBundle/Resources/views/Hello/hello.php Hello <?php echo $name ?>! # Including another template in the current template <?php echo $view->render('HelloBundle:Hello:hello', array('name' => $name)) ?> src/Bundle/HelloBundle/Resources/views/Hello/hello.php  
  56. Symfony offre également un moyen d’inclure le rendu d’une action depuis une vue… # src/Application/HelloBundle/Resources/views/Hello/index.php <?php $view['actions']->output('HelloBundle:Hello:fancy', array( 'name' => $name, 'color' => 'green’ )) ?>
  57. # src/Application/HelloBundle/Controller/HelloController.php class HelloController extends Controller { public function fancyAction($name, $color) { // create some object, based on the $color variable $object = ...; return $this->render('HelloBundle:Hello:fancy', array( 'name' => $name, 'object' => $object )); } // ... }
  58. Les aides de vue sont des objets accessibles depuis les templates et qui permettent de simpli er la logique d’affichage
  59. Générer une URL avec le router helper <a href="<?php echo $view['router']->generate('hello', array( 'name' => 'Thomas')) ?>">Greet Thomas!</a> Inclure des feuilles de style <head> <!-- ... --> <?php $view['stylesheets']->add('css/styles.css') ?> <?php echo $view['stylesheets'] ?> </head>
  60. Inclure des javascripts <head> <!-- ... --> <?php $view['javascripts']->add('js/libraries.js') ?> <?php echo $view['javascripts'] ?> </head> Manipuler des ressource web (images, ash…) <img src="<?php echo $view['assets']->getUrl('images/logo.png') ?>" src=""/> Traduire des chaînes de l’interface <?php echo $view['translator']->trans('Symfony is %what%!', array( '%what%' => 'awesome')) ?>
  61. Con guration
  62. 3 formats de con guration PHP YAML XML
  63. Quel format choisir ? Avantages Inconvénients XML Validation Verbeux Complétion dans les EDIs Long à écrire Facile à analyser YAML Concis Besoin du composant YAML Facile à lire Pas de validation Facile à modi er Pas d’autocomplétion PHP Flexible Pas de validation Plus facile à manipuler
  64. Con guration en YML # app/config/routing.php homepage: pattern: / defaults: { _controller: FrameworkBundle:Default:index } hello: resource: HelloBundle/Resources/config/routing.yml Import  d’une  autre  configura0on  
  65. Con guration en PHP # app/config/routing.php use SymfonyComponentRoutingRouteCollection; use SymfonyComponentRoutingRoute; $collection = new RouteCollection(); $collection->addRoute('homepage', new Route('/', array( '_controller' => 'FrameworkBundle:Default:index', ))); $collection->addCollection( $loader->import("HelloBundle/Resources/config/routing.php") ); Import  d’une  autre  configura0on   return $collection;
  66. Con guration en XML # app/config/routing.xml <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://www.symfony-project.org/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.symfony-project.org/schema/routing http:// www.symfony-project.org/schema/routing/routing-1.0.xsd"> <route id="homepage" pattern="/"> <default key="_controller">FrameworkBundle:Default:index</default> </route> <import resource="HelloBundle/Resources/config/routing.xml" /> </routes> Import  d’une  autre  configura0on  
  67. Import de chiers INI # app/config/config_dev.yml imports: - { resource: config.yml } - { resource: custom.ini} zend.logger: priority: debug path: %kernel.root_dir%/logs/%kernel.environment%.log # app/config/custom.ini [parameters] dice.min = 1 dice.max = 6
  68. Accès à la con guration depuis le code public function diceAction() { // ... $min = (int) $this->container->getParameter('dice.min'); $max = (int) $this->container->getParameter('dice.max'); // ... }
  69. Outils de Débogage
  70. Parce qu’il est important pour un développeur d’identi er rapidement les bogues et les problèmes !!!
  71. Web Debug Toolbar
  72. Logs
  73. Traces d’exception Trace  de  l’excep0on   courrante   Trace  pour  une   InvalidArgumentExcep0on   404  Status  Code  
  74. Afficher  /  masquer  la  trace  d’une   excep0on   Logs  enregistrés   Lien  vers  le  profiler  
  75. Pro ler
  76. Trace  de  l’excep0on   Recherche  dans  les  logs  
  77. Requêtes SQL
  78. Extensibilité
  79. http://www.symfony2bundles.org
  80. Enregistrement de bundles # app/AppKernel.php class AppKernel extends Kernel { // ... public function registerBundles() { $bundles = array( // ... // Register third party bundles new BundleTwitterBundleTwitterBundle(), new BundleForumBundleForumBundle() ); // ... return $bundles; } }
  81. DBAL & ORM Doctrine2
  82. •  Abstraction de base de données relationnelles •  Performance •  Plus de magie •  Manipulation de vrais objets PHP (POPO) •  Génération de code •  Adapteur MongoDB disponible
  83. ๏  Con gurer la connexion BDD en YAML # app/config/config.yml doctrine.dbal: dbname: Blog user: root password: ~ doctrine.orm: ~ ๏  Con gurer la connexion BDD dans Apache // web/.htaccess or in the vhost configuration SetEnv SYMFONY__DOCTRINE__DBAL__USERNAME "root" SetEnv SYMFONY__DOCTRINE__DBAL__PASSWORD "secret"
  84. ๏  Dé nition d’une entité (table) à l’aide d’une classe PHP namespace ApplicationBlogBundleEntity; /** * @Entity(repositoryClass="ApplicationBlogBundleModelBlogPostRepository") * @Table(name="blog_post") */ Annota0ons   class BlogPost { /** * @Id @Column(type="integer") * @GeneratedValue(strategy="IDENTITY") */ protected $id; /** @Column(length=100) */ protected $title; /** @Column(type="text") */ protected $content; }
  85. ๏  Génération de la base de données à partir des classes PHP $ php app/console doctrine:database:create $ php app/console doctrine:schema:create ๏  Chargement des données de test $ php app/console doctrine:data:load
  86. ๏  Les données de test sont écrites en pur PHP # src/Application/BlogBundle/Resources/data/fixtures/doctrine/fixtures.php use ApplicationBlogBundleEntityBlogPost; $post1 = new BlogPost(); $post1->setTitle('My first blog post'); $post1->setContent('Lorem ipsum dolor sit amet...'); $post2 = new BlogPost(); $post2->setTitle('My second blog post'); $post2->setContent('Lorem ipsum dolor sit amet...'); $post3 = new BlogPost(); $post3->setTitle('My third blog post'); $post3->setContent('Lorem ipsum dolor sit amet...');
  87. ๏  Ecrire des requêtes DQL dans un modèle Doctrine # src/Application/BlogBundle/Model/BlogPostRepository.php namespace ApplicationBlogBundleModel; use DoctrineORMEntityRepository; class BlogPostRepository extends EntityRepository { public function getHomepagePosts() { $query = $this->_em->createQuery(' SELECT u FROM BlogBundle:BlogPost u ORDER BY u.id DESC '); return $query->getResult(); } }
  88. ๏  Interroger la base de données à l’aide du Modèle Doctrine # src/Application/BlogBundle/Controller/BlogController.php // ... class BlogController extends Controller { public function indexAction() { $em = $this['doctrine.orm.entity_manager']; $posts = $em->getRepository('BlogBundle:BlogPost') ->getHomepagePosts(); return $this->render('BlogBundle:Blog:index', array( 'posts' => $posts )); } // ... }
  89. Emails Swift Mailer
  90. •  API Orientée Objet Open-Source •  Support des connexions SMTP •  Support des pièces jointes •  Support des formats de mails (text, html…) •  Gestion des les d’attente (spools) •  Facile à con gurer et à étendre avec des plugins
  91. Con gurer Swift Mailer # app/config/config.yml swift.mailer: transport: smtp encryption: ssl auth_mode: login host: smtp.gmail.com username: your_username password: your_password
  92. Envoyer un Email public function indexAction($name) { Récupéra0on  du  service  d’envoi  de  mails   $mailer = $this['mailer']; $message = Swift_Message::newInstance() ->setSubject('Hello Email') ->setFrom('send@example.com') ->setTo('recipient@example.com') ->setBody($this->renderView('HelloBundle:Hello:email', array( 'name' => $name ))); Généra0on  du  corps  du  mail  à  l’aide   d’un  template  et  de  la  méthode   $mailer->send($message); renderView()   return $this->render(...); }
  93. Tests Automatisés PHPUnit
  94. •  Tests Unitaires et Couverture de Code •  Garantir la qualité du code •  Eviter les bugs et les régressions •  Documenter le code •  Industrialiser et professionnaliser les développements
  95. ๏  Exemple de script de tests unitaires dans Symfony2 # src/Application/BlogBundle/Tests/Entity/BlogPostTest.php namespace ApplicationBlogBundleTestsEntity; use ApplicationBlogBundleEntityBlogPost; class BlogPostTest extends PHPUnit_Framework_TestCase { public function testTitleIsSlugifiedOnce() { $slug = 'symfony2-rules-the-world'; $post = new BlogPost(); $post->setTitle('Symfony2 rules the world'); $this->assertEquals($slug, $post->getSlug()); // Slug doesn't change when it's already set $post->setTitle('An other title'); $this->assertEquals($slug, $post->getSlug()); } }
  96. •  Tests fonctionnels •  Simuler des scénarios de navigation •  Simuler un client Web (navigateur) •  Véri er que l’application respecte le cahier des charges
  97. ๏  Exemple de script de tests fonctionnels dans Symfony2 class BlogControllerTest extends WebTestCase { // ... public function testAddComment() { $this->client->followRedirects(); $crawler = $this->client->request('GET', '/'); // Get the first link to a post $link = $crawler->filter('h2.post a')->first()->link(); // Click on the link and check there are two comments $crawler = $this->client->click($link); $this->assertTrue($crawler->filter('.comment')->count() == 2); } }
  98. ๏  Simuler des requêtes GET $crawler = $client->request('GET', '/hello/Fabien'); ๏  Simuler des requêtes POST $client->request('POST', '/submit', array('name' => 'Fabien') ๏  Simuler des uploads de chiers en POST $client->request('POST', '/submit', array('name' => 'Fabien'), array('photo' => '/path/to/photo') );
  99. ๏  Simuler une requête HTTP DELETE avec des entêtes $client->request('DELETE', '/post/12', array(), array(), array( 'PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word' )); ๏  Désactiver / activer les redirections HTTP $client->followRedirects(false); $client->followRedirect(); ๏  Insoler le client dans un processus séparé $client->insulate();
  100. ๏  Naviguer dans l’historique comme dans un navigateur web $client->back(); $client->forward(); $client->reload(); ๏  Réinitialiser le Client $client->restart();
  101. ๏  Parcourir le DOM avec le DOM Crawler // Nodes that match the CSS selector $crawler->filter('h1'); // Nodes that match the XPath expression $crawler->filterXpath('h1'); // Node for the specified index $crawler->eq(1); // First node $crawler->first(); // Last node $crawler->last();
  102. // Siblings $crawler->siblings(); // All following siblings $crawler->nextAll(); // All preceding siblings $crawler->previousAll(); // Parent nodes $crawler->parents(); // Children $crawler->children(); // Nodes for which the callable, a lambda, returns true $crawler->reduce($lambda);
  103. ๏  Extraire des données sur des noeuds // Returns the attribute value for the first node $crawler->attr('class'); // Returns the node value for the first node $crawler->text(); // Extracts an array of attributes for all nodes // (_text returns the node value) $crawler->extract(array('_text', 'href')); // Executes a lambda for each node // and return an array of results $data = $crawler->each(function ($node, $i) { return $node->getAttribute('href'); });
  104. ๏  Simuler des clics sur des liens ou boutons $crawler->selectLink('Click here'); $link = $crawler->link(); $client->click($link); $links = $crawler->links(); ๏  Poster des formulaires // Select the submit button of a form $crawler->selectButton('submit'); // Get a form instance $form = $crawler->form(); // Override the default form values $form = $crawler->form(array( 'name' => 'Fabien', 'like_symfony' => true, ));
  105. Performances
  106. •  PHP 5.3.2 minimum •  “ Cachy framework “ •  Cache HTTP & Proxy cache (ESI) •  Faible consommation mémoire •  Tous les services sont chargés à la demande
  107. // src/Application/BlogBundle/Resources/views/layout.php $view['actions']->output('BlogBundle:Blog:lastComments', array(), array( 'standalone' => false )); If  the  standalone  parameter  is  set   to  false,  Symfony2  will  render  the   HTML  content  
  108. // src/Application/BlogBundle/Resources/views/layout.php $view['actions']->output('BlogBundle:Blog:lastComments', array(), array( 'standalone' => true )); If  the  standalone  parameter  is  set  to   true  and  if  there  is  a  compa0ble  proxy   <esi:include  src="..."  />   cache,  Symfony2  will  render  an  ESI  tag  
  109. Edge Side Includes aka ESI...
  110. Edge Side Includes
  111. Questions ?
  112. Trainings Business Unit trainings@sensio.com Sensio S.A. 92-98, boulevard Victor Hugo 92 115 Clichy Cedex FRANCE Tél. : +33 1 40 99 80 80 www.sensiolabs.com - www.symfony-project.org - trainings.sensiolabs.com
Anúncio