Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Fabien Potencier

March 21, 2012
Tweet

More Decks by Fabien Potencier

Other Decks in Programming

Transcript

  1. Drupal 8 meets Symfony Fabien Potencier @fabpot [email protected] Founder of

    Lead developer of Open-Source libraries Twig, Swiftmailer, Silex, Pirum, Sismo, Pimple, Goutte, ... Symfony founder and lead developer
  2. Drupal 8 meets Symfony Lukas Kahwe Smith @lsmith [email protected] Works

    for in Switzerland PHP 5.3 Release Manager Co-lead of PHPCR Symfony2 core contributor
  3. 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
  4. 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
  5. 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!
  6. Drupal 8 meets Symfony So Drupal is wrong? No, the

    question is just if the benefits of doing things differently outweigh the disadvantages
  7. 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
  8. 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
  9. 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
  10. 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.
  11. 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
  12. 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
  13. 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
  14. 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
  15. Drupal 8 meets Symfony is... ... a full-stack web framework

    http://www.flickr.com/photos/krislitman/493626935
  16. Drupal 8 meets Symfony Which Open-Source projects are already using

    the Symfony Components? http://www.flickr.com/photos/maistora/3014414972
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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();
  25. 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
  26. Drupal 8 meets Symfony The Web in action The User

    asks for a Resource in a Browser http://example.com/foo.html
  27. 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
  28. 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!
  29. 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
  30. 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!
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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;
  38. 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!
  39. 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!
  40. 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!
  41. 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!
  42. 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!
  43. 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
  44. 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
  45. 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);
  46. 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', );
  47. 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
  48. 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());
  49. Drupal 8 meets Symfony The Symfony EventDispatcher Component implements a

    lightweight version of the Observer design pattern http://www.flickr.com/photos/ynaffitx/4667769355
  50. 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
  51. 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
  52. 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); }
  53. 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
  54. 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
  55. 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
  56. 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
  57. Drupal 8 meets Symfony namespace Symfony\Component\HttpKernel\Controller; interface ControllerResolverInterface { function

    getController(Request $request); function getArguments(Request $request, $controller); }
  58. 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
  59. 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
  60. 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
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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();
  68. Drupal 8 meets Symfony $handler = function ($exception) { return

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

    = new ExceptionHandler(); return $handler->createResponse($exception); }); $dispatcher->addSubscriber(new ExceptionListener($handler));
  70. 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
  71. 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());
  72. 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);
  73. 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;
  74. Drupal 8 meets Symfony Varnish The HTTP accelerator Varnish The

    HTTP accelerator http://www.flickr.com/photos/stuckincustoms/3232133635
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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