Symfony2 - WebExpo 2010

4,556 views
4,505 views

Published on

Published in: Technology
2 Comments
3 Likes
Statistics
Notes
No Downloads
Views
Total views
4,556
On SlideShare
0
From Embeds
0
Number of Embeds
1,043
Actions
Shares
0
Downloads
60
Comments
2
Likes
3
Embeds 0
No embeds

No notes for slide

Symfony2 - WebExpo 2010

  1. 1. Symfony2 Fabien Potencier
  2. 2. How many of you have already used symfony1?
  3. 3. How many of you have already played with Symfony2?
  4. 4. What is Symfony2?
  5. 5. A set of decoupled and cohesive components
  6. 6. DependencyInjection EventDispatcher HttpFoundation OutputEscaper DomCrawler CssSelector Templating HttpKernel BrowserKit Validator Routing Console Process Finder Form Yaml
  7. 7. git clone git://github.com/symfony/symfony.git
  8. 8. A set of decoupled and cohesive components Autoloading
  9. 9. PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Twig_Node_For > Twig/Node/For.php
  10. 10. SymfonyFoundationKernel Symfony/Foundation/Kernel.php DoctrineDBALDriver Doctrine/DBAL/Driver.php pdependreflectionReflectionSession pdepend/reflection/ReflectionSession.php http://groups.google.com/group/php-standards/web/psr-0-final-proposal  
  11. 11. require_once '.../Symfony/Framework/ UniversalClassLoader.php'; use SymfonyFrameworkUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->register();
  12. 12. $loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', 'pdepend' => '/path/to/reflection/source', )); PHP 5.3 technical interoperability standards
  13. 13. $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); PEAR style
  14. 14. A set of decoupled and cohesive components Process
  15. 15. use SymfonyComponentProcessProcess; $cmd = 'ssh 1.2.3.4 "ps waux"'; $process = new Process($cmd); $process->run(); if (!$process->isSuccessful()) { throw new RuntimeException( $process->getErrorOutput()); } echo $process->getOutput();
  16. 16. $cmd = 'ssh 1.2.3.4 "tail -f /some/log"'; $process = new Process($cmd); $process->run(function ($type, $buffer) { echo $buffer; });
  17. 17. use SymfonyComponentProcessPhpProcess; $process = new PhpProcess( '<?php echo "hello"; ?>'); $process->run(); if (!$process->isSuccessful()) { throw new RuntimeException( $process->getErrorOutput()); } echo $process->getOutput();
  18. 18. A set of decoupled and cohesive components CssSelector
  19. 19. use SymfonyComponentCssSelectorParser; Parser::cssToXpath('h4 > a:contains("foo")');
  20. 20. use SymfonyComponentCssSelectorParser; $document = new DOMDocument(); $document->loadHTMLFile('...'); $xpath = new DOMXPath($document); $expr = Parser::cssToXpath('a.smart'); $nodes = $xpath->query($expr); foreach ($nodes as $node) { printf("%s (%s)n", $node->nodeValue, $node- >getAttribute('href')); }
  21. 21. A set of decoupled and cohesive components Finder
  22. 22. use SymfonyComponentFinderFinder; $finder = new Finder(); $finder ->files() ->in(__DIR__) ->...() ->sortByName() ;
  23. 23. $finder ->name('*.php') ->depth('<= 1') ->date('>= yesterday') ->size('<= 1K') ->filter(function (SplFileInfo $file) { return strlen($file->getBasename()) < 9; }) ;
  24. 24. foreach ($finder as $file) { print $file->getRealpath()."n"; } $files = iterator_to_array($finder); $count = iterator_count($finder);
  25. 25. use SymfonyComponentFinderFinder; $s3 = new Zend_Service_Amazon_S3($key, $sct); $s3->registerStreamWrapper("s3"); $finder = new Finder(); $finder ->name('photos*') ->size('< 100K') ->date('since 1 hour ago') ->in('s3://bucket-name') ;
  26. 26. A set of decoupled and cohesive components Routing
  27. 27. /blog.php?section=symfony&article_id=18475
  28. 28. web/ index.php
  29. 29. /index.php/blog/2010/09/18/Symfony2-in-India
  30. 30. /blog/2010/09/18/Symfony2-in-India
  31. 31. /blog/:year/:month/:day/:slug
  32. 32. post: pattern: /blog/:year/:month/:day/:slug defaults: { _controller: BlogBundle:Post:show }
  33. 33. <routes> <route id="post" pattern="/blog/:year/:month/:day/:slug"> <default key="_controller"> BlogBundle:Post:show </default> </route> </routes>
  34. 34. use SymfonyComponentRoutingRouteCollection; use SymfonyComponentRoutingRoute; $collection = new RouteCollection(); $route = new Route( '/blog/:year/:month/:day/:slug', array('_controller' => 'BlogBundle:Post:show')); $collection->addRoute('post', $route); return $collection;
  35. 35. $router ->match('/blog/2010/09/18/Symfony2-in-India') $router ->generate('post', array('slug' => '...'))
  36. 36. post: pattern: /post/:slug defaults: { _controller: BlogBundle:Post:show }
  37. 37. $router ->generate('post', array('slug' => '...'))
  38. 38. An Object-Oriented abstraction on top of PHP
  39. 39. An Object-Oriented abstraction on top of PHP Request
  40. 40. use SymfonyComponentHttpFoundationRequest; $request = new Request(); // get a $_GET parameter $request->query->get('page'); // get a $_POST parameter $request->request->get('page'); // get a $_COOKIE parameter $request->cookies->get('name'); $request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest();
  41. 41. // get a $_FILE parameter $f = $request->files->get('image'); // $f is an instance of // SymfonyComponentHttpFoundationFileUploadedFile // guess extension, based on the mime type $n = '/path/to/file'.$file->getDefaultExtension(); $f->move($n);
  42. 42. new Request(); new Request( $_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER ); Request::create('/hello/Fabien', 'GET');
  43. 43. An Object-Oriented abstraction on top of PHP Session
  44. 44. $session = $request->getSession(); $session->set('foo', 'bar'); $session->get('foo'); $session->setFlash('notice', 'Congratulations!');
  45. 45. An Object-Oriented abstraction on top of PHP Response
  46. 46. use SymfonyComponentHttpFoundationResponse; $response = new Response('Hello World', 200, array('Content-Type' => 'text/plain')); $response->send(); $response->setHeader('Content-Type', 'text/ plain'); $response->setCookie('foo', 'bar'); $response->setContent('Hello World'); $response->setStatusCode(200);
  47. 47. An Object-Oriented abstraction of the HTTP dialog
  48. 48. A MVC Web Framework
  49. 49. The Symfony2 MVC Philosophy
  50. 50. Be as easy as possible for newcomers and as flexible as possible for advanced users
  51. 51. MVC
  52. 52. http://symfony-reloaded.org/ http://symfony-reloaded.org/downloads/ sandbox_2_0_PR3.zip
  53. 53. post: pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index } namespace ApplicationHelloBundleController; use SymfonyBundleFrameworkBundleController; class HelloController extends Controller { public function indexAction($name) { return new Response('Hello '.$name); } }
  54. 54. namespace ApplicationHelloBundleController; use SymfonyBundleFrameworkBundleController; class HelloController extends Controller { public function indexAction($name) { // Get things from the Model return $this->render( 'HelloBundle:Hello:index', array('name' => $name) ); } }
  55. 55. Hello <?php echo $name ?>!
  56. 56. <?php $view->extend('HelloBundle::layout') ?> Hello <?php echo $name ?>!
  57. 57. <html> <head> <title> <?php $view['slots']->output('title') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
  58. 58. slot title Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel   _content Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,   vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla   facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris   vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing   malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo   layout libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum   luctus  metus,  in  pulvinar  lectus  rutrum  sit  amet.  Duis  gravida,  metus  in   dictum  eleifend,  dolor  risus  ;ncidunt  ligula,  non  volutpat  nulla  sapien  in   elit.  Nulla  rutrum  erat  id  neque  suscipit  eu  ultricies  odio  sollicitudin.   Aliquam  a  mi  vel  eros  placerat  hendrerit.  Phasellus  por6tor,  augue  sit   amet  vulputate  venena;s,  dui  leo  commodo  odio,  a  euismod  turpis   ligula  in  elit.     slot
  59. 59. {% extends "HelloBundle::layout" %} {% block content %} Hello {{ name }}! {% endblock %}
  60. 60. <html> <head> <title> {% block title %}{% endblock %} </title> </head> <body> {% block body %}{% endblock %} </body> </html>
  61. 61. ~ PAC / HMVC http://en.wikipedia.org/wiki/Presentation-abstraction-control
  62. 62. Lorem  ipsum  dolor  sit  amet,  consectetur   Lorem  ipsum  dolor  sit   layout adipiscing  elit.  In  vel  nulla  arcu,  vitae   amet,  consectetur   cursus  nunc.  Integer  semper  turpis  et  enim   adipiscing  elit.  In  vel  nulla   por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum   arcu,  vitae  cursus  nunc.   dolor  sit  amet,  consectetur  adipiscing  elit.   Integer  semper  turpis  et   Mauris  vehicula  ves;bulum  dictum.   enim  por6tor  iaculis.   Aenean  non  velit  tortor.  Nullam  adipiscing   Nulla  facilisi.  Lorem  ipsum   malesuada  aliquam.  Mauris  dignissim,  urna   dolor  sit  amet,   quis  iaculis  tempus,  justo  libero  por6tor   consectetur  adipiscing  elit.   est,  nec  eleifend  est  elit  vitae  ante.   Mauris  vehicula   Curabitur  interdum  luctus  metus,  in   ves;bulum  dictum.   pulvinar  lectus  rutrum  sit  amet.  Duis   Aenean  non  velit  tortor.   gravida,  metus  in  dictum  eleifend,  dolor   Nullam  adipiscing   risus  ;ncidunt  ligula,  non  volutpat  nulla   malesuada  aliquam.   sapien  imain controller n  elit.  Nulla  rutrum  erat  id  neque   embedded MVC Mauris  dignissim,  urna   suscipit  eu  ultricies  odio  sollicitudin.   (_content slot) quis  iaculis  tempus,  justo   controller Aliquam  a  mi  vel  eros  placerat  hendrerit.   libero  por6tor  est,  nec   Phasellus  por6tor,  augue  sit  amet   eleifend  est  elit  vitae  ante.   vulputate  venena;s,  dui  leo  commodo   Curabitur  interdum  luctus   odio,  a  euismod  turpis  ligula  in  elit.     metus.  
  63. 63. public function indexAction($name) { $embedded = $this['controller_resolver'] ->render('HelloBundle:Hello:foo', array('name' => $name)); return $this->render( 'HelloBundle:Hello:index', array( 'name' => $name, 'embedded' => $embedded, ) ); }
  64. 64. <?php $view->extend('...:layout') ?> Lorem ipsum... <?php echo $view['actions'] ->render('HelloBundle:Hello:foo', array('name' => $name)) ?> Lorem ipsum...
  65. 65. Bundles
  66. 66. .../ SomeBundle/ Controller/ Entity/ Resources/ config/ views/ SomeBundle.php Tests/
  67. 67. public function registerBundleDirs() { return array( 'Application' => __DIR__.'/../src/Application', 'Bundle' => __DIR__.'/../src/Bundle', 'SymfonyBundle' => __DIR__.'/../src/vendor/ symfony/src/Symfony/Bundle', ); }
  68. 68. $this->render('SomeBundle:Hello:index', $params)
  69. 69. hello: pattern: /hello/:name defaults: { _controller: SomeBundle:Hello:index }
  70. 70. SomeBundle can be any of ApplicationSomeBundle BundleSomeBundle SymfonyBundleSomeBundle
  71. 71. Environments
  72. 72. Developers Customer End Users Development Staging Production Environment Environment Environment
  73. 73. cache cache cache debug   debug   debug   logs   logs   logs   stats stats stats Development Staging Production Environment Environment Environment
  74. 74. # config/config.yml doctrine.dbal: dbname: mydbname user: root password: %doctrine.dbal_password% swift.mailer: transport: smtp host: localhost
  75. 75. # config/config_dev.yml imports: - { resource: config.yml } doctrine.dbal: password: null swift.mailer: transport: gmail username: xxxxxxxx password: xxxxxxxx
  76. 76. # Doctrine Configuration doctrine.dbal: dbname: xxxxxxxx user: xxxxxxxx password: ~ # Swiftmailer Configuration swift.mailer: transport: smtp encryption: ssl auth_mode: login host: smtp.gmail.com username: xxxxxxxx password: xxxxxxxx
  77. 77. <!-- Doctrine Configuration --> <doctrine:dbal dbname="xxxxxxxx" user="xxxxxxxx" password="" /> <!-- Swiftmailer Configuration --> <swift:mailer transport="smtp" encryption="ssl" auth_mode="login" host="smtp.gmail.com" username="xxxxxxxx" password="xxxxxxxx" />
  78. 78. // Doctrine Configuration $container->loadFromExtension('doctrine', 'dbal', array( 'dbname' => 'xxxxxxxx', 'user' => 'xxxxxxxx', 'password' => '', )); // Swiftmailer Configuration $container->loadFromExtension('swift', 'mailer', array( 'transport' => "smtp", 'encryption' => "ssl", 'auth_mode' => "login", 'host' => "smtp.gmail.com", 'username' => "xxxxxxxx", 'password' => "xxxxxxxx", ));
  79. 79. Dependency Injection Container
  80. 80. Third-party libraries integration Unified Configuration
  81. 81. # Twig Configuration twig.config: auto_reload: true # Zend Logger Configuration zend.logger: priority: debug path: %kernel.root_dir%/logs/ %kernel.environment%.log
  82. 82. Configuration formats XML, YAML, PHP, INI, or Annotations Parameters management Fast (cached) Inheritance Sensitive data security …
  83. 83. <doctrine:dbal dbname="sfweb" username="root" password="SuperSecretPasswordThatAnyoneCanSee" />
  84. 84. in a .htaccess or httpd.conf file SetEnv SYMFONY__DOCTRINE__DBAL__PASSWORD "foobar" %doctrine.dbal.password%
  85. 85. <doctrine:dbal dbname="sfweb" username="root" password="%doctrine.dbal.password%" />
  86. 86. Developer Tools
  87. 87. INFO: Matched route "blog_home" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'index', '_route' => 'blog_home',)) INFO: Using controller "BundleBlogBundleController PostController::indexAction" INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ ORDER BY s0_.published_at DESC LIMIT 10 (array ())
  88. 88. INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) INFO: Using controller "BundleBlogBundleController PostController::showAction » INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught SymfonyComponentsRequestHandlerException NotFoundHttpException exception) INFO: Using controller "SymfonyFrameworkWebBundleController ExceptionController::exceptionAction"
  89. 89. DEBUG: Notifying (until) event "core.request" to listener "(SymfonyFrameworkWebBundleListenerRequestParser, resolve)" INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) DEBUG: Notifying (until) event "core.load_controller" to listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" INFO: Using controller "BundleBlogBundleControllerPostController::showAction" DEBUG: Listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" processed the event "core.load_controller" INFO: Trying to get post "3456" from database INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) DEBUG: Notifying (until) event "core.exception" to listener "(SymfonyFrameworkWebBundleListenerExceptionHandler, handle)" ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught SymfonyComponents RequestHandlerExceptionNotFoundHttpException exception) DEBUG: Notifying (until) event "core.request" to listener "(SymfonyFrameworkWebBundleListenerRequestParser, resolve)" DEBUG: Notifying (until) event "core.load_controller" to listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" INFO: Using controller "SymfonyFrameworkWebBundleControllerExceptionController::exceptionAction" DEBUG: Listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" processed the event "core.load_controller" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleListenerResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugDataCollector DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugWebDebugToolbar, handle)" DEBUG: Listener "(SymfonyFrameworkWebBundleListenerExceptionHandler, handle)" processed the event "core.exception" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleListenerResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugDataCollector DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugWebDebugToolbar, handle)"
  90. 90. Security XSS / CSRF / SQL Injection
  91. 91. Functional Tests
  92. 92. $client = $this->createClient(); $crawler = $client->request( 'GET', '/hello/Fabien'); $this->assertTrue($crawler->filter( 'html:contains("Hello Fabien")')->count());
  93. 93. $this->assertEquals( 10, $crawler->filter('div.hentry')->count()); $this->assertTrue( $client->getResponse()->isSuccessful());
  94. 94. $crawler = $client->request( 'GET', 'hello/Lucas' );
  95. 95. $link = $crawler->selectLink("Greet Lucas"); $client->click($link);
  96. 96. $form = $crawler->selectButton('submit'); $client->submit($form, array( 'name' => 'Lucas', 'country' => 'France', 'like_symfony' => true, 'photo' => '/path/to/lucas.jpg', ));
  97. 97. $harry = $this->createClient(); $sally = $this->createClient(); $harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages'); $this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
  98. 98. $harry = $this->createClient(); $sally = $this->createClient(); $harry->insulate(); $sally->insulate(); $harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages'); $this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
  99. 99. Caching
  100. 100. HTTP Expiration / HTTP Validation
  101. 101. $response->setSharedMaxAge(...); $response->setTtl(...); $response->setMaxAge(...); $response->setClientTtl(...); $response->setExpires(...); $response->setETag(...); $response->setLastModified(...);
  102. 102. Cache-Control: s-maxage=10
  103. 103. public function showAction() { // ... $response = $this->render('...', $vars); $response->setSharedMaxAge(10); return $response; }
  104. 104. Symfony 2 comes built-in with an HTTP accelerator
  105. 105. cacheable for 10 seconds cacheable for 5 seconds Lorem  ipsum  dolor  sit  amet,  consectetur   Lorem  ipsum  dolor  sit   layout adipiscing  elit.  In  vel  nulla  arcu,  vitae   amet,  consectetur   cursus  nunc.  Integer  semper  turpis  et  enim   adipiscing  elit.  In  vel  nulla   por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum   arcu,  vitae  cursus  nunc.   dolor  sit  amet,  consectetur  adipiscing  elit.   Integer  semper  turpis  et   Mauris  vehicula  ves;bulum  dictum.   enim  por6tor  iaculis.   Aenean  non  velit  tortor.  Nullam  adipiscing   Nulla  facilisi.  Lorem  ipsum   malesuada  aliquam.  Mauris  dignissim,  urna   dolor  sit  amet,   quis  iaculis  tempus,  justo  libero  por6tor   consectetur  adipiscing  elit.   est,  nec  eleifend  est  elit  vitae  ante.   Mauris  vehicula   Curabitur  interdum  luctus  metus,  in   ves;bulum  dictum.   pulvinar  lectus  rutrum  sit  amet.  Duis   Aenean  non  velit  tortor.   gravida,  metus  in  dictum  eleifend,  dolor   Nullam  adipiscing   risus  ;ncidunt  ligula,  non  volutpat  nulla   malesuada  aliquam.   sapien  main Nulla  rutrum  erat  id  neque   in  elit.   Mauris  embeddedurna   dignissim,   suscipit  eu  ultricies  odio  sollicitudin.   controller quis  iaculis  tempus,  justo   controller Aliquam  a  mi  vel  eros  placerat  hendrerit.   libero  por6tor  est,  nec   Phasellus  por6tor,  augue  sit  amet   eleifend  est  elit  vitae  ante.   vulputate  venena;s,  dui  leo  commodo   Curabitur  interdum  luctus   odio,  a  euismod  turpis  ligula  in  elit.     metus.  
  106. 106. cacheable for 10 seconds <?php $view->extend('...:layout') ?> <?php $view['slots']->start('sidebar') ?> 5 seconds cacheable for <?php echo $view['actions']->render('...:foo') ?> <?php $view['slots']->stop() ?>
  107. 107. $view['actions']->render('HelloBundle:Hello:foo', array('name' => $name), array('standalone' => true) )
  108. 108. Lorem  ipsum  dolor  sit  amet,  consectetur   Lorem  ipsum  dolor  sit   adipiscing  elit.  In  vel  nulla  arcu,  vitae   amet,  consectetur   cursus  nunc.  Integer  semper  turpis  et  enim   adipiscing  elit.  In  vel  nulla   por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum   arcu,  vitae  cursus  nunc.   dolor  sit  amet,  consectetur  adipiscing  elit.   Integer  semper  turpis  et   Mauris  vehicula  ves;bulum  dictum.   enim  por6tor  iaculis.   Aenean  non  velit  tortor.  Nullam  adipiscing   Nulla  facilisi.  Lorem  ipsum   malesuada  aliquam.  Mauris  dignissim,  urna   dolor  sit  amet,   quis  iaculis  tempus,  justo  libero  por6tor   consectetur  adipiscing  elit.   est,  nec  eleifend  est  elit  vitae  ante.   Mauris  vehicula   Curabitur  interdum  luctus  metus,  in   ves;bulum  dictum.   pulvinar  lectus  rutrum  sit  amet.  Duis   Aenean  non  velit  tortor.   gravida,  metus  in  dictum  eleifend,  dolor   Nullam  adipiscing   risus  ;ncidunt  ligula,  non  volutpat  nulla   malesuada  aliquam.   sapien  in  elit.  Nulla  rutrum  erat  id  neque   Mauris  dignissim,  urna   suscipit  eu  ultricies  odio  sollicitudin.   quis  iaculis  tempus,  justo   Aliquam  a  mi  vel  eros  placerat  hendrerit.   libero  por6tor  est,  nec   Phasellus  por6tor,  augue  sit  amet   eleifend  est  elit  vitae  ante.   vulputate  venena;s,  dui  leo  commodo   Curabitur  interdum  luctus   odio,  a  euismod  turpis  ligula  in  elit.     metus.  
  109. 109. <esi:include src="..." /> Lorem  ipsum  dolor  sit  amet,  consectetur   adipiscing  elit.  In  vel  nulla  arcu,  vitae   cursus  nunc.  Integer  semper  turpis  et  enim   por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum   dolor  sit  amet,  consectetur  adipiscing  elit.   Mauris  vehicula  ves;bulum  dictum.   Aenean  non  velit  tortor.  Nullam  adipiscing   malesuada  aliquam.  Mauris  dignissim,  urna   quis  iaculis  tempus,  justo  libero  por6tor   est,  nec  eleifend  est  elit  vitae  ante.   Curabitur  interdum  luctus  metus,  in   pulvinar  lectus  rutrum  sit  amet.  Duis   gravida,  metus  in  dictum  eleifend,  dolor   risus  ;ncidunt  ligula,  non  volutpat  nulla   sapien  in  elit.  Nulla  rutrum  erat  id  neque   suscipit  eu  ultricies  odio  sollicitudin.   Aliquam  a  mi  vel  eros  placerat  hendrerit.   Phasellus  por6tor,  augue  sit  amet   vulputate  venena;s,  dui  leo  commodo   odio,  a  euismod  turpis  ligula  in  elit.    
  110. 110. ESI… or Edge Side Includes
  111. 111. Lorem  ipsum   dolor  sit   amet,     1 2 Symfony2 Application Lorem   ipsum   Reverse Proxy dolor   Client 3 Lorem  ipsum   Lorem   dolor  sit   ipsum   amet,     dolor   4
  112. 112. Web Server Symfony2 app Requests Response
  113. 113. Web Server Symfony2 HTTP proxy Symfony2 app Requests Response
  114. 114. Reverse proxy Web Server Symfony2 app Requests Response
  115. 115. Extensibility
  116. 116. Request core.request getController() core.controller getArguments() core.view core.response Response
  117. 117. Request core.request getController() core.controller core.exception getArguments() core.view core.response Response
  118. 118. SwiftmailerBundle DoctrineBundle ZendBundle ... FrameworkBundle TwigBundle Bundles Components HttpKernel DependencyInjection Console Routing Templating HttpFoundation Event Dispatcher ...
  119. 119. Questions?

×