Symfony2 meets Drupal 8

Symfony2 meets Drupal 8

As you might know, some of the Symfony2 components will be used as the core foundation for the upcoming Drupal 8 release. In this session, I will first provide a quick overview of the Symfony2 components; then I will dive deeper into the ones that are going to be used in Drupal 8, explaining how they works and how to leverage all their features and flexibility. Besides the code, I will also talk about the benefits for the two communities and how we can learn from each others to make both Symfony and Drupal stronger in the PHP market.

9a22d09f92d50fa3d2a16766d0ba52f8?s=128

Fabien Potencier

March 21, 2012
Tweet

Transcript

  1. meets http://www.flickr.com/photos/nimport_nawak/3404931191

  2. Drupal 8 meets Symfony Fabien Potencier @fabpot fabien@symfony.com Founder of

    Lead developer of Open-Source libraries Twig, Swiftmailer, Silex, Pirum, Sismo, Pimple, Goutte, ... Symfony founder and lead developer
  3. Drupal 8 meets Symfony Lukas Kahwe Smith @lsmith smith@pooteeweet.org Works

    for in Switzerland PHP 5.3 Release Manager Co-lead of PHPCR Symfony2 core contributor
  4. http://www.flickr.com/photos/dunechaser/160405823 Drupal 8 meets Symfony How many of you are

    PHP developers?
  5. Drupal 8 meets Symfony http://www.flickr.com/photos/dunechaser/142079357 How many of you are

    Symfony “aware”?
  6. Drupal 8 meets Symfony We are both “outsiders” We are

    both quite experienced PHP developers We have a rough understanding of the hook paradigm aka the Drupal way http://www.flickr.com/photos/pictureperfectpose/76138988
  7. Drupal 8 meets Symfony A sad realization It would take

    a long time for us to be productive in Drupal let alone work on the core And everything we learn along the way would only help us with Drupal
  8. Drupal 8 meets Symfony What others do Building on top

    of long established OO design patterns Leverage new PHP language features and performance improvements Share code!
  9. Drupal 8 meets Symfony So Drupal is wrong? No, the

    question is just if the benefits of doing things differently outweigh the disadvantages
  10. Drupal 8 meets Symfony Core brain drain “The complexity of

    the custom code that’s used and the non-standard architecture combines to create a barrier to entry for developers new to Drupal (both experienced and novice developers alike).” buytaert.net
  11. Drupal 8 meets Symfony What could be gained Facilitate the

    refactoring towards a “framework” core Focus Drupal dev resources on the CMS Easier integration with other applications Ensure that the Drupal developer pool continues to grow
  12. Drupal 8 meets Symfony A decision was made “While these

    changes may seem large, and some of them are, we believe that they will achieve the right balance between empowering Drupal's design and architecture, and moving toward more modern, standard, well-tested code and techniques to empower a new generation of developers.” buytaert.net
  13. Drupal 8 meets Symfony How to collaborate? Symfony2 is MIT

    licensed which is GPL compatible Symfony2 development is very transparently managed on github.com We want to ensure Symfony2 works for Drupal, phpBB, etc.
  14. Drupal 8 meets Symfony For example ... Symfony2.0 provides a

    concept called “flash messages” to pass messages to the very next request drupal_set_message() could be replaced by this if we make it a bit more flexible Drak, lead of the Zikula CMS, created a PR to address exactly these concerns
  15. Drupal 8 meets Symfony What is Symfony? http://www.flickr.com/photos/apranihita/141159146/

  16. Drupal 8 meets Symfony http://www.flickr.com/photos/bigpinkcookie/22716359

  17. Drupal 8 meets Symfony is... ... a reusable set of

    standalone, decoupled, and cohesive PHP components that solve common web development problems http://www.flickr.com/photos/krislitman/493626935
  18. Drupal 8 meets Symfony is... ... an Object-Oriented set of

    classes ... compatible with PHP 5.3 and later http://www.flickr.com/photos/krislitman/493626935
  19. Drupal 8 meets Symfony DependencyInjection EventDispatcher HttpFoundation DomCrawler ClassLoader CssSelector

    HttpKernel BrowserKit Templating Translation Filesystem Serializer Validator Security Routing Console Process Config Finder Locale Yaml Form
  20. Drupal 8 meets Symfony is... ... a full-stack web framework

    http://www.flickr.com/photos/krislitman/493626935
  21. Drupal 8 meets Symfony Official website http://symfony.com/ Official repository https://github.com/symfony/symfony

    http://www.flickr.com/photos/28634332@N05/5654415647
  22. Drupal 8 meets Symfony Official website http://symfony.com/components Official repositories https://github.com/symfony/XXXX

    Components http://www.flickr.com/photos/28634332@N05/5654415647
  23. Drupal 8 meets Symfony Mailing-list https://groups.google.com/group/symfony2 IRC channel irc://irc.freenode.net/symfony http://www.flickr.com/photos/28634332@N05/5654415647

  24. Drupal 8 meets Symfony Which Open-Source projects are already using

    the Symfony Components? http://www.flickr.com/photos/maistora/3014414972
  25. Drupal 8 meets Symfony Behat - a BDD framework Console,

    DependencyInjection, EventDispatcher, Finder, Yaml, Config, Translation Doctrine - an object relational mapper Console, Yaml Propel - an object relational mapper Console, ClassLoader, Yaml PHPUnit - a PHP unit testing framework Yaml, (Finder soon?) Jackalope - a content repository (JCR 170/283) ClassLoader, Console Developer Tools http://www.flickr.com/photos/c_r_i_s/77763712
  26. Drupal 8 meets Symfony Silex - a micro-framework BrowerKit, CssSelector,

    DomCrawler, EventDispatcher, HttpFoundation, HttpKernel, Routing, Form, Translation, Validator PPI 2 - a framework ClassLoader, HttpFoundation, Routing, Templating Frameworks http://www.flickr.com/photos/c_r_i_s/77763712
  27. Drupal 8 meets Symfony easybook - a book publishing platform

    ClassLoader, Console, EventDispatcher, Filesystem, Finder, Yaml Midgard CMS - a content management framework uses the full-stack framework Zikula - ex PostNuke - an application framework HttpFoundation, HttpKernel, EventDispatcher, ClassLoader, DependencyInjection phpBB - a bulletin board software EventDispatcher, and most of them for version 4? Products http://www.flickr.com/photos/c_r_i_s/77763712
  28. Drupal 8 meets Symfony What about Drupal 8? http://www.flickr.com/photos/aloshbennett/619307160

  29. Drupal 8 meets Symfony DependencyInjection EventDispatcher HttpFoundation DomCrawler ClassLoader CssSelector

    HttpKernel BrowserKit Templating Translation Filesystem Serializer Validator Security Routing Console Process Config Finder Locale Yaml Form
  30. Drupal 8 meets Symfony DependencyInjection EventDispatcher HttpFoundation DomCrawler ClassLoader CssSelector

    HttpKernel BrowserKit Templating Translation Filesystem Serializer Validator Security Routing Console Process Config Finder Locale Yaml Form
  31. Drupal 8 meets Symfony Using the Symfony Components http://www.flickr.com/photos/35168673@N03/6086229920

  32. Drupal 8 meets Symfony $ git clone https://github.com/symfony/Console.git $ git

    co v2.0.9 $ git co 2.0 $ git co master Git
  33. Drupal 8 meets Symfony $ curl -O https://github.com/symfony/Console/zipball/v2.0.9 $ curl

    -O https://github.com/symfony/Console/zipball/2.0 $ curl -O https://github.com/symfony/Console/zipball/master Archives
  34. Drupal 8 meets Symfony $ pear channel-discover pear.symfony.com $ pear

    install symfony2/Console-2.0.9 PEAR
  35. Drupal 8 meets Symfony composer.json { "require": { "symfony/console": "2.1.*",

    "symfony/http-foundation": "v2.0.9" } } curl -s http://getcomposer.org/installer | php php composer.phar install Composer
  36. Drupal 8 meets Symfony Symfony Components comes with Drupal 8

  37. Drupal 8 meets Symfony ClassLoader

  38. Drupal 8 meets Symfony http://symfony.com/PSR0

  39. Drupal 8 meets Symfony require_once __DIR__.'/src/Symfony/Component/ ClassLoader/UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; $loader

    = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/vendor/symfony/src', )); $loader->register();
  40. $loader->registerPrefixes(array( 'Twig_' => __DIR__.'/vendor/twig/lib', )); Drupal 8 meets Symfony

  41. Drupal 8 meets Symfony The Symfony ClassLoader Component loads your

    project classes automatically if they follow some standard conventions http://www.flickr.com/photos/ynaffitx/4667769355
  42. Drupal 8 meets Symfony HttpFoundation

  43. Drupal 8 meets Symfony http://www.flickr.com/photos/deniscollette/6741424757 HTTP HTTP/1.1 RFC 2616 http://www.ietf.org/rfc/rfc2616.txt

    http://tools.ietf.org/wg/httpbis/
  44. Drupal 8 meets Symfony The Web in action The User

    asks for a Resource in a Browser http://example.com/foo.html
  45. Drupal 8 meets Symfony The Web in action The User

    asks for a Resource in a Browser The Browser sends a Request to the Server GET /foo.html HTTP/1.1 Host: example.com
  46. Drupal 8 meets Symfony The Web in action The User

    asks for a Resource in a Browser The Browser sends a Request to the Server The Server sends back a Response to the Browser HTTP/1.1 200 OK Date: Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  47. Drupal 8 meets Symfony The Web in action The User

    asks for a Resource in a Browser The Browser sends a Request to the Server The Server sends back a Response to the Browser The Browser displays the Resource to the User
  48. Drupal 8 meets Symfony Internet Client Server The Client sends

    a Request to the Server The Server sends back a Response to the Client Request GET /foo.html HTTP/1.1 Host: example.com Response HTTP/1.1 200 OK Date: Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  49. Drupal 8 meets Symfony Request GET /foo.html HTTP/1.1 Host: example.com

    http://www.flickr.com/photos/splorp/64027565
  50. session_start(); $name = $_GET['name']; // $_POST, $_FILE, $_COOKIE, ... echo

    $_SESSION['name']; $method = $_SERVER['REQUEST_METHOD']; Drupal 8 meets Symfony Request GET /foo.html HTTP/1.1 Host: example.com
  51. Drupal 8 meets Symfony $clientIp = $_SERVER['REMOTE_ADDR']; Request GET /foo.html

    HTTP/1.1 Host: example.com
  52. Drupal 8 meets Symfony if (isset($_SERVER['HTTP_CLIENT_IP'])) { return $_SERVER['HTTP_CLIENT_IP']; }

    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); return isset($ips[0]) ? trim($ips[0]) : ''; } return $_SERVER['REMOTE_ADDR']; Request GET /foo.html HTTP/1.1 Host: example.com
  53. Drupal 8 meets Symfony if ($trustProxy) { if (isset($_SERVER['HTTP_CLIENT_IP'])) {

    return $_SERVER['HTTP_CLIENT_IP']; } if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); return isset($ips[0]) ? trim($ips[0]) : ''; } } return $_SERVER['REMOTE_ADDR']; Request GET /foo.html HTTP/1.1 Host: example.com
  54. Drupal 8 meets Symfony http://www.flickr.com/photos/viamoi/3338093351 Not Object-Oriented Low-level abstraction only

    “Singleton” like Not Object-Oriented Request GET /foo.html HTTP/1.1 Host: example.com
  55. Drupal 8 meets Symfony use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); $request

    = Request::create('/hello.html', 'GET'); $request->overrideGlobals(); Request GET /foo.html HTTP/1.1 Host: example.com
  56. Drupal 8 meets Symfony $request->query->get('name', 'Default'); $request->getSession()->get('name'); $request->getPathInfo(); $request->getClientIp(); Request::trustProxyData();

    Request GET /foo.html HTTP/1.1 Host: example.com
  57. Drupal 8 meets Symfony Response HTTP/1.1 200 OK Date: Wed,

    15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World! http://www.flickr.com/photos/splorp/64027565
  58. Drupal 8 meets Symfony Response HTTP/1.1 200 OK Date: Wed,

    15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World! header('HTTP/1.0 404 Not Found'); header('Content-Type: text/html; charset=UTF-8'); setcookie('name', $name); $_SESSION['name'] = 'Fabien'; echo 'Hello '.$name;
  59. Drupal 8 meets Symfony http://www.flickr.com/photos/viamoi/3338093351 Low-level abstraction only “Singleton” like

    Does not play well with the CLI Not Object-Oriented Response HTTP/1.1 200 OK Date: Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  60. Drupal 8 meets Symfony use Symfony\Component\HttpFoundation\Response; $response = new Response('Not

    Found', 404, array('Content-Type' => 'text/plain')); $response = new Response(); $response->setContent('Hello World'); $response->send(); Response HTTP/1.1 200 OK Date: Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  61. Drupal 8 meets Symfony use Symfony\Component\HttpFoundation\StreamedResponse; $response = new StreamedResponse(function

    () { echo 'foo'; flush(); echo 'bar'; }); $response->send(); Response HTTP/1.1 200 OK Date: Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  62. Drupal 8 meets Symfony $headers = $response->headers; $headers->set( 'Content-Disposition', $headers->makeDisposition(

    ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'foo.pdf') ); Response HTTP/1.1 200 OK Date: Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  63. Drupal 8 meets Symfony $response->prepare($request); Response HTTP/1.1 200 OK Date:

    Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World!
  64. Drupal 8 meets Symfony Session Management http://www.flickr.com/photos/tomvu/5371659662

  65. Drupal 8 meets Symfony The Symfony HttpFoundation Component defines a

    feature-full object-oriented layer for the HTTP messages http://www.flickr.com/photos/ynaffitx/4667769355
  66. Drupal 8 meets Symfony It replaces PHP native global variables

    and functions to allow writing better, more secure, and more testable code http://www.flickr.com/photos/ynaffitx/4667769355
  67. Drupal 8 meets Symfony Routing

  68. Drupal 8 meets Symfony use Symfony\Component\Routing\Route; $route = new Route('/node/{id}',

    array( '_controller' => 'SomeClass::someMethod' )); use Symfony\Component\Routing\RouteCollection; $routes = new RouteCollection(); $routes->add('node', $route);
  69. Drupal 8 meets Symfony use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Matcher\UrlMatcher; $matcher =

    new UrlMatcher($routes, new RequestContext()); $attributes = $matcher->match('/node/12'); $attributes = $matcher->match($request->getPathInfo()); print_r($attributes); array( '_route' => 'node', 'id' => 12, '_controller' => 'SomeClass::someMethod', );
  70. Drupal 8 meets Symfony use Symfony\Component\Routing\Generator\UrlGenerator; $generator = new UrlGenerator($routes,

    $context); echo $generator->generate('node', array('id' => 12));
  71. Drupal 8 meets Symfony The Symfony Routing Component decouples the

    look of URLs from the code that handle them http://www.flickr.com/photos/ynaffitx/4667769355
  72. Drupal 8 meets Symfony EventDispatcher

  73. Drupal 8 meets Symfony use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher();

    $callable = function (Event $event) { // do something }; $dispatcher->addListener('event_name', $callable); $dispatcher->dispatch('event_name', new Event());
  74. Drupal 8 meets Symfony The Symfony EventDispatcher Component implements a

    lightweight version of the Observer design pattern http://www.flickr.com/photos/ynaffitx/4667769355
  75. Drupal 8 meets Symfony HttpKernel

  76. Drupal 8 meets Symfony Request Response HTTP/1.1 200 OK Date:

    Wed, 15 Oct 2005 07:07:07 GMT Content-Length: 14 Content-Type: text/html Hello World! GET /foo.html HTTP/1.1 Host: example.com http://www.flickr.com/photos/-bast-/349497988
  77. Drupal 8 meets Symfony The web in action The User

    asks for a Resource in a Browser The Browser sends a Request to the Server Symfony gives the Developer a Request Object The Developer “converts” the Request Object to a Response Object The Server sends back a Response to the Browser The Browser displays the Resource to the User
  78. Drupal 8 meets Symfony namespace Symfony\Component\HttpKernel; interface HttpKernelInterface { /**

    * @return Response A Response instance */ function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true); }
  79. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content Workflow
  80. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  81. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  82. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  83. Drupal 8 meets Symfony namespace Symfony\Component\HttpKernel\Controller; interface ControllerResolverInterface { function

    getController(Request $request); function getArguments(Request $request, $controller); }
  84. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  85. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  86. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  87. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  88. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  89. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  90. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  91. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  92. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  93. Drupal 8 meets Symfony $routes = new RouteCollection(); $routes->add('hello', new

    Route('/hello', array('_controller' => function (Request $request) { return new Response(sprintf("Hello %s", $request->get('name'))); } ))); $request = Request::createFromGlobals(); $matcher = new UrlMatcher($routes, new RequestContext()); $dispatcher = new EventDispatcher(); $dispatcher->addSubscriber(new RouterListener($matcher)); $resolver = new ControllerResolver(); $kernel = new HttpKernel($dispatcher, $resolver); $kernel->handle($request)->send();
  94. Drupal 8 meets Symfony Symfony built-in listeners http://www.flickr.com/photos/c_r_i_s/67306260

  95. Drupal 8 meets Symfony $handler = function ($exception) { return

    new Response($exception->getMessage(), 500); }); $dispatcher->addSubscriber(new ExceptionListener($handler));
  96. Drupal 8 meets Symfony $handler = function ($exception) { $handler

    = new ExceptionHandler(); return $handler->createResponse($exception); }); $dispatcher->addSubscriber(new ExceptionListener($handler));
  97. Drupal 8 meets Symfony

  98. Drupal 8 meets Symfony The default HttpKernel implementation makes Drupal

    interoperable with any other software using the same http://www.flickr.com/photos/ynaffitx/4667769355
  99. Drupal 8 meets Symfony http://www.flickr.com/photos/cmogle/2947179118 HTTP Testing

  100. Drupal 8 meets Symfony use Symfony\Component\HttpKernel\Client; $client = new Client($kernel);

    $client->request('GET', '/hello/Fabien'); $response = $client->getResponse(); $this->assertEquals(200, $response->getStatusCode());
  101. Drupal 8 meets Symfony use Symfony\Component\HttpKernel\Client; $client = new Client($kernel);

    $crawler = $client->request('GET', '/hello/Fabien'); $nodes = $crawler->filter('h1:contains("Fabien")'); $this->assertCount(1, $nodes);
  102. http://www.flickr.com/photos/laserstars/908946494 Drupal 8 meets Symfony HTTP Caching

  103. Expiration Cache-Control Expires

  104. Validation Last-Modified If-Modified-Since ETag If-None-Match

  105. Drupal 8 meets Symfony $response->setTtl(10); $response->setClientTtl(10);

  106. Drupal 8 meets Symfony // get the last modified date

    as fast as you can $lastModified = ...; $response = new Response(); $response->setLastModified($lastModified); if ($response->isNotModified($request)) { return $response; } // do the expensive work $response->setContent(...); return $response;
  107. Drupal 8 meets Symfony Expiration wins over Validation http://www.flickr.com/photos/hoyvinmayvin/4672922637

  108. Drupal 8 meets Symfony $kernel = new HttpKernel($dispatcher, $resolver); $kernel

    = new HttpCache($kernel, new Store($cacheDir));
  109. Drupal 8 meets Symfony Varnish The HTTP accelerator Varnish The

    HTTP accelerator http://www.flickr.com/photos/stuckincustoms/3232133635
  110. Drupal 8 meets Symfony Using the default HttpKernel allows Drupal

    to benefit from the many built-in features http://www.flickr.com/photos/ynaffitx/4667769355
  111. Drupal 8 meets Symfony Edge Side Includes ESI http://www.w3.org/TR/esi-lang h"p://www.flickr.com/photos/bored-­‐now/2264811719

  112. Drupal 8 meets Symfony

  113. Drupal 8 meets Symfony

  114. Drupal 8 meets Symfony HTTP Validation

  115. Drupal 8 meets Symfony HTTP Expiration HTTP Validation

  116. Drupal 8 meets Symfony <esi:include src="..." />

  117. Drupal 8 meets Symfony Request Response response Call Controller response?

    expection Sub-Request terminate controller view resolve controller resolve arguments request exception “sub-response” content
  118. Drupal 8 meets Symfony HTTP Expiration

  119. Reverse Proxy Cache Browser Your PHP application GET /foo HTTP/1.1

    Host: foo.org GET /foo HTTP/1.1 Host: foo.org GET /bar HTTP/1.1 Host: foo.org Lorem   ipsum   dolor   <esi:include   src="h4p.."  /> HTTP/1.1 200 OK C-C: s-maxage=600 Lorem  ipsum   dolor HTTP/1.1 200 OK C-C: s-maxage=5 Lorem  ipsum   dolor  sit  amet,   Lorem   ipsum   dolor HTTP/1.1 200 OK GET /foo C-C: s-maxage=600 Lor <esi:include /> GET /bar C-C: s-maxage=5 Lorem
  120. Reverse Proxy Cache Your PHP application GET /foo HTTP/1.1 Host:

    foo.org Lorem  ipsum   dolor  sit  amet,   Lorem   ipsum   dolor HTTP/1.1 200 OK GET /foo C-C: s-maxage=600 Lor <esi:include /> GET /bar C-C: s-maxage=5 Lorem before exp. Browser
  121. Reverse Proxy Cache Your PHP application GET /foo HTTP/1.1 Host:

    foo.org GET /bar HTTP/1.1 Host: foo.org Lorem  ipsum   dolor HTTP/1.1 200 OK C-C: s-maxage=5 Lorem  ipsum   dolor  sit  amet,   Lorem   ipsum   dolor HTTP/1.1 200 OK GET /foo C-C: s-maxage=600 Lor <esi:include /> GET /bar C-C: s-maxage=5 Lorem after exp. Browser
  122. Drupal 8 meets Symfony $kernel = new HttpCache( $kernel, new

    Store($cacheDir), new Esi() );
  123. Drupal 8 meets Symfony http://www.flickr.com/photos/stuckincustoms/3232133635 Varnish The HTTP accelerator Varnish

    The HTTP accelerator
  124. Drupal 8 meets Symfony The Symfony HttpKernel Component provides the

    building blocks to create flexible, extensible, and scalable HTTP-based frameworks http://www.flickr.com/photos/ynaffitx/4667769355
  125. Drupal 8 meets Symfony The Symfony HttpKernel Component leverages the

    HTTP specification to make integration between projects easy http://www.flickr.com/photos/ynaffitx/4667769355
  126. Drupal 8 meets Symfony DependencyInjection EventDispatcher HttpFoundation DomCrawler ClassLoader CssSelector

    HttpKernel BrowserKit Templating Translation Filesystem Serializer Validator Security Routing Console Process Config Finder Locale Yaml Form http://www.flickr.com/photos/ecstaticist/3860865429 http://symfony.com/components
  127. Drupal 8 meets Symfony Silex https://github.com/fabpot/Silex http://silex.sensiolabs.org/ http://www.flickr.com/photos/linhngan/2715287035

  128. Drupal 8 meets Symfony http://fabien.potencier.org/build-a-framework Build your own framework http://www.flickr.com/photos/linhngan/2715287035

  129. Drupal 8 meets Symfony http://live.symfony.com/

  130. Drupal 8 meets Symfony The Symfony Components provides the low-level

    building blocks that you need to build a web product so that YOU can focus on what matters most for Drupal http://www.flickr.com/photos/ynaffitx/4667769355
  131. Drupal 8 meets Symfony http://www.flickr.com/photos/stevendepolo/4582437563 @fabpot @lsmith