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

Post on 19-Aug-2014

2.668 views 11 download

description

Slides from my talk at Dutch PHP Conference in Amsterdam

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

FORGET ABOUT INDEX.PHPBUILD YOUR APPLICATIONS AROUND HTTP!

Kacper Gunia @cakper Software Engineer @SensioLabsUK

Symfony Certified Developer

PHPers Silesia @PHPersPL

Good old daysflickr.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 simpleflickr.com/wildhaber/5936335464

Requestflickr.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

Responseflickr.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]Res

po

nse

R

equ

est

What if we create objects from Request & Response?

Object-oriented HTTPflickr.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!

HttpFoundationflickr.com/rubempjr/8050505443

“The HttpFoundation component defines an object-orientedlayer for the HTTP

specification”Symfony.com

Requestflickr.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

Responseflickr.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 Controllerflickr.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 Kernelflickr.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 Dispatcherflickr.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 Eventflickr.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 Componentflickr.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 Controllerflickr.com/rightbrainphotography/480979176

interface  ControllerResolverInterface  {          public  function  getController(                                                  Request  $request                                          );  !

       public  function  getArguments(                                                  Request  $request,                                                                            $controller                                          );  }

Controller is a PHP callable

The kernel.controller Eventflickr.com/drakegoodman/12451824524

Change controller here (if you need)

and initialise data

e.g. parameters conversion

happens now

Resolve Argumentsflickr.com/joiseyshowaa/2720195951

interface  ControllerResolverInterface  {          public  function  getController(                                                  Request  $request                                          );  !

       public  function  getArguments(                                                  Request  $request,                                                                            $controller                                          );  }

Arguments come from

$request->attributes ParameterBag

Controller Callflickr.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 Eventflickr.com/drakegoodman/14482752231

Manipulate Response

e.g. WebDebugToolbar

Send Responseflickr.com/stuckincustoms/5727003126

The kernel.terminate Eventflickr.com/drakegoodman/12203395206

Do the heavy stuff now

e.g. Send Emails

HTTP Cacheflickr.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;  }

ESIflickr.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 Proxyflickr.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 8phpBB

SilexeZ Publish

Laravel

Kacper Gunia Software Engineer

Symfony Certified Developer

PHPers Silesia

Thanks!

joind.in/10880