DeSymfony 2012: Symfony internals

Post on 18-Dec-2014

2.493 views 0 download

description

Slides de la charla 'Symfony Internals' en DeSymfony 2012

Transcript of DeSymfony 2012: Symfony internals

¿Quién soy?¿Quién soy?

Raúl Fraile

@raulfraile

PHP/Symfony2 freelance developer

¿Qué hago?¿Qué hago?

SensioLabsSensioLabsConnectConnect

¿Por qué?¿Por qué?

app[_dev].phpapp[_dev].php

Controlador frontal

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();

bootstrap.php.cachebootstrap.php.cache

Clases/namespaces en

un único fichero.

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); } ...}

bootstrap.php.cachebootstrap.php.cache

Reduce operaciones I/O

bootstrap.php.cachebootstrap.php.cache

Carga autoload.php

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',));

ClassLoaderClassLoader

Autoload de

clases/interfaces en

Symfony2

ClassLoader

ClassLoaderClassLoader

Implementa PSR-0

PSR-0PSR-0

Aprobado por el “Framework Interop Group”

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

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

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; } }}

ClassLoaderClassLoader

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

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

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();

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'); }}

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();

EnvironmentDebug

AppKernel.phpAppKernel.php

If (true === $debug) {

} else {

Guarda inicio petición (microtime)

display_errors = 1

error_reporting = -1

DebugUniversalClassLoader

}display_errors = 0

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();

LoadClassCacheLoadClassCache

Objetivo: mapear FQN y

paths de las principales

clases/interfaces

LoadClassCacheLoadClassCache

Se cachea en

classes.map y

classes.php.meta

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();

RequestRequest

Componente

HttpFoundation

RequestRequest

Abstracción OO de

una petición HTTP

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

...

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();

HttpKernelHttpKernel

Corazón de Symfony

HttpKernelHttpKernel

Gestiona entorno

formado por bundles,

DIC...

Inicialización de

bundles y DIC

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

Se cargan los bundles

definidos en

AppKernel::registerBundles()

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

Se genera usando el

ContainerBuilder del

DependencyInjection

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

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

{rootDir}{Environment}

[Debug]ProjectContainer

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

Por cada bundle se ejecuta

Bundle::build() y se

registran sus extensiones

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

Por cada bundle se asigna

el 'container' y se ejecuta

el boot()

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

Objetivo: Devolver un

objeto Response

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

Se lanza en cuanto

llega la petición

Evento kernel.requestEvento kernel.request

Un listener puede

devolver un Response

y 'finalizar' la ejecución

Evento kernel.requestEvento kernel.request

FrameworkBundle lo

utiliza para rellenar el

valor de _controller

Evento kernel.requestEvento kernel.request

Utiliza un RouterMatcher

(autogenerado por comp.

Routing)

RouterListenerRouterListener

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')); } ... }

Encargado de devolver un

controlador + argumentos

a partir de _controller

ControllerResolverControllerResolver

Agrupa componentes y

librerías para crear un

framework MVC

FrameworkBundleFrameworkBundle

Además, ofrece...

FrameworkBundleFrameworkBundle

php app/console

FrameworkBundleFrameworkBundle

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();

Comandos

FrameworkBundleFrameworkBundle

assets:install

cache:clear

cache:warmup

container:debug

router:dump-apache

router:debug

Controller

FrameworkBundleFrameworkBundle

FrameworkBundleFrameworkBundle

// src/Acme/DemoBundle/Controller/DemoController

namespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

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

Y mucho más: ESI,

WebTestCase,

DataCollectors...

FrameworkBundleFrameworkBundle

Una vez definido el

controlador, se lanza el

evento

Evento kernel.controllerEvento kernel.controller

Se puede cambiar,

pasando un Callable

Evento kernel.controllerEvento kernel.controller

Se lanza si el Controller

no devuelve un objeto

Response

Evento kernel.viewEvento kernel.view

Objetivo: construir un

objeto Response del

return del Controller

Evento kernel.viewEvento kernel.view

Permite reemplazar o

modificar el objeto

Response

Evento kernel.responseEvento kernel.response

Oportunidad para

convertir una Exception

en un Response

Evento kernel.exceptionEvento kernel.exception

Todos heredan de

KernelEvent

EventosEventos

getRequestType(): MASTER_REQUEST o SUB_REQUEST

getKernel();

getRequest();

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

// 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

Envía las cabeceras y el

contenido

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

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

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

DemoDemo

¡Gracias!

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

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

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

FotografíasFotografías

¿Preguntas?¿Preguntas?