Symfony2 - WebExpo 2010

Preview:

Citation preview

Symfony2 Fabien Potencier

How many of you have already used symfony1?

How many of you have already played with Symfony2?

What is Symfony2?

A set of decoupled and cohesive components

DependencyInjection EventDispatcher HttpFoundation OutputEscaper

DomCrawler CssSelector Templating HttpKernel BrowserKit Validator Routing Console Process Finder Form Yaml

git clone git://github.com/symfony/symfony.git

A set of decoupled and cohesive components

Autoloading

PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php

Swift_Mime_Message > Swift/Mime/Message.php Twig_Node_For > Twig/Node/For.php

Symfony\Foundation\Kernel Symfony/Foundation/Kernel.php

Doctrine\DBAL\Driver Doctrine/DBAL/Driver.php

pdepend\reflection\ReflectionSession pdepend/reflection/ReflectionSession.php

http://groups.google.com/group/php-standards/web/psr-0-final-proposal  

require_once '.../Symfony/Framework/UniversalClassLoader.php';

use Symfony\Framework\UniversalClassLoader;

$loader = new UniversalClassLoader(); $loader->register();

PHP 5.3 technical interoperability standards

$loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', 'pdepend' => '/path/to/reflection/source', ));

$loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', ));

PEAR style

A set of decoupled and cohesive components

Process

use Symfony\Component\Process\Process;

$cmd = 'ssh 1.2.3.4 "ps waux"';

$process = new Process($cmd); $process->run();

if (!$process->isSuccessful()) { throw new \RuntimeException( $process->getErrorOutput()); }

echo $process->getOutput();

$cmd = 'ssh 1.2.3.4 "tail -f /some/log"';

$process = new Process($cmd);

$process->run(function ($type, $buffer) { echo $buffer; });

use Symfony\Component\Process\PhpProcess;

$process = new PhpProcess( '<?php echo "hello"; ?>'); $process->run();

if (!$process->isSuccessful()) { throw new \RuntimeException( $process->getErrorOutput()); }

echo $process->getOutput();

A set of decoupled and cohesive components

CssSelector

use Symfony\Component\CssSelector\Parser;

Parser::cssToXpath('h4 > a:contains("foo")');

use Symfony\Component\CssSelector\Parser;

$document = new \DOMDocument(); $document->loadHTMLFile('...'); $xpath = new \DOMXPath($document);

$expr = Parser::cssToXpath('a.smart'); $nodes = $xpath->query($expr);

foreach ($nodes as $node) { printf("%s (%s)\n", $node->nodeValue, $node->getAttribute('href')); }

A set of decoupled and cohesive components

Finder

use Symfony\Component\Finder\Finder;

$finder = new Finder(); $finder ->files() ->in(__DIR__) ->...() ->sortByName() ;

$finder ->name('*.php') ->depth('<= 1') ->date('>= yesterday') ->size('<= 1K') ->filter(function (\SplFileInfo $file) { return strlen($file->getBasename()) < 9; }) ;

foreach ($finder as $file) { print $file->getRealpath()."\n"; }

$files = iterator_to_array($finder);

$count = iterator_count($finder);

use Symfony\Component\Finder\Finder;

$s3 = new \Zend_Service_Amazon_S3($key, $sct); $s3->registerStreamWrapper("s3");

$finder = new Finder(); $finder ->name('photos*') ->size('< 100K') ->date('since 1 hour ago') ->in('s3://bucket-name') ;

A set of decoupled and cohesive components

Routing

/blog.php?section=symfony&article_id=18475

web/ index.php

/index.php/blog/2010/09/18/Symfony2-in-India

/blog/2010/09/18/Symfony2-in-India

/blog/:year/:month/:day/:slug

post: pattern: /blog/:year/:month/:day/:slug defaults: { _controller: BlogBundle:Post:show }

<routes> <route id="post" pattern="/blog/:year/:month/:day/:slug"> <default key="_controller"> BlogBundle:Post:show </default> </route> </routes>

use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route;

$collection = new RouteCollection();

$route = new Route( '/blog/:year/:month/:day/:slug', array('_controller' => 'BlogBundle:Post:show'));

$collection->addRoute('post', $route);

return $collection;

$router ->match('/blog/2010/09/18/Symfony2-in-India')

$router ->generate('post', array('slug' => '...'))

post: pattern: /post/:slug defaults: { _controller: BlogBundle:Post:show }

$router ->generate('post', array('slug' => '...'))

An Object-Oriented abstraction on top of PHP

An Object-Oriented abstraction on top of PHP

Request

use Symfony\Component\HttpFoundation\Request;

$request = new Request();

// get a $_GET parameter $request->query->get('page');

// get a $_POST parameter $request->request->get('page');

// get a $_COOKIE parameter $request->cookies->get('name');

$request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest();

// get a $_FILE parameter $f = $request->files->get('image');

// $f is an instance of // Symfony\Component\HttpFoundation\File\UploadedFile

// guess extension, based on the mime type $n = '/path/to/file'.$file->getDefaultExtension(); $f->move($n);

new Request();

new Request( $_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER );

Request::create('/hello/Fabien', 'GET');

An Object-Oriented abstraction on top of PHP

Session

$session = $request->getSession();

$session->set('foo', 'bar'); $session->get('foo');

$session->setFlash('notice', 'Congratulations!');

An Object-Oriented abstraction on top of PHP

Response

use Symfony\Component\HttpFoundation\Response;

$response = new Response('Hello World', 200, array('Content-Type' => 'text/plain')); $response->send();

$response->setHeader('Content-Type', 'text/plain'); $response->setCookie('foo', 'bar'); $response->setContent('Hello World'); $response->setStatusCode(200);

An Object-Oriented abstraction of the HTTP dialog

A MVC Web Framework

The Symfony2 MVC Philosophy

Be as easy as possible for newcomers and as flexible as possible for advanced users

MVC

http://symfony-reloaded.org/

http://symfony-reloaded.org/downloads/sandbox_2_0_PR3.zip

post: pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index }

namespace Application\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller;

class HelloController extends Controller { public function indexAction($name) { return new Response('Hello '.$name); } }

namespace Application\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller;

class HelloController extends Controller { public function indexAction($name) { // Get things from the Model

return $this->render( 'HelloBundle:Hello:index', array('name' => $name) ); } }

Hello <?php echo $name ?>!

<?php $view->extend('HelloBundle::layout') ?>

Hello <?php echo $name ?>!

<html> <head> <title> <?php $view['slots']->output('title') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus,  in  pulvinar  lectus  rutrum  sit  amet.  Duis  gravida,  metus  in  dictum  eleifend,  dolor  risus  ;ncidunt  ligula,  non  volutpat  nulla  sapien  in  elit.  Nulla  rutrum  erat  id  neque  suscipit  eu  ultricies  odio  sollicitudin.  Aliquam  a  mi  vel  eros  placerat  hendrerit.  Phasellus  por6tor,  augue  sit  amet  vulputate  venena;s,  dui  leo  commodo  odio,  a  euismod  turpis  ligula  in  elit.    

_content

title

layout

slot

slot

{% extends "HelloBundle::layout" %}

{% block content %} Hello {{ name }}! {% endblock %}

<html> <head> <title> {% block title %}{% endblock %} </title> </head> <body> {% block body %}{% endblock %} </body> </html>

~ PAC / HMVC

http://en.wikipedia.org/wiki/Presentation-abstraction-control

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus.  

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus,  in  pulvinar  lectus  rutrum  sit  amet.  Duis  gravida,  metus  in  dictum  eleifend,  dolor  risus  ;ncidunt  ligula,  non  volutpat  nulla  sapien  in  elit.  Nulla  rutrum  erat  id  neque  suscipit  eu  ultricies  odio  sollicitudin.  Aliquam  a  mi  vel  eros  placerat  hendrerit.  Phasellus  por6tor,  augue  sit  amet  vulputate  venena;s,  dui  leo  commodo  odio,  a  euismod  turpis  ligula  in  elit.    

main controller (_content slot)

embedded MVC controller

layout

public function indexAction($name) { $embedded = $this['controller_resolver'] ->render('HelloBundle:Hello:foo', array('name' => $name));

return $this->render( 'HelloBundle:Hello:index', array( 'name' => $name, 'embedded' => $embedded, ) ); }

<?php $view->extend('...:layout') ?>

Lorem ipsum...

<?php echo $view['actions'] ->render('HelloBundle:Hello:foo', array('name' => $name)) ?>

Lorem ipsum...

Bundles

.../ SomeBundle/ Controller/ Entity/ Resources/ config/ views/ SomeBundle.php Tests/

public function registerBundleDirs() { return array( 'Application' => __DIR__.'/../src/Application', 'Bundle' => __DIR__.'/../src/Bundle', 'Symfony\Bundle' => __DIR__.'/../src/vendor/symfony/src/Symfony/Bundle', ); }

$this->render('SomeBundle:Hello:index', $params)

hello: pattern: /hello/:name defaults: { _controller: SomeBundle:Hello:index }

SomeBundle can be any of

Application\SomeBundle Bundle\SomeBundle Symfony\Bundle\SomeBundle

Environments

Developers Customer End Users

Development Environment

Staging Environment

Production Environment

cache cache cache

debug   debug   debug  

logs   logs   logs  

stats stats stats

Development Environment

Staging Environment

Production Environment

# config/config.yml doctrine.dbal: dbname: mydbname user: root password: %doctrine.dbal_password%

swift.mailer: transport: smtp host: localhost

# config/config_dev.yml imports: - { resource: config.yml }

doctrine.dbal: password: null

swift.mailer: transport: gmail username: xxxxxxxx password: xxxxxxxx

# Doctrine Configuration doctrine.dbal: dbname: xxxxxxxx user: xxxxxxxx password: ~

# Swiftmailer Configuration swift.mailer: transport: smtp encryption: ssl auth_mode: login host: smtp.gmail.com username: xxxxxxxx password: xxxxxxxx

<!-- Doctrine Configuration --> <doctrine:dbal dbname="xxxxxxxx" user="xxxxxxxx" password="" />

<!-- Swiftmailer Configuration --> <swift:mailer transport="smtp" encryption="ssl" auth_mode="login" host="smtp.gmail.com" username="xxxxxxxx" password="xxxxxxxx" />

// Doctrine Configuration $container->loadFromExtension('doctrine', 'dbal', array( 'dbname' => 'xxxxxxxx', 'user' => 'xxxxxxxx', 'password' => '', ));

// Swiftmailer Configuration $container->loadFromExtension('swift', 'mailer', array( 'transport' => "smtp", 'encryption' => "ssl", 'auth_mode' => "login", 'host' => "smtp.gmail.com", 'username' => "xxxxxxxx", 'password' => "xxxxxxxx", ));

Dependency Injection Container

Third-party libraries integration Unified Configuration

# Twig Configuration twig.config: auto_reload: true

# Zend Logger Configuration zend.logger: priority: debug path: %kernel.root_dir%/logs/%kernel.environment%.log

Configuration formats XML, YAML, PHP, INI, or Annotations

Parameters management Fast (cached) Inheritance

Sensitive data security …

<doctrine:dbal dbname="sfweb" username="root" password="SuperSecretPasswordThatAnyoneCanSee" />

SetEnv SYMFONY__DOCTRINE__DBAL__PASSWORD "foobar"

in a .htaccess or httpd.conf file

%doctrine.dbal.password%

<doctrine:dbal dbname="sfweb" username="root" password="%doctrine.dbal.password%" />

Developer Tools

INFO: Matched route "blog_home" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'index', '_route' => 'blog_home',))

INFO: Using controller "Bundle\BlogBundle\Controller\PostController::indexAction"

INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ ORDER BY s0_.published_at DESC LIMIT 10 (array ())

INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',))

INFO: Using controller "Bundle\BlogBundle\Controller\PostController::showAction »

INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught Symfony\Components\RequestHandler\Exception\NotFoundHttpException exception)

INFO: Using controller "Symfony\Framework\WebBundle\Controller\ExceptionController::exceptionAction"

DEBUG: Notifying (until) event "core.request" to listener "(Symfony\Framework\WebBundle\Listener\RequestParser, resolve)" INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) DEBUG: Notifying (until) event "core.load_controller" to listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" INFO: Using controller "Bundle\BlogBundle\Controller\PostController::showAction" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" processed the event "core.load_controller" INFO: Trying to get post "3456" from database INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) DEBUG: Notifying (until) event "core.exception" to listener "(Symfony\Framework\WebBundle\Listener\ExceptionHandler, handle)" ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught Symfony\Components\RequestHandler\Exception\NotFoundHttpException exception) DEBUG: Notifying (until) event "core.request" to listener "(Symfony\Framework\WebBundle\Listener\RequestParser, resolve)" DEBUG: Notifying (until) event "core.load_controller" to listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" INFO: Using controller "Symfony\Framework\WebBundle\Controller\ExceptionController::exceptionAction" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" processed the event "core.load_controller" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Listener\ResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\DataCollector\DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\WebDebugToolbar, handle)" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ExceptionHandler, handle)" processed the event "core.exception" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Listener\ResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\DataCollector\DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\WebDebugToolbar, handle)"

Security

XSS / CSRF / SQL Injection

Functional Tests

$client = $this->createClient();

$crawler = $client->request( 'GET', '/hello/Fabien');

$this->assertTrue($crawler->filter( 'html:contains("Hello Fabien")')->count());

$this->assertEquals( 10, $crawler->filter('div.hentry')->count());

$this->assertTrue( $client->getResponse()->isSuccessful());

$crawler = $client->request( 'GET', 'hello/Lucas' );

$link = $crawler->selectLink("Greet Lucas");

$client->click($link);

$form = $crawler->selectButton('submit');

$client->submit($form, array( 'name' => 'Lucas', 'country' => 'France', 'like_symfony' => true, 'photo' => '/path/to/lucas.jpg', ));

$harry = $this->createClient(); $sally = $this->createClient();

$harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages');

$this->assertEquals(201, $harry->getResponse()->getStatusCode());

$this->assertRegExp('/Hello/', $sally->getResponse()->getContent());

$harry = $this->createClient(); $sally = $this->createClient();

$harry->insulate(); $sally->insulate();

$harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages');

$this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());

Caching

HTTP Expiration / HTTP Validation

$response->setSharedMaxAge(...); $response->setTtl(...); $response->setMaxAge(...); $response->setClientTtl(...); $response->setExpires(...);

$response->setETag(...); $response->setLastModified(...);

Cache-Control: s-maxage=10

public function showAction() { // ...

$response = $this->render('...', $vars);

$response->setSharedMaxAge(10);

return $response; }

Symfony 2 comes built-in with an HTTP accelerator

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus.  

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus,  in  pulvinar  lectus  rutrum  sit  amet.  Duis  gravida,  metus  in  dictum  eleifend,  dolor  risus  ;ncidunt  ligula,  non  volutpat  nulla  sapien  in  elit.  Nulla  rutrum  erat  id  neque  suscipit  eu  ultricies  odio  sollicitudin.  Aliquam  a  mi  vel  eros  placerat  hendrerit.  Phasellus  por6tor,  augue  sit  amet  vulputate  venena;s,  dui  leo  commodo  odio,  a  euismod  turpis  ligula  in  elit.    

cacheable for 10 seconds cacheable for 5 seconds

main controller

embedded controller

layout

<?php $view->extend('...:layout') ?>

<?php $view['slots']->start('sidebar') ?>

<?php echo $view['actions']->render('...:foo') ?>

<?php $view['slots']->stop() ?>

cacheable for 10 seconds

cacheable for 5 seconds

$view['actions']->render('HelloBundle:Hello:foo', array('name' => $name), array('standalone' => true) )

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus.  

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus,  in  pulvinar  lectus  rutrum  sit  amet.  Duis  gravida,  metus  in  dictum  eleifend,  dolor  risus  ;ncidunt  ligula,  non  volutpat  nulla  sapien  in  elit.  Nulla  rutrum  erat  id  neque  suscipit  eu  ultricies  odio  sollicitudin.  Aliquam  a  mi  vel  eros  placerat  hendrerit.  Phasellus  por6tor,  augue  sit  amet  vulputate  venena;s,  dui  leo  commodo  odio,  a  euismod  turpis  ligula  in  elit.    

Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  In  vel  nulla  arcu,  vitae  cursus  nunc.  Integer  semper  turpis  et  enim  por6tor  iaculis.  Nulla  facilisi.  Lorem  ipsum  dolor  sit  amet,  consectetur  adipiscing  elit.  Mauris  vehicula  ves;bulum  dictum.  Aenean  non  velit  tortor.  Nullam  adipiscing  malesuada  aliquam.  Mauris  dignissim,  urna  quis  iaculis  tempus,  justo  libero  por6tor  est,  nec  eleifend  est  elit  vitae  ante.  Curabitur  interdum  luctus  metus,  in  pulvinar  lectus  rutrum  sit  amet.  Duis  gravida,  metus  in  dictum  eleifend,  dolor  risus  ;ncidunt  ligula,  non  volutpat  nulla  sapien  in  elit.  Nulla  rutrum  erat  id  neque  suscipit  eu  ultricies  odio  sollicitudin.  Aliquam  a  mi  vel  eros  placerat  hendrerit.  Phasellus  por6tor,  augue  sit  amet  vulputate  venena;s,  dui  leo  commodo  odio,  a  euismod  turpis  ligula  in  elit.    

<esi:include src="..." />

ESI… or Edge Side Includes

Symf

ony2

Appli

catio

n

Reve

rse Pr

oxy

Clien

t Lorem  ipsum  dolor  sit  amet,    

Lorem  ipsum  dolor  

Lorem  ipsum  dolor  sit  amet,    

Lorem  ipsum  dolor  

1

2

3

4

Symfony2 app

Web Server

Requests

Response

Symfony2 app

Symfony2 HTTP proxy

Web Server

Requests

Response

Symfony2 app

Web Server

Reverse proxy

Requests

Response

Extensibility

Request

Response

core.controller

core.response

core.view

core.request

getController()

getArguments()

Request

Response

core.controller

core.response

core.view

core.request

getController()

getArguments()

core.exception

HttpFoundation

HttpKernel

FrameworkBundle

Routing

Console

SwiftmailerBundle

TwigBundle

DependencyInjection

...

...

Components

Bundles

Event Dispatcher

Templating

DoctrineBundle

ZendBundle

Questions?