FORGET ABOUT INDEX.PHP BUILD YOUR APPLICATIONS AROUND HTTP!
Kacper Gunia @cakper Software Engineer @SensioLabsUK Symfony Certified Developer PHPers Silesia @PHPersPL
Good old days flickr.com/linkahwai/5162310920
Hello world in PHP“ ” + tutorial
Gojko’s two facts about programming web: 1)Ctrl-C 2)Ctrl-V
<?php   ! $name  =  $_GET['name'];   echo  "Hello  $name!";
It works! :D
but…
and so on… ;)
How HTTP works? flickr.com/see-­‐through-­‐the-­‐eye-­‐of-­‐g/4278744230
Request Kabooooom! Response
This is what HTTP is about! Request Response
This is what Your App is about! Request Response
“(…) the goal of your application is always to interpret a request and create the appropriate response based on your application logic.” Symfony.com
HTTP is simple flickr.com/wildhaber/5936335464
Request flickr.com/haniamir/3318727924
GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000
GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 I want to see…
GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 …this resource!
GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 And I know it should be on localhost
GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 Psst, I’m using 1.1 version of HTTP protocol
Response flickr.com/aftab/3364835006
HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper!
HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! OK man, I’ve found it!
HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! And it’s an HTML
HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! Hello World!
[METH]  [REQUEST-­‐URI]  HTTP/[VER]   [Field1]:  [Value1]   [Field2]:  [Value2]   ! [request  body,  if  any] HTTP/[VER]  [CODE]  [TEXT]   [Field1]:  [Value1]   [Field2]:  [Value2]   ! [response  body] ResponseRequest
What if we create objects from Request & Response?
Object-oriented HTTP flickr.com/mohammadafshar/9571051345
GET  /index.php?name=Kacper  HTTP/1.1   Host:  localhost:8000 $request-­‐>getMethod();      GET   $request-­‐>getPathInfo();  /
HTTP/1.1  200  OK   Host:  localhost:8000   Content-­‐type:  text/html   ! Hello  Kacper! $response-­‐>getStatusCode();  200   $response-­‐>getContent();        Hello  Kacper!
HttpFoundation flickr.com/rubempjr/8050505443
“The HttpFoundation component defines an object-oriented
 layer for the HTTP specification” Symfony.com
Request flickr.com/haniamir/3318727924
$request  =  Request::createFromGlobals();   ! $request  =  new  Request(          $_GET,          $_POST,          array(),          $_COOKIE,          $_FILES,          $_SERVER   );
!        $_GET          $request-­‐>query            $_POST        $request-­‐>request          $_COOKIE    $request-­‐>cookies          $_FILES      $request-­‐>files          $_SERVER    $request-­‐>server   !                            $request-­‐>headers                                $request-­‐>attributes ParameterBag instances
$name  =  isset($_GET['name'])                    ?  $_GET['name']                    :  "World"; $name  =  $request                  -­‐>query                  -­‐>get('name',  'World');
$request-­‐>isSecure(); Verify configured header or standard one
$request-­‐>isXmlHttpRequest(); Verify AJAX request
$request  =  Request::create(                                      '/',                                      'GET',                                      ['name'  =>  'Kacper']                        ); Simulate a Request
Response flickr.com/aftab/3364835006
$response  =  new  Response(          ‘Hello  Kacper!’,          Response::HTTP_OK,          ['content-­‐type'  =>  'text/html']   );   ! $response-­‐>prepare($request);   $response-­‐>send();
$response  =  new  RedirectResponse(
                                'http://example.com/'                          ); Redirect Response
$response  =  new  JsonResponse();   $response-­‐>setData(['name'  =>  'Kacper']); JSON Response
Let’s use them together!
$kernel  =  new  AppKernel('dev',  true);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   ! $kernel-­‐>terminate($request,  $response); Symfony app_dev.php
$kernel  =  new  AppKernel('dev',  true);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   ! $kernel-­‐>terminate($request,  $response); Symfony app_dev.php
Reminds something? ;)
Request Kabooooom! Response
Front Controller flickr.com/cedwardbrice/8334047708
”The Front Controller consolidates all request handling by channeling requests through a single handler object (…)” MartinFowler.com
$kernel  =  new  AppKernel('dev',  true);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   ! $kernel-­‐>terminate($request,  $response);
Let’s go deeper…
HTTP Kernel flickr.com/stuckincustoms/6341844005
“The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher.” Symfony.com
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);   }
How Symfony transforms Request into Response?
Event Dispatcher flickr.com/parksjd/11847079564
“The EventDispatcher component provides tools that allow your application components to communicate with each other by dispatching events and listening to them.” Symfony.com
EventDispatcher is an implementation of Mediator pattern
$dispatcher  =  new  EventDispatcher();   $dispatcher-­‐>addListener(                            'foo.action',                              function  (Event  $event)  {                                    //  do  whatever  you  need   });   ! $event  =  new  Event();   $dispatcher-­‐>dispatch('foo.action',  $event);
The kernel.request Event flickr.com/drakegoodman/13479419575
Manipulate your Request here…
…you can even return a Response!
public  function  onKernelRequest(GetResponseEvent  $event)   {          $request  =  $event-­‐>getRequest();          if  ($request-­‐>query-­‐>get('name')  ===  'Kacper')  {                  $event-­‐>setResponse(                          new  Response("We  don't  like  you!")                  );          }   }
…or e.g. detect device, location…
…and routing is resolved here
The Routing Component flickr.com/checksam/12814058644
“The Routing component maps an HTTP request to a set of configuration variables.” Symfony.com
$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']
$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']
$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']
$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']
$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']
Resolve Controller flickr.com/rightbrainphotography/480979176
interface  ControllerResolverInterface   {          public  function  getController(                                                  Request  $request                                          );   !        public  function  getArguments(                                                  Request  $request,                                                                    $controller                                          );   }
Controller is a PHP callable
The kernel.controller Event flickr.com/drakegoodman/12451824524
Change controller here (if you need)
and initialise data
e.g. parameters conversion happens now
Resolve Arguments flickr.com/joiseyshowaa/2720195951
interface  ControllerResolverInterface   {          public  function  getController(                                                  Request  $request                                          );   !        public  function  getArguments(                                                  Request  $request,                                                                    $controller                                          );   }
Arguments come from $request->attributes ParameterBag
Controller Call flickr.com/taspicsvns/11768808836
Time for your application logic
Return Response object
Optional: The kernel.view event flickr.com/drakegoodman/11006558364
Transform non-Response into Response
e.g. @Template annotation
e.g. transform arrays into JSON Responses
The kernel.response Event flickr.com/drakegoodman/14482752231
Manipulate Response
e.g. WebDebugToolbar
Send Response flickr.com/stuckincustoms/5727003126
The kernel.terminate Event flickr.com/drakegoodman/12203395206
Do the heavy stuff now
e.g. Send Emails
HTTP Cache flickr.com/soldiersmediacenter/403524071
Cache-Control Expires
Cache-Control Expires
$response  =  new  Response();   ! $response-­‐>setPublic();   $response-­‐>setMaxAge(600);   $response-­‐>setSharedMaxAge(600);
Validation
public  function  indexAction(Request  $request,                                                            $name)   {          $response  =  new  Response("Hello  $name");          $response-­‐>setETag(md5($response-­‐>getContent()));          $response-­‐>setPublic();          $response-­‐>isNotModified($request);   !        return  $response;   }
ESI flickr.com/nasamarshall/6950477589
“The ESI specification describes tags you can embed in your pages to communicate with the gateway cache.” Symfony.com
<!DOCTYPE  html>   <html>          <body>          <!-­‐-­‐  ...  content  -­‐-­‐>   !        <!-­‐-­‐  Embed  the  content  of  another  page  -­‐-­‐>          <esi:include  src="http://..."/>   !        <!-­‐-­‐  ...  content  -­‐-­‐>          </body>   </html>
But I don’t have Varnish!
Symfony2 Reverse Proxy flickr.com/zacharyz/3950845049
$kernel  =  new  AppKernel('prod',  false);   $kernel-­‐>loadClassCache();   ! $kernel  =  new  AppCache($kernel);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   $kernel-­‐>terminate($request,  $response);
$kernel  =  new  AppKernel('prod',  false);   $kernel-­‐>loadClassCache();   ! $kernel  =  new  AppCache($kernel);   ! $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   $kernel-­‐>terminate($request,  $response);
OK, but are those things actually used outside of Symfony?
flickr.com/tombricker/5709640847 YES!
Drupal 8 phpBB Silex eZ Publish Laravel
Kacper Gunia Software Engineer Symfony Certified Developer PHPers Silesia Thanks!
joind.in/10880

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