Forget about index.php and build you applications around HTTP!

3,847 views
3,766 views

Published on

Slides from my talk at Dutch PHP Conference in Amsterdam

Published in: Engineering, Technology, Sports
0 Comments
14 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,847
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
39
Comments
0
Likes
14
Embeds 0
No embeds

No notes for slide

Forget about index.php and build you applications around HTTP!

  1. 1. FORGET ABOUT INDEX.PHP BUILD YOUR APPLICATIONS AROUND HTTP!
  2. 2. Kacper Gunia @cakper Software Engineer @SensioLabsUK Symfony Certified Developer PHPers Silesia @PHPersPL
  3. 3. Good old days flickr.com/linkahwai/5162310920
  4. 4. Hello world in PHP“ ” + tutorial
  5. 5. Gojko’s two facts about programming web: 1)Ctrl-C 2)Ctrl-V
  6. 6. <?php   ! $name  =  $_GET['name'];   echo  "Hello  $name!";
  7. 7. It works! :D
  8. 8. but…
  9. 9. and so on… ;)
  10. 10. How HTTP works? flickr.com/see-­‐through-­‐the-­‐eye-­‐of-­‐g/4278744230
  11. 11. Request Kabooooom! Response
  12. 12. This is what HTTP is about! Request Response
  13. 13. This is what Your App is about! Request Response
  14. 14. “(…) the goal of your application is always to interpret a request and create the appropriate response based on your application logic.” Symfony.com
  15. 15. HTTP is simple flickr.com/wildhaber/5936335464
  16. 16. Request flickr.com/haniamir/3318727924
  17. 17. GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000
  18. 18. GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 I want to see…
  19. 19. GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 …this resource!
  20. 20. GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 And I know it should be on localhost
  21. 21. GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 Psst, I’m using 1.1 version of HTTP protocol
  22. 22. Response flickr.com/aftab/3364835006
  23. 23. HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper!
  24. 24. HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! OK man, I’ve found it!
  25. 25. HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! And it’s an HTML
  26. 26. HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! Hello World!
  27. 27. [METH]  [REQUEST-­‐URI]  HTTP/[VER]   [Field1]:  [Value1]   [Field2]:  [Value2]   ! [request  body,  if  any] HTTP/[VER]  [CODE]  [TEXT]   [Field1]:  [Value1]   [Field2]:  [Value2]   ! [response  body] ResponseRequest
  28. 28. What if we create objects from Request & Response?
  29. 29. Object-oriented HTTP flickr.com/mohammadafshar/9571051345
  30. 30. GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 $request-­‐>getMethod();      GET   $request-­‐>getPathInfo();  /
  31. 31. HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! $response-­‐>getStatusCode();  200   $response-­‐>getContent();        Hello  Kacper!
  32. 32. HttpFoundation flickr.com/rubempjr/8050505443
  33. 33. “The HttpFoundation component defines an object-oriented
 layer for the HTTP specification” Symfony.com
  34. 34. Request flickr.com/haniamir/3318727924
  35. 35. $request  =  Request::createFromGlobals();   ! $request  =  new  Request(          $_GET,          $_POST,          array(),          $_COOKIE,          $_FILES,          $_SERVER   );
  36. 36. !        $_GET          $request-­‐>query            $_POST        $request-­‐>request          $_COOKIE    $request-­‐>cookies          $_FILES      $request-­‐>files          $_SERVER    $request-­‐>server   !                            $request-­‐>headers                                $request-­‐>attributes ParameterBag instances
  37. 37. $name  =  isset($_GET['name'])                    ?  $_GET['name']                    :  "World"; $name  =  $request                  -­‐>query                  -­‐>get('name',  'World');
  38. 38. $request-­‐>isSecure(); Verify configured header or standard one
  39. 39. $request-­‐>isXmlHttpRequest(); Verify AJAX request
  40. 40. $request  =  Request::create(                                      '/',                                      'GET',                                      ['name'  =>  'Kacper']                        ); Simulate a Request
  41. 41. Response flickr.com/aftab/3364835006
  42. 42. $response  =  new  Response(          ‘Hello  Kacper!’,          Response::HTTP_OK,          ['content-­‐type'  =>  'text/html']   );   ! $response-­‐>prepare($request);   $response-­‐>send();
  43. 43. $response  =  new  RedirectResponse(
                                'http://example.com/'                          ); Redirect Response
  44. 44. $response  =  new  JsonResponse();   $response-­‐>setData(['name'  =>  'Kacper']); JSON Response
  45. 45. Let’s use them together!
  46. 46. $kernel  =  new  AppKernel('dev',  true);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   ! $kernel-­‐>terminate($request,  $response); Symfony app_dev.php
  47. 47. $kernel  =  new  AppKernel('dev',  true);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   ! $kernel-­‐>terminate($request,  $response); Symfony app_dev.php
  48. 48. Reminds something? ;)
  49. 49. Request Kabooooom! Response
  50. 50. Front Controller flickr.com/cedwardbrice/8334047708
  51. 51. ”The Front Controller consolidates all request handling by channeling requests through a single handler object (…)” MartinFowler.com
  52. 52. $kernel  =  new  AppKernel('dev',  true);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   ! $kernel-­‐>terminate($request,  $response);
  53. 53. Let’s go deeper…
  54. 54. HTTP Kernel flickr.com/stuckincustoms/6341844005
  55. 55. “The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher.” Symfony.com
  56. 56. interface  HttpKernelInterface   {          const  MASTER_REQUEST  =  1;          const  SUB_REQUEST  =  2;   !        /**            *  @return  Response  A  Response  instance            */          public  function  handle(                  Request  $request,                    $type  =  self::MASTER_REQUEST,                    $catch  =  true);   }
  57. 57. How Symfony transforms Request into Response?
  58. 58. Event Dispatcher flickr.com/parksjd/11847079564
  59. 59. “The EventDispatcher component provides tools that allow your application components to communicate with each other by dispatching events and listening to them.” Symfony.com
  60. 60. EventDispatcher is an implementation of Mediator pattern
  61. 61. $dispatcher  =  new  EventDispatcher();   $dispatcher-­‐>addListener(                            'foo.action',                              function  (Event  $event)  {                                    //  do  whatever  you  need   });   ! $event  =  new  Event();   $dispatcher-­‐>dispatch('foo.action',  $event);
  62. 62. The kernel.request Event flickr.com/drakegoodman/13479419575
  63. 63. Manipulate your Request here…
  64. 64. …you can even return a Response!
  65. 65. public  function  onKernelRequest(GetResponseEvent  $event)   {          $request  =  $event-­‐>getRequest();          if  ($request-­‐>query-­‐>get('name')  ===  'Kacper')  {                  $event-­‐>setResponse(                          new  Response("We  don't  like  you!")                  );          }   }
  66. 66. …or e.g. detect device, location…
  67. 67. …and routing is resolved here
  68. 68. The Routing Component flickr.com/checksam/12814058644
  69. 69. “The Routing component maps an HTTP request to a set of configuration variables.” Symfony.com
  70. 70. $route  =  new  Route('/',  array('controller'  =>  'HelloController'));   $routes  =  new  RouteCollection();   $routes-­‐>add('hello_route',  $route);   ! $context  =  new  RequestContext();   $context-­‐>fromRequest($request);   ! $matcher  =  new  UrlMatcher($routes,  $context);   ! $parameters  =  $matcher-­‐>match('/');   //  ['controller'  =>  'HelloController',  '_route'  =>  'hello_route']
  71. 71. $route  =  new  Route('/',  array('controller'  =>  'HelloController'));   $routes  =  new  RouteCollection();   $routes-­‐>add('hello_route',  $route);   ! $context  =  new  RequestContext();   $context-­‐>fromRequest($request);   ! $matcher  =  new  UrlMatcher($routes,  $context);   ! $parameters  =  $matcher-­‐>match('/');   //  ['controller'  =>  'HelloController',  '_route'  =>  'hello_route']
  72. 72. $route  =  new  Route('/',  array('controller'  =>  'HelloController'));   $routes  =  new  RouteCollection();   $routes-­‐>add('hello_route',  $route);   ! $context  =  new  RequestContext();   $context-­‐>fromRequest($request);   ! $matcher  =  new  UrlMatcher($routes,  $context);   ! $parameters  =  $matcher-­‐>match('/');   //  ['controller'  =>  'HelloController',  '_route'  =>  'hello_route']
  73. 73. $route  =  new  Route('/',  array('controller'  =>  'HelloController'));   $routes  =  new  RouteCollection();   $routes-­‐>add('hello_route',  $route);   ! $context  =  new  RequestContext();   $context-­‐>fromRequest($request);   ! $matcher  =  new  UrlMatcher($routes,  $context);   ! $parameters  =  $matcher-­‐>match('/');   //  ['controller'  =>  'HelloController',  '_route'  =>  'hello_route']
  74. 74. $route  =  new  Route('/',  array('controller'  =>  'HelloController'));   $routes  =  new  RouteCollection();   $routes-­‐>add('hello_route',  $route);   ! $context  =  new  RequestContext();   $context-­‐>fromRequest($request);   ! $matcher  =  new  UrlMatcher($routes,  $context);   ! $parameters  =  $matcher-­‐>match('/');   //  ['controller'  =>  'HelloController',  '_route'  =>  'hello_route']
  75. 75. Resolve Controller flickr.com/rightbrainphotography/480979176
  76. 76. interface  ControllerResolverInterface   {          public  function  getController(                                                  Request  $request                                          );   !        public  function  getArguments(                                                  Request  $request,                                                                    $controller                                          );   }
  77. 77. Controller is a PHP callable
  78. 78. The kernel.controller Event flickr.com/drakegoodman/12451824524
  79. 79. Change controller here (if you need)
  80. 80. and initialise data
  81. 81. e.g. parameters conversion happens now
  82. 82. Resolve Arguments flickr.com/joiseyshowaa/2720195951
  83. 83. interface  ControllerResolverInterface   {          public  function  getController(                                                  Request  $request                                          );   !        public  function  getArguments(                                                  Request  $request,                                                                    $controller                                          );   }
  84. 84. Arguments come from $request->attributes ParameterBag
  85. 85. Controller Call flickr.com/taspicsvns/11768808836
  86. 86. Time for your application logic
  87. 87. Return Response object
  88. 88. Optional: The kernel.view event flickr.com/drakegoodman/11006558364
  89. 89. Transform non-Response into Response
  90. 90. e.g. @Template annotation
  91. 91. e.g. transform arrays into JSON Responses
  92. 92. The kernel.response Event flickr.com/drakegoodman/14482752231
  93. 93. Manipulate Response
  94. 94. e.g. WebDebugToolbar
  95. 95. Send Response flickr.com/stuckincustoms/5727003126
  96. 96. The kernel.terminate Event flickr.com/drakegoodman/12203395206
  97. 97. Do the heavy stuff now
  98. 98. e.g. Send Emails
  99. 99. HTTP Cache flickr.com/soldiersmediacenter/403524071
  100. 100. Cache-Control Expires
  101. 101. Cache-Control Expires
  102. 102. $response  =  new  Response();   ! $response-­‐>setPublic();   $response-­‐>setMaxAge(600);   $response-­‐>setSharedMaxAge(600);
  103. 103. Validation
  104. 104. public  function  indexAction(Request  $request,                                                            $name)   {          $response  =  new  Response("Hello  $name");          $response-­‐>setETag(md5($response-­‐>getContent()));          $response-­‐>setPublic();          $response-­‐>isNotModified($request);   !        return  $response;   }
  105. 105. ESI flickr.com/nasamarshall/6950477589
  106. 106. “The ESI specification describes tags you can embed in your pages to communicate with the gateway cache.” Symfony.com
  107. 107. <!DOCTYPE  html>   <html>          <body>          <!-­‐-­‐  ...  content  -­‐-­‐>   !        <!-­‐-­‐  Embed  the  content  of  another  page  -­‐-­‐>          <esi:include  src="http://..."/>   !        <!-­‐-­‐  ...  content  -­‐-­‐>          </body>   </html>
  108. 108. But I don’t have Varnish!
  109. 109. Symfony2 Reverse Proxy flickr.com/zacharyz/3950845049
  110. 110. $kernel  =  new  AppKernel('prod',  false);   $kernel-­‐>loadClassCache();   ! $kernel  =  new  AppCache($kernel);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   $kernel-­‐>terminate($request,  $response);
  111. 111. $kernel  =  new  AppKernel('prod',  false);   $kernel-­‐>loadClassCache();   ! $kernel  =  new  AppCache($kernel);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   $kernel-­‐>terminate($request,  $response);
  112. 112. OK, but are those things actually used outside of Symfony?
  113. 113. flickr.com/tombricker/5709640847 YES!
  114. 114. Drupal 8 phpBB Silex eZ Publish Laravel
  115. 115. Kacper Gunia Software Engineer Symfony Certified Developer PHPers Silesia Thanks!
  116. 116. joind.in/10880

×