72

Symfony internals [english]

Embed Size (px)

DESCRIPTION

Slides from the 'Symfony internals' talk at DeSymfony

Citation preview

Page 1: Symfony internals [english]
Page 2: Symfony internals [english]
Page 3: Symfony internals [english]

Who am I?Who am I?

Raúl Fraile

@raulfraile

PHP/Symfony2 freelance developer

Page 4: Symfony internals [english]

What do I do?What do I do?

Page 5: Symfony internals [english]

SensioLabsSensioLabsConnectConnect

Page 6: Symfony internals [english]

Why?Why?

Page 7: Symfony internals [english]
Page 8: Symfony internals [english]

app[_dev].phpapp[_dev].php

Front controller

Page 9: Symfony internals [english]

app[_dev].phpapp[_dev].php

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

Page 10: Symfony internals [english]

bootstrap.php.cachebootstrap.php.cache

Several classes/interfaces

in the same file

Page 11: Symfony internals [english]

bootstrap.php.cachebootstrap.php.cache

// app/bootstrap.php.cache

namespace { require_once __DIR__.'/autoload.php'; }

namespace Symfony\Component\DependencyInjection{ interface ContainerAwareInterface { function setContainer(ContainerInterface $container = null); } ...}

Page 12: Symfony internals [english]

bootstrap.php.cachebootstrap.php.cache

Reduces I/O operations

Page 13: Symfony internals [english]

bootstrap.php.cachebootstrap.php.cache

Loads autoload.php

Page 14: Symfony internals [english]

autoload.phpautoload.php// app/autoload.php

use Symfony\Component\ClassLoader\UniversalClassLoader;

$loader = new UniversalClassLoader();$loader->registerNamespaces(array( 'Symfony' => array( __DIR__.'/../vendor/symfony/src', __DIR__.'/../vendor/bundles'), 'Assetic' => __DIR__.'/../vendor/assetic/src',));$loader->registerPrefixes(array( 'Twig_' => __DIR__.'/../vendor/twig/lib',));

Page 15: Symfony internals [english]

ClassLoaderClassLoader

Autoloading of

classes/interfaces in

Symfony2

Page 16: Symfony internals [english]

ClassLoader

Page 17: Symfony internals [english]

ClassLoaderClassLoader

Implements PSR-0

Page 18: Symfony internals [english]

PSR-0PSR-0

Approved by the “Framework Interop Group”

github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md

Page 19: Symfony internals [english]

PSR-0PSR-0

Fully Qualified Name

Filesystem

\Symfony\Core\Request\Zend\Mail\Message

[vendor_path]/Symfony/Core/Request.php[vendor_path]/Zend/Mail/Message.php

Page 20: Symfony internals [english]

ClassLoaderClassLoader// namespaced class name$namespace = substr($class, 0, $pos);foreach ($this->namespaces as $ns => $dirs) { if (0 !== strpos($namespace, $ns)) { continue; }

foreach ($dirs as $dir) { $className = substr($class, $pos + 1); $file = $dir . DIR_SEPARATOR . str_replace('\\',DIR_SEPARATOR, $namespace) . DIR_SEPARATOR . str_replace('_', DIR_SEPARATOR, $className) . '.php'; if (file_exists($file)) { return $file; } }}

Page 21: Symfony internals [english]

ClassLoaderClassLoader

$loader->findFile( 'Symfony\Component\HttpFoundation\Request');

/Sites/desymfony/app/../vendor/symfony/src/ Symfony/Component/HttpFoundation/Request.php

Page 22: Symfony internals [english]

app[_dev].phpapp[_dev].php

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

Page 23: Symfony internals [english]

AppKernel.phpAppKernel.php// src/AppKernel.php

use Symfony\Component\HttpKernel\Kernel;use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel{ public function registerBundles() { $bundles = array( new Symfony\Bundle\TwigBundle\TwigBundle(), ... ); return $bundles; }

public function registerContainerConfiguration(LoaderInterface $loader) { $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); }}

Page 24: Symfony internals [english]

app[_dev].phpapp[_dev].php

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

Environment

Debug

Page 25: Symfony internals [english]

AppKernel.phpAppKernel.php

If (true === $debug) {

} else {

Saves initial time (microtime)

display_errors = 1

error_reporting = -1

DebugUniversalClassLoader

}display_errors = 0

Page 26: Symfony internals [english]

app[_dev].phpapp[_dev].php

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

Page 27: Symfony internals [english]

LoadClassCacheLoadClassCache

Objective: map

FQN/filenames of

classes and interfaces

Page 28: Symfony internals [english]

LoadClassCacheLoadClassCache

It is cached in

classes.map and

classes.php.meta

Page 29: Symfony internals [english]

app[_dev].phpapp[_dev].php

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

Page 30: Symfony internals [english]

RequestRequest

HttpFoundation

Component

Page 31: Symfony internals [english]

RequestRequest

OO abstraction of a

HTTP request

Page 32: Symfony internals [english]

RequestRequest

GET /index.php HTTP/1.1␍␊ Host: test.com␍␊ Accept-Language:en;q=0.8␍␊ Accept-Encoding:gzip␍␊ User-Agent: Mozilla/5.0␍␊ ␍␊

$_GET

$_POST

$_COOKIE

$_FILES

$_SERVER

Request

queryrequestcookies

filesserver

headers

getHostgetClientIp

...

Page 33: Symfony internals [english]

app[_dev].phpapp[_dev].php

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

Page 34: Symfony internals [english]

HttpKernelHttpKernel

Wrapper on top of

Request/Response to

handle the dynamic

part of HTTP

Page 35: Symfony internals [english]

HttpKernelHttpKernel

Handles an

environment consisting

of bundles, DIC...

Page 36: Symfony internals [english]

Initialize

bundles and DIC

$kernel->boot()$kernel->boot()

Page 37: Symfony internals [english]

Loads bundles defined in

AppKernel::registerBundles()

$kernel->initializeBundles()$kernel->initializeBundles()

Page 38: Symfony internals [english]

Generated using the

ContainerBuilder from

DependencyInjection

$kernel->initializeContainer()$kernel->initializeContainer()

Page 39: Symfony internals [english]

ContainerBuilderContainerBuilder

// example.com/src/container.phpuse Symfony\Component\DependencyInjection;use Symfony\Component\DependencyInjection\Reference;

$sc = new DependencyInjection\ContainerBuilder(); $sc->register('context', 'Symfony\Component\Routing\RequestContext');$sc->register('matcher', 'Symfony\Component\Routing\Matcher\UrlMatcher') ->setArguments(array($routes, new Reference('context')));

$sc->register('framework', 'Simplex\Framework') ->setArguments(array(new Reference('dispatcher'), new Reference('resolver'))) ;

http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12

Page 40: Symfony internals [english]

{rootDir}{Environment}

[Debug]ProjectContainer

$kernel->initializeContainer()$kernel->initializeContainer()

Page 41: Symfony internals [english]

For each bundle,

Bundle::build() method is

executed and extensions

are loaded

$kernel->initializeContainer()$kernel->initializeContainer()

Page 42: Symfony internals [english]

For each bundle, the

container is injected and

the boot() method is

executed

$kernel->boot()$kernel->boot()

Page 43: Symfony internals [english]

Goal: Return a Response

object

$kernel->handle()$kernel->handle()

Page 44: Symfony internals [english]

Dispatched as soon as

the request arrives

Event kernel.requestEvent kernel.request

Page 45: Symfony internals [english]

Any listener can return

a Response and 'end'

the execution

Event kernel.requestEvent kernel.request

Page 46: Symfony internals [english]

Used by

FrameworkBundle to set

the _controller value

Event kernel.requestEvent kernel.request

Page 47: Symfony internals [english]

Uses a RouterMatcher

(autogenerated by the

Routing component)

RouterListenerRouterListener

Page 48: Symfony internals [english]

RouterListenerRouterListener

// app/cache/dev/appdevUrlMatcher.php

class appdevUrlMatcher extends RedirectableUrlMatcher{ ... public function match($pathinfo) { ... // _demo_hello if (0 === strpos($pathinfo, '/demo/hello') && preg_match('#^/demo/hello/(?P<name>[^/]+?)$#s', $pathinfo, $m)) { return array_merge($this->mergeDefaults($m, array( '_controller' => 'Acme\\DemoBundle\\Controller\\DemoController::helloAction') ), array( '_route' => '_demo_hello')); } ... }

Page 49: Symfony internals [english]

Must return the controller

+ arguments from

_controller

ControllerResolverControllerResolver

Page 50: Symfony internals [english]

Ties components and

libraries together to make

a MVC framework

FrameworkBundleFrameworkBundle

Page 51: Symfony internals [english]

Moreover...

FrameworkBundleFrameworkBundle

Page 52: Symfony internals [english]

php app/console

FrameworkBundleFrameworkBundle

Page 53: Symfony internals [english]

FrameworkBundleFrameworkBundle// app/console

#!/usr/bin/env php<?php

require_once __DIR__.'/bootstrap.php.cache';require_once __DIR__.'/AppKernel.php';

use Symfony\Bundle\FrameworkBundle\Console\Application;use Symfony\Component\Console\Input\ArgvInput;

$input = new ArgvInput();$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');$debug = !$input->hasParameterOption(array('--no-debug', ''));

$kernel = new AppKernel($env, $debug);$application = new Application($kernel);$application->run();

Page 54: Symfony internals [english]

Commands

FrameworkBundleFrameworkBundle

assets:install

cache:clear

cache:warmup

container:debug

router:dump-apache

router:debug

Page 55: Symfony internals [english]

Base Controller

FrameworkBundleFrameworkBundle

Page 56: Symfony internals [english]

FrameworkBundleFrameworkBundle

// src/Acme/DemoBundle/Controller/DemoController

namespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DemoController extends Controller{ public function helloAction($name) { ... }}

Page 57: Symfony internals [english]

And much more: ESI,

WebTestCase,

DataCollectors...

FrameworkBundleFrameworkBundle

Page 58: Symfony internals [english]

Once the controller has

been resolved, this

event is generated

Event kernel.controllerEvent kernel.controller

Page 59: Symfony internals [english]

Any listener can

manipulate the

Controller callable

Event kernel.controllerEvent kernel.controller

Page 60: Symfony internals [english]

This event is called only

if the Controller does

not return a Response

Event kernel.viewEvent kernel.view

Page 61: Symfony internals [english]

Goal: build a Response

object from the return

value of the Controller

Event kernel.viewEvent kernel.view

Page 62: Symfony internals [english]

Allows to modify or

replace the Response

object after its creation

Event kernel.responseEvent kernel.response

Page 63: Symfony internals [english]

Last change to convert a

Exception into a

Response object

Event kernel.exceptionEvent kernel.exception

Page 64: Symfony internals [english]

Extend from KernelEvent

EventsEvents

getRequestType(): MASTER_REQUEST or SUB_REQUEST

getKernel();

getRequest();

Page 65: Symfony internals [english]

HTTP/1.1 200 OK Content-type: text/html Date:Thu, 31 May 2012 17:54:50 GMT

<!DOCTYPE HTML> <html lang="es"> <head> <meta charset="utf-8"> ...

Response

Headers

Version

Content

Status code

Status text

Charset

ResponseResponse

Page 66: Symfony internals [english]

// web/app[_env].php

1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';

3. use Symfony\Component\HttpFoundation\Request;

4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();

app[_dev].phpapp[_dev].php

Page 67: Symfony internals [english]

Send headers and

content

Response::send()Response::send()

Page 68: Symfony internals [english]

Response::send()Response::send()

Page 69: Symfony internals [english]

https://github.com/raulfraile/internals-desymfony2012

DemoDemo

Page 70: Symfony internals [english]

¡Thank you!

Page 71: Symfony internals [english]

http://www.flickr.com/photos/connectirmeli/7233514862

http://www.flickr.com/photos/barretthall/6070677596

http://www.flickr.com/photos/f-oxymoron/5005673112/

PhotosPhotos

Page 72: Symfony internals [english]

Questions?Questions?