Symfony 2
Fabien Potencier
             Symfony 2 | Fabien Potencier
Who am I?
•  Founder of Sensio
   – Web Agency (France and USA)
   – Since 1998
   – 70 people
   – Open-Source Specialist...
How many of you have used symfony?
               1.0? 1.1? 1.2?


       Symfony 2 | Fabien Potencier
symfony 1.0 – January 2007

•  Started as a glue between existing Open-Source libraries:
   – Mojavi (heavily modified), Pr...
symfony 1.2 – November 2008


•  Decoupled but cohesive components: the symfony platform

    –  Forms, Routing, Cache, YA...
Roadmap

•  1.0 – January 2007
•  1.1 – June 2008
•  1.2 – November 2008
•  1.3 – November 2009
•  Version 2.0 …
•  1.4 – ...
symfony platform
                                                             >= 1.1

                                    ...
Symfony Components
•  Standalone components
•  Packaged individually
•  Upcoming dedicated website
     –  http://componen...
Symfony 2 is an evolution of symfony 1


•  Same Symfony platform / components

•  Different controller implementation

•  ...
Symfony 2 main goals


                           Flexibility
                                        Fast
               ...
Symfony 2: New components


     Dependency Injection Container
            Templating Framework
                 Controll...
Symfony 2

•  Not yet available as a full-stack MVC framework
•  Some components have already been merged into Symfony 1
 ...
symfony 1: Not fast enough?

          Symfony 2 | Fabien Potencier
symfony 1 is
  one of the slowest framework
     when you test it against
a simple Hello World application
     Symfony 2 ...
1644&

1544&               !"#$%&!'!&

1344&

1144&

1444&

 ;44&
                                                        ...
Conclusion?




Symfony 2 | Fabien Potencier
Don’t use symfony
 for your next « Hello World » website

                        Use PHP ;)



Symfony 2 | Fabien Potenci...
By the way,

      the fastest implemention
of a Hello World application with PHP:

   die('Hello World');

Symfony 2 | Fa...
But symfony 1 is probably fast enough
        for your next website


     Symfony 2 | Fabien Potencier
… anyway, it is fast enough for Yahoo!

Yahoo! Bookmarks                       sf-to.org/bookmarks

Yahoo! Answers        ...
… and recently
   dailymotion.com announced
     its migration to Symfony

       sf-to.org/dailymotion


Symfony 2 | Fabi...
Second most popular video sharing website
  One of the top 50 websites in the world
     42 million unique users in Decemb...
…and of course
many other smaller websites…



Symfony 2 | Fabien Potencier
Symfony 2: Faster?

          Symfony 2 | Fabien Potencier
Symfony 2 core is so light and flexible
   that you can easily customize it
  to have outstanding performance
     for a He...
Symfony 2 core is so light and flexible
      that its raw performance
            is outstanding


     Symfony 2 | Fabien...
require_once dirname(__FILE__).'/sf20/autoload2/sfCore2Autoload.class.php';
sfCore2Autoload::register();

$app = new Hello...
7922&

7822&   !"#$%&!'!&                                                     Hello World
                                ...
7 times faster ?!



 You won’t have such a difference for real applications
        as most of the time, the limiting fact...
Twitto ?!

            Symfony 2 | Fabien Potencier
Twitto: The PHP framework that fits in a tweet

•  The fastest framework around?
•  Uses some PHP 5.3 new features
•  It al...
Don’t use Twitto for your next website
            It is a joke ;)


     Symfony 2 | Fabien Potencier
7 times faster ?!

•  But raw speed matters because
   – It demonstrates that the core « kernel » is very light
   – It al...
symfony platform
                                                                            2.0



  sfRequestHandler    ...
Symfony 2 kernel:
The Request Handler
         Symfony 2 | Fabien Potencier
Symfony 2 secret weapon:
The Request Handler
         Symfony 2 | Fabien Potencier
The Request Handler

•  The backbone of Symfony 2 controller implementation
•  Class to build web frameworks, not only MVC...
The Request Handler

$handler = new
sfRequestHandler($dispatcher);

$request = new
sfWebRequest($dispatcher);
$response = ...
The Request Handler

•  The sfRequestHandler does several things:
    – Notify events
    – Execute a callable (the contro...
class sfRequestHandler
{
  protected $dispatcher = null;

    public function __construct(sfEventDispatcher $dispatcher)
 ...
Request Handler Events

  application.request
  application.load_controller
  application.controller
  application.view
  ...
application.response




 As the very last event notified, a listener can modify the
    Response object just before it is ...
application.request



•  The very firstevent notified

•  It can act as a short-circuit event

•  If one listener returns a...
application.load_controller


•  Only event for which at least one listener must be connected to

•  A listener must retur...
application.view




    The controller must return a Response object
            except if a listener can convert
       ...
application.exception




   The request handler catches all exceptions
          and give a chance to listeners
         ...
Request Handler

•  Several listeners can be attached to a single event
•  Listeners are called in turn
                  ...
require_once dirname(__FILE__).'/sf20/autoload2/sfCore2Autoload.class.php';
sfCore2Autoload::register();

$app = new Hello...
require_once '/path/to/sfCore2Autoload.class.php';
sfCore2Autoload::register();




           Symfony 2 | Fabien Potencier
$app = new HelloApplication();
$app->run()->send();




        Symfony 2 | Fabien Potencier
public function __construct()
 {
   $this->dispatcher = new sfEventDispatcher();
   $this->dispatcher->connect(
      'app...
public function loadController(sfEvent $event)
 {
   $event->setReturnValue(array(
    array($this, 'hello'),
    array($t...
public function hello($dispatcher, $request)
 {
   $response = new sfWebResponse($dispatcher);
   $response->setContent('H...
public function run()
 {
   $request = new sfWebRequest($this->dispatcher);
   $handler = new sfRequestHandler($this->disp...
Case study: dailymotion.com

•  The problem: the Dailymotion developers add new features on a
   nearly everyday basis
•  ...
Symfony 2: The Templating Framework

         Symfony 2 | Fabien Potencier
New Templating Framework

•  4 components
   – Template Engine
   – Template Renderers
   – Template Loaders
   – Template...
require_once '/path/to/sfCore2Autoload.class.php';
sfCore2Autoload::register();

$dispatcher = new sfEventDispatcher();

$...
Template Loaders

•  No assumption about where and how templates are to be found
   – Filesystem
   – Database
   – Memory...
Template Renderers

•  No assumption about the format of the templates
•  Template names are prefixed with the renderer nam...
Template Embedding



Hello <?php echo $name ?>

<?php $this->render('embedded', array('name' => $name)) ?>

<?php $this->...
Template Inheritance

<?php $this->decorator('layout') ?>
Hello <?php echo $name ?>
<html>
  <head>
  </head>
  <body>
   ...
Template Slots
<html>
  <head>
    <title><?php $this->output('title') ?></title>
  </head>
  <body>
    <?php $this->outp...
Template Multiple Inheritance



         A layout can be decorated by another layout

                   Each layout can ...
Templating: An example

         Symfony 2 | Fabien Potencier
CMS Templating

•  Imagine a CMS with the following features:
   – The CMS comes bundled with default templates
   – The d...
CMS Templating

•  The CMS has several built-in sections and pages
   – Each page is decorated by a layout, depending on t...
articles/content.php



<h1>{{ title }}</h1>

<p>
  {{ content }}
</p>

        Symfony 2 | Fabien Potencier
articles/article.php


<?php $this->decorator('articles/layout') ?>
<?php $this->set('title', $title) ?>
<?php echo $this-...
articles/layout.php


<?php $this->decorator('base') ?>

<?php $this->set('title', 'Articles | '.$this->get('title')) ?>

...
articles/layout.php




<?php $this->decorator('base') ?>

<?php $this->set('title', 'Articles | '.$this->get('title')) ?>...
base.php
<html>
  <head>
    <title>
      <?php $this->output('title') ?>
    </title>
    <?php $this->output('head') ?>...
Template Renderer



$t = new sfTemplateEngine($dispatcher, $loader, array(
  'user' => new ProjectTemplateRenderer($dispa...
Template Renderer
class ProjectTemplateRenderer extends sfTemplateRenderer
{
  public function evaluate($template, array $...
Template Loaders



$loader = new sfTemplateLoaderFilesystem($dispatcher,
  array(
    '/path/to/project/templates/%s.php'...
Template Loader Chain


$loader = new sfTemplateLoaderChain($dispatcher, array(
  new ProjectTemplateLoader(
    $dispatch...
Database Template Loader
class ProjectTemplateLoader extends sfTemplateLoader
{
  public function load($template)
  {
    ...
Database Template Loader



$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE tpl (name, tpl)');
$pdo->exec('INS...
Template Loader Cache



$loader = new sfTemplateLoaderCache(
  $dispatcher,
  $loader,
  new sfFileCache(array('dir' => '...
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE tpl (name, tpl)');
$pdo->exec('INSERT INTO tpl (name, tpl) VAL...
Symfony 2: Dependency Injection Container

          Symfony 2 | Fabien Potencier
« Dependency Injection is where components
 are given their dependencies through their
    constructors, methods, or direc...
The Symfony 2 dependency injection container
replaces several symfony 1 concepts
into one integrated system:

   – sfConte...
DI Hello World example
class Message
{
  public function __construct(OutputInterface $output, array $options)
  {
    $thi...
DI Hello World example
interface OutputInterface
{
  public function render($msg);
}

class Output implements OutputInterf...
DI Hello World example




$output = new FancyOutput();
$message = new Message($output, array('with_newline' => true));
$m...
A DI container facilitates
objects description and object relationships,
    configures and instantiates objects


       S...
DI Container Hello World example


$container = new sfServiceContainerBuilder();

$container->register('output', 'FancyOut...
$message = $container->message;


           Get the configuration for the message service

     The Message constructor mu...
$message = $container->message;


                        is roughly equivalent to

                  $output = new FancyO...
$container = new sfServiceContainerBuilder();

$container->register('output', 'FancyOutput');
$container->
  register('mes...
$container = new sfServiceContainerBuilder();

$container->register('output', 'FancyOutput');
$container->
  register('mes...
<container>
  <parameters>
    <parameter key="output.class">FancyOutput</parameter>
    <parameter key="message.options" ...
<container>
  <imports>
    <import resource="config.xml" />
  </imports>

  <services>
    <service id="output" class="%o...
<services>
 <import resource="config.yml" class="sfServiceLoaderFileYaml" />

  <service id="output" class="%output.class%...
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE tpl (name, tpl)');
$pdo->exec('INSERT INTO tpl (name, tpl) VAL...
$pdo = new PDO('sqlite::memory:');



<service id="pdo" class="PDO">
  <argument>sqlite::memory:</argument>
</service>



...
$container = new sfServiceContainerBuilder();
$loader = new sfServiceLoaderFileXml($container);
$loader->load('cms.xml');
...
<container>
  <imports>
    <import resource="config.yml" class="sfServiceLoaderFileYaml" />
    <import resource="templat...
<services>
  <service id="template_loader_project" class="ProjectTemplateLoader">
    <argument type="service" id="event_d...
<services>
  <service id="template_loader" class="sfTemplateLoaderCache" lazy="true">
    <argument type="service" id="eve...
Symfony 2 | Fabien Potencier
Questions?

         Symfony 2 | Fabien Potencier
Sensio S.A.
                     92-98, boulevardVictor Hugo
                         92 115 Clichy Cedex
                ...
Upcoming SlideShare
Loading in...5
×

Symfony Live 09 Symfony 2

3,354

Published on

0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,354
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

Symfony Live 09 Symfony 2

  1. 1. Symfony 2 Fabien Potencier Symfony 2 | Fabien Potencier
  2. 2. Who am I? •  Founder of Sensio – Web Agency (France and USA) – Since 1998 – 70 people – Open-Source Specialists – Big corporate customers – Consulting, training, development, web design, … – Main sponsor of symfony and Doctrine •  Creator and lead developer of symfony Symfony 2 | Fabien Potencier
  3. 3. How many of you have used symfony? 1.0? 1.1? 1.2? Symfony 2 | Fabien Potencier
  4. 4. symfony 1.0 – January 2007 •  Started as a glue between existing Open-Source libraries: – Mojavi (heavily modified), Propel, Prado i18n, … •  Borrowed concepts from other languages and frameworks: – Routing, CLI, functional tests, YAML, Rails helpers… •  Added new concepts to the mix – Web Debug Toolbar, admin generator, configuration cascade, … Symfony 2 | Fabien Potencier
  5. 5. symfony 1.2 – November 2008 •  Decoupled but cohesive components: the symfony platform –  Forms, Routing, Cache, YAML, ORMs, … •  Controller still based on Mojavi –  View, Filter Chain, … Symfony 2 | Fabien Potencier
  6. 6. Roadmap •  1.0 – January 2007 •  1.1 – June 2008 •  1.2 – November 2008 •  1.3 – November 2009 •  Version 2.0 … •  1.4 – Last 1.X version – same as 1.3 but with all deprecated features removed Symfony 2 | Fabien Potencier
  7. 7. symfony platform >= 1.1 2.0 sfRequest sfRouting sfLogger sfI18N sfUser sfResponse sfYAML sfDatabase sfForm sfEventDispatcher sfStorage sfCache sfOutputEscaper sfValidator sfWidget sfCoreAutoload platform Symfony 2 | Fabien Potencier
  8. 8. Symfony Components •  Standalone components •  Packaged individually •  Upcoming dedicated website –  http://components.symfony-project.org/ •  Dedicated section for each component •  Dedicated documentation •  Dedicated Subversion repository –  http://svn.symfony-project.com/components/ •  Git mirror –  http://github.com/fabpot •  Already published components: –  YAML, Dependency Injection, Event Dispatcher Symfony 2 | Fabien Potencier
  9. 9. Symfony 2 is an evolution of symfony 1 •  Same Symfony platform / components •  Different controller implementation •  Oh! Symfony now takes a capital S!!! Symfony 2 | Fabien Potencier
  10. 10. Symfony 2 main goals Flexibility Fast Smart Symfony 2 | Fabien Potencier
  11. 11. Symfony 2: New components Dependency Injection Container Templating Framework Controller Handling Symfony 2 | Fabien Potencier
  12. 12. Symfony 2 •  Not yet available as a full-stack MVC framework •  Some components have already been merged into Symfony 1 –  Event Dispatcher –  Form Framework •  Other new components will soon be released as standalone components: –  Controller Handling –  Templating Framework –  Dependency Injection Container (done) Symfony 2 | Fabien Potencier
  13. 13. symfony 1: Not fast enough? Symfony 2 | Fabien Potencier
  14. 14. symfony 1 is one of the slowest framework when you test it against a simple Hello World application Symfony 2 | Fabien Potencier
  15. 15. 1644& 1544& !"#$%&!'!& 1344& 1144& 1444& ;44& x 19.5 :44& 944& 844& Hello World 744& 644& Benchmark 544& 344& ()"#*& x 2.3 144& +,& -./0)%.&123& 4& based on numbers from http://paul-m-jones.com/?p=315 Symfony 2 | Fabien Potencier
  16. 16. Conclusion? Symfony 2 | Fabien Potencier
  17. 17. Don’t use symfony for your next « Hello World » website Use PHP ;) Symfony 2 | Fabien Potencier
  18. 18. By the way, the fastest implemention of a Hello World application with PHP: die('Hello World'); Symfony 2 | Fabien Potencier
  19. 19. But symfony 1 is probably fast enough for your next website Symfony 2 | Fabien Potencier
  20. 20. … anyway, it is fast enough for Yahoo! Yahoo! Bookmarks sf-to.org/bookmarks Yahoo! Answers sf-to.org/answers delicious.com sf-to.org/delicious Symfony 2 | Fabien Potencier
  21. 21. … and recently dailymotion.com announced its migration to Symfony sf-to.org/dailymotion Symfony 2 | Fabien Potencier
  22. 22. Second most popular video sharing website One of the top 50 websites in the world 42 million unique users in December Symfony 2 | Fabien Potencier
  23. 23. …and of course many other smaller websites… Symfony 2 | Fabien Potencier
  24. 24. Symfony 2: Faster? Symfony 2 | Fabien Potencier
  25. 25. Symfony 2 core is so light and flexible that you can easily customize it to have outstanding performance for a Hello World application Symfony 2 | Fabien Potencier
  26. 26. Symfony 2 core is so light and flexible that its raw performance is outstanding Symfony 2 | Fabien Potencier
  27. 27. require_once dirname(__FILE__).'/sf20/autoload2/sfCore2Autoload.class.php'; sfCore2Autoload::register(); $app = new HelloApplication(); Hello World $app->run()->send(); class HelloApplication 0 h Symfony 2. { public function __construct() { wit $this->dispatcher = new sfEventDispatcher(); $this->dispatcher->connect('application.load_controller', array($this, 'loadController')); } public function run() { $request = new sfWebRequest($this->dispatcher); $handler = new sfRequestHandler($this->dispatcher); $response = $handler->handle($request); return $response; } public function loadController(sfEvent $event) { $event->setReturnValue(array(array($this, 'hello'), array($this->dispatcher, $event['request']))); return true; } public function hello($dispatcher, $request) { $response = new sfWebResponse($dispatcher); $response->setContent('Hello World'); return $response; } } Symfony 2 | Fabien Potencier
  28. 28. 7922& 7822& !"#$%&!'!& Hello World Benchmark ()$*+& 7022& 7722& 7222& >22& =22& <22& ;22& :22& ,-./+%-&012& 922& x 3 x 7 822& 022& 3+"#4& 722& 56& ,-./+%-&710& 2& based on numbers from http://paul-m-jones.com/?p=315 Symfony 2 | Fabien Potencier
  29. 29. 7 times faster ?! You won’t have such a difference for real applications as most of the time, the limiting factor is not the framework itself Symfony 2 | Fabien Potencier
  30. 30. Twitto ?! Symfony 2 | Fabien Potencier
  31. 31. Twitto: The PHP framework that fits in a tweet •  The fastest framework around? •  Uses some PHP 5.3 new features •  It also fits in a slide… require __DIR__.'/c.php'; if (!is_callable($c = @$_GET['c'] ?: function() { echo 'Woah!'; })) throw new Exception('Error'); $c(); rg .o twitto Symfony 2 | Fabien Potencier
  32. 32. Don’t use Twitto for your next website It is a joke ;) Symfony 2 | Fabien Potencier
  33. 33. 7 times faster ?! •  But raw speed matters because – It demonstrates that the core « kernel » is very light – It allows you to use several Symfony frameworks within a single application with the same behavior but different optimizations: •  One full-stack framework optimized for ease of use (think symfony 1) •  One light framework optimized for speed (think Rails Metal ;)) Symfony 2 | Fabien Potencier
  34. 34. symfony platform 2.0 sfRequestHandler sfRequest sfRouting sfLogger sfI18N sfUser sfTemplate sfResponse sfValidator sfForm sfWidget sfCache sfDatabase sfStorage sfYAML sfOutputEscaper sfServiceContainer sfEventDispatcher sfCoreAutoload platform Symfony 2 | Fabien Potencier
  35. 35. Symfony 2 kernel: The Request Handler Symfony 2 | Fabien Potencier
  36. 36. Symfony 2 secret weapon: The Request Handler Symfony 2 | Fabien Potencier
  37. 37. The Request Handler •  The backbone of Symfony 2 controller implementation •  Class to build web frameworks, not only MVC ones •  Based on a simple assumption: – The input is a request object – The output is a response object •  The request object can be anything you want •  The response object must implement a send() method Symfony 2 | Fabien Potencier
  38. 38. The Request Handler $handler = new sfRequestHandler($dispatcher); $request = new sfWebRequest($dispatcher); $response = $handler->handle($request); $response->send(); Symfony 2 | Fabien Potencier
  39. 39. The Request Handler •  The sfRequestHandler does several things: – Notify events – Execute a callable (the controller) – Ensure that the Request is converted to a Response object •  The framework is responsible for choosing the controller •  The controller is responsible for the conversion of the Request to a Response Symfony 2 | Fabien Potencier
  40. 40. class sfRequestHandler { protected $dispatcher = null; public function __construct(sfEventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function handle($request) { try { return $this->handleRaw($request); } catch (Exception $e) { $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.exception', array('request' => $request, 'exception' => $e))); if ($event->isProcessed()) { sfRequestHandler return $this->filterResponse($event->getReturnValue(), 'An "application.exception" listener returned a non response object.'); } throw $e; } } is less than 100 public function handleRaw($request) { $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.request', array('request' => $request))); if ($event->isProcessed()) { lines of PHP code! return $this->filterResponse($event->getReturnValue(), 'An "application.request" listener returned a non response object.'); } $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.load_controller', array('request' => $request))); if (!$event->isProcessed()) { throw new Exception('Unable to load the controller.'); } list($controller, $arguments) = $event->getReturnValue(); if (!is_callable($controller)) { throw new Exception(sprintf('The controller must be a callable (%s).', var_export($controller, true))); } $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.controller', array('request' => $request, 'controller' => &$controller, 'arguments' => &$arguments))); if ($event->isProcessed()) { try { return $this->filterResponse($event->getReturnValue(), 'An "application.controller" listener returned a non response object.'); } catch (Exception $e) { $retval = $event->getReturnValue(); } } else { $retval = call_user_func_array($controller, $arguments); } $event = $this->dispatcher->filter(new sfEvent($this, 'application.view'), $retval); return $this->filterResponse($event->getReturnValue(), sprintf('The controller must return a response (instead of %s).', is_object($event->getReturnValue()) ? 'an object of class '.get_class($event->getReturnValue()) : (string) $event->getReturnValue())); } protected function filterResponse($response, $message) { if (!is_object($response) || !method_exists($response, 'send')) { throw new RuntimeException($message); } $event = $this->dispatcher->filter(new sfEvent($this, 'application.response'), $response); $response = $event->getReturnValue(); if (!is_object($response) || !method_exists($response, 'send')) { throw new RuntimeException('An "application.response" listener returned a non response object.'); } return $response; } } Symfony 2 | Fabien Potencier
  41. 41. Request Handler Events application.request application.load_controller application.controller application.view application.response application.exception Symfony 2 | Fabien Potencier
  42. 42. application.response As the very last event notified, a listener can modify the Response object just before it is returned to the user Symfony 2 | Fabien Potencier
  43. 43. application.request •  The very firstevent notified •  It can act as a short-circuit event •  If one listener returns a Response object, it stops the processing Symfony 2 | Fabien Potencier
  44. 44. application.load_controller •  Only event for which at least one listener must be connected to •  A listener must return – A PHP callable (the controller) – The arguments to pass to the callable Symfony 2 | Fabien Potencier
  45. 45. application.view The controller must return a Response object except if a listener can convert the controller return value to a Response Symfony 2 | Fabien Potencier
  46. 46. application.exception The request handler catches all exceptions and give a chance to listeners to return a Response object Symfony 2 | Fabien Potencier
  47. 47. Request Handler •  Several listeners can be attached to a single event •  Listeners are called in turn sfEventDispatcher load_controller controller response request view exception request sfRequestHandler response Symfony 2 | Fabien Potencier
  48. 48. require_once dirname(__FILE__).'/sf20/autoload2/sfCore2Autoload.class.php'; sfCore2Autoload::register(); $app = new HelloApplication(); $app->run()->send(); class HelloApplication { public function __construct() { $this->dispatcher = new sfEventDispatcher(); Hello World $this->dispatcher->connect('application.load_controller', array($this, 'loadController')); } nts fony Compone public function run() { $request = new sfWebRequest($this->dispatcher); with Sym $handler = new sfRequestHandler($this->dispatcher); $response = $handler->handle($request); return $response; } public function loadController(sfEvent $event) { $event->setReturnValue(array(array($this, 'hello'), array($this->dispatcher, $event['request']))); return true; } public function hello($dispatcher, $request) { $response = new sfWebResponse($dispatcher); $response->setContent('Hello World'); return $response; } } Symfony 2 | Fabien Potencier
  49. 49. require_once '/path/to/sfCore2Autoload.class.php'; sfCore2Autoload::register(); Symfony 2 | Fabien Potencier
  50. 50. $app = new HelloApplication(); $app->run()->send(); Symfony 2 | Fabien Potencier
  51. 51. public function __construct() { $this->dispatcher = new sfEventDispatcher(); $this->dispatcher->connect( 'application.load_controller', array($this, 'loadController') ); } sfEventDispatcher load_controller controller response request view exception request sfRequestHandler response Symfony 2 | Fabien Potencier
  52. 52. public function loadController(sfEvent $event) { $event->setReturnValue(array( array($this, 'hello'), array($this->dispatcher, $event['request']) )); return true; } Symfony 2 | Fabien Potencier
  53. 53. public function hello($dispatcher, $request) { $response = new sfWebResponse($dispatcher); $response->setContent('Hello World'); return $response; } Symfony 2 | Fabien Potencier
  54. 54. public function run() { $request = new sfWebRequest($this->dispatcher); $handler = new sfRequestHandler($this->dispatcher); $response = $handler->handle($request); return $response; } Symfony 2 | Fabien Potencier
  55. 55. Case study: dailymotion.com •  The problem: the Dailymotion developers add new features on a nearly everyday basis •  The challenge: Migrate by introducing small doses of Symfony goodness •  The process – Wrap everything with sfRequestHandler by implementing an application.load_controller listener that calls the old code, based on the request – Migrate the mod_rewrite rules to the symfony routing – Add unit and functional tests Symfony 2 | Fabien Potencier
  56. 56. Symfony 2: The Templating Framework Symfony 2 | Fabien Potencier
  57. 57. New Templating Framework •  4 components – Template Engine – Template Renderers – Template Loaders – Template Storages •  Independant library Symfony 2 | Fabien Potencier
  58. 58. require_once '/path/to/sfCore2Autoload.class.php'; sfCore2Autoload::register(); $dispatcher = new sfEventDispatcher(); $loader = new sfTemplateLoaderFilesystem($dispatcher, '/path/to/templates/%s.php'); $t = new sfTemplateEngine($dispatcher, $loader); echo $t->render('index', array('name' => 'Fabien')); Symfony 2 | Fabien Potencier
  59. 59. Template Loaders •  No assumption about where and how templates are to be found – Filesystem – Database – Memory – … •  Template names are « logical » names: $loader = new sfTemplateLoaderFilesystem($dispatcher, '/path/to/templates/%s.php'); Symfony 2 | Fabien Potencier
  60. 60. Template Renderers •  No assumption about the format of the templates •  Template names are prefixed with the renderer name: –  index == php:index –  user:index $t = new sfTemplateEngine($dispatcher, $loader, array( 'user' => new ProjectTemplateRenderer($dispatcher), 'php' => new sfTemplateRendererPhp($dispatcher), )); Symfony 2 | Fabien Potencier
  61. 61. Template Embedding Hello <?php echo $name ?> <?php $this->render('embedded', array('name' => $name)) ?> <?php $this->render('smarty:embedded') ?> Symfony 2 | Fabien Potencier
  62. 62. Template Inheritance <?php $this->decorator('layout') ?> Hello <?php echo $name ?> <html> <head> </head> <body> <?php $this->output('content') ?> </body> </html> Symfony 2 | Fabien Potencier
  63. 63. Template Slots <html> <head> <title><?php $this->output('title') ?></title> </head> <body> <?php $this->output('content') ?> </body> </html> <?php $this->set('title', 'Hello World! ') ?> <?php $this->start('title') ?> Hello World! <?php $this->stop() ?> Symfony 2 | Fabien Potencier
  64. 64. Template Multiple Inheritance A layout can be decorated by another layout Each layout can override slots Symfony 2 | Fabien Potencier
  65. 65. Templating: An example Symfony 2 | Fabien Potencier
  66. 66. CMS Templating •  Imagine a CMS with the following features: – The CMS comes bundled with default templates – The developer can override default templates for a specific project – The webmaster can override some templates •  The CMS and developer templates are stored on the filesystem and are written with pure PHP code •  The webmaster templates are stored in a database and are written in a simple templating language: Hello {{ name }} Symfony 2 | Fabien Potencier
  67. 67. CMS Templating •  The CMS has several built-in sections and pages – Each page is decorated by a layout, depending on the section – Each section layout is decorated by a base layout cms/templates/ project/templates/ base.php base.php articles/ articles/ layout.php layout.php article.php article.php content.php Symfony 2 | Fabien Potencier
  68. 68. articles/content.php <h1>{{ title }}</h1> <p> {{ content }} </p> Symfony 2 | Fabien Potencier
  69. 69. articles/article.php <?php $this->decorator('articles/layout') ?> <?php $this->set('title', $title) ?> <?php echo $this->render( 'user:articles/content', array('title' => $title, 'content' => $content) ) ?> Symfony 2 | Fabien Potencier
  70. 70. articles/layout.php <?php $this->decorator('base') ?> <?php $this->set('title', 'Articles | '.$this->get('title')) ?> <?php $this->start('head') ?> <?php $this->output('head') ?> <link rel="stylesheet" type="text/css" media="all" href="/css/ articles.css" /> <?php $this->stop() ?> <?php $this->output('content') ?> Symfony 2 | Fabien Potencier
  71. 71. articles/layout.php <?php $this->decorator('base') ?> <?php $this->set('title', 'Articles | '.$this->get('title')) ?> <?php $this->stylesheets->add('/css/articles.css') ?> <?php $this->output('content') ?> Symfony 2 | Fabien Potencier
  72. 72. base.php <html> <head> <title> <?php $this->output('title') ?> </title> <?php $this->output('head') ?> </head> <body> <?php $this->output('content') ?> </body> </html> Symfony 2 | Fabien Potencier
  73. 73. Template Renderer $t = new sfTemplateEngine($dispatcher, $loader, array( 'user' => new ProjectTemplateRenderer($dispatcher), 'php' => new sfTemplateRendererPhp($dispatcher), )); Symfony 2 | Fabien Potencier
  74. 74. Template Renderer class ProjectTemplateRenderer extends sfTemplateRenderer { public function evaluate($template, array $parameters = array()) { if ($template instanceof sfTemplateStorageFile) { $template = file_get_contents($template); } $this->parameters = $parameters; return preg_replace_callback('/{{s*(.+?)s*}}/', array($this, 'replaceParameters'), $template); } public function replaceParameters($matches) { return isset($this->parameters[$matches[1]]) ? $this->parameters[$matches[1]] : null; } } Symfony 2 | Fabien Potencier
  75. 75. Template Loaders $loader = new sfTemplateLoaderFilesystem($dispatcher, array( '/path/to/project/templates/%s.php', '/path/to/cms/templates/%s.php' )); Symfony 2 | Fabien Potencier
  76. 76. Template Loader Chain $loader = new sfTemplateLoaderChain($dispatcher, array( new ProjectTemplateLoader( $dispatcher, array('pdo' => $pdo)), new sfTemplateLoaderFilesystem($dispatcher, array( '/path/to/project/templates/%s.php', '/path/to/cms/templates/%s.php' )), )); Symfony 2 | Fabien Potencier
  77. 77. Database Template Loader class ProjectTemplateLoader extends sfTemplateLoader { public function load($template) { $stmt = $this->options['pdo']->prepare('SELECT tpl FROM tpl WHERE name = :name'); try { $stmt->execute(array('name' => $template)); if (count($rows = $stmt->fetchAll(PDO::FETCH_NUM))) { return $rows[0][0]; } } catch (PDOException $e) { } return false; } } Symfony 2 | Fabien Potencier
  78. 78. Database Template Loader $pdo = new PDO('sqlite::memory:'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")'); Symfony 2 | Fabien Potencier
  79. 79. Template Loader Cache $loader = new sfTemplateLoaderCache( $dispatcher, $loader, new sfFileCache(array('dir' => 'path/to/cache')) ); Symfony 2 | Fabien Potencier
  80. 80. $pdo = new PDO('sqlite::memory:'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")'); $loader = new sfTemplateLoaderCache( $dispatcher, new sfTemplateLoaderChain($dispatcher, array( new ProjectTemplateLoader($dispatcher, array('pdo' => $pdo)), new sfTemplateLoaderFilesystem($dispatcher, array( '/path/to/project/templates/%s.php', '/path/to/cms/templates/%s.php' )), )), new sfFileCache(array('dir' => 'path/to/cache')) ); $t = new sfTemplateEngine($dispatcher, $loader, array( 'user' => new ProjectTemplateRenderer($dispatcher) )); $t->render('articles/article', array('title' => 'Title', 'content' => 'Lorem...')); Symfony 2 | Fabien Potencier
  81. 81. Symfony 2: Dependency Injection Container Symfony 2 | Fabien Potencier
  82. 82. « Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. » h"p://www.picocontainer.org/injec2on.html  Symfony 2 | Fabien Potencier
  83. 83. The Symfony 2 dependency injection container replaces several symfony 1 concepts into one integrated system: – sfContext – sfConfiguration – sfConfig – factories.yml – settings.yml / logging.yml / i18n.yml Symfony 2 | Fabien Potencier
  84. 84. DI Hello World example class Message { public function __construct(OutputInterface $output, array $options) { $this->output = $output; $this->options = array_merge(array('with_newline' => false), $options); } public function say($msg) { $this->output->render($msg.($this->options['with_newline'] ? "n" : '')); } } Symfony 2 | Fabien Potencier
  85. 85. DI Hello World example interface OutputInterface { public function render($msg); } class Output implements OutputInterface { public function render($msg) { echo $msg; } } class FancyOutput implements OutputInterface { public function render($msg) { echo sprintf("033[33m%s033[0m", $msg); } } Symfony 2 | Fabien Potencier
  86. 86. DI Hello World example $output = new FancyOutput(); $message = new Message($output, array('with_newline' => true)); $message->say('Hello World'); Symfony 2 | Fabien Potencier
  87. 87. A DI container facilitates objects description and object relationships, configures and instantiates objects Symfony 2 | Fabien Potencier
  88. 88. DI Container Hello World example $container = new sfServiceContainerBuilder(); $container->register('output', 'FancyOutput'); $container-> register('message', 'Message')-> setArguments(array(new sfServiceReference('output'), array('with_newline' => true))) ; $container->message->say('Hello World!'); Symfony 2 | Fabien Potencier
  89. 89. $message = $container->message; Get the configuration for the message service The Message constructor must be given an output service Get the output object from the container Create a Message object by passing the constructor arguments Symfony 2 | Fabien Potencier
  90. 90. $message = $container->message; is roughly equivalent to $output = new FancyOutput(); $message = new Message($output, array('with_newline' => true));! Symfony 2 | Fabien Potencier
  91. 91. $container = new sfServiceContainerBuilder(); $container->register('output', 'FancyOutput'); $container-> register('message', 'Message')-> setArguments(array(new sfServiceReference('output'), array('with_newline' => true))) ; PHP $container->message->say('Hello World!'); <container> <services> XML <service id="output" class="FancyOutput" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument type="collection"> <argument key="with_newline">true</argument> </argument> </service> </services> </container> $container = new sfServiceContainerBuilder(); $loader = new sfServiceLoaderFileXml($container); $loader->load('services.xml'); Symfony 2 | Fabien Potencier
  92. 92. $container = new sfServiceContainerBuilder(); $container->register('output', 'FancyOutput'); $container-> register('message', 'Message')-> setArguments(array(new sfServiceReference('output'), array('with_newline' => true))) ; PHP $container->message->say('Hello World!'); services: output: { class: FancyOutput } YAML message: class: Message arguments: - @output - { with_newline: true } $container = new sfServiceContainerBuilder(); $loader = new sfServiceLoaderFileYaml($container); $loader->load('services.yml'); Symfony 2 | Fabien Potencier
  93. 93. <container> <parameters> <parameter key="output.class">FancyOutput</parameter> <parameter key="message.options" type="collection"> <parameter key="with_newline">true</parameter> </parameter> </parameters> <services> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> </container> $container = new sfServiceContainerBuilder(); $loader = new sfServiceLoaderFileXml($container); $loader->load('services.xml'); Symfony 2 | Fabien Potencier
  94. 94. <container> <imports> <import resource="config.xml" /> </imports> <services> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> </container> <container> <parameters> <parameter key="output.class">FancyOutput</parameter> <parameter key="message.options" type="collection"> <parameter key="with_newline">true</parameter> </parameter> </parameters> </container> $container = new sfServiceContainerBuilder(); $loader = new sfServiceLoaderFileXml($container); $loader->load('services.xml'); 2 | Fabien Potencier Symfony
  95. 95. <services> <import resource="config.yml" class="sfServiceLoaderFileYaml" /> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> parameters: output.class: FancyOutput message.options: { with_newline: true } $container = new sfServiceContainerBuilder(); $loader = new sfServiceLoaderFileXml($container); $loader->load('services.xml'); Symfony 2 | Fabien Potencier
  96. 96. $pdo = new PDO('sqlite::memory:'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")'); $loader = new sfTemplateLoaderCache( $dispatcher, new sfTemplateLoaderChain($dispatcher, array( new ProjectTemplateLoader($dispatcher, array('pdo' => $pdo)), new sfTemplateLoaderFilesystem($dispatcher, array( '/path/to/project/templates/%s.php', '/path/to/cms/templates/%s.php' )), )), new sfFileCache(array('dir' => 'path/to/cache')) ); $t = new sfTemplateEngine($dispatcher, $loader, array( 'user' => new ProjectTemplateRenderer($dispatcher) )); $t->render('articles/article', array('title' => 'Title', 'content' => 'Lorem...')); Symfony 2 | Fabien Potencier
  97. 97. $pdo = new PDO('sqlite::memory:'); <service id="pdo" class="PDO"> <argument>sqlite::memory:</argument> </service> Symfony 2 | Fabien Potencier
  98. 98. $container = new sfServiceContainerBuilder(); $loader = new sfServiceLoaderFileXml($container); $loader->load('cms.xml'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")'); echo $container->template->render('articles/article', array('title' => 'Title', 'content' => 'Lorem...')); Symfony 2 | Fabien Potencier
  99. 99. <container> <imports> <import resource="config.yml" class="sfServiceLoaderFileYaml" /> <import resource="template_loader.xml" /> </imports> <services> <service id="event_dispatcher" class="sfEventDispatcher" /> <service id="pdo" class="PDO"> <argument>sqlite::memory:</argument> </service> <service id="template_renderer" class="ProjectTemplateRenderer" lazy="true"> <argument type="service" id="event_dispatcher" /> </service> <service id="template" class="sfTemplateEngine" lazy="true"> <argument type="service" id="event_dispatcher" /> <argument type="service" id="template_loader" /> <argument type="collection"> <argument type="service" key="user" id="template_renderer" /> </argument> </service> </services> </container> Symfony 2 | Fabien Potencier
  100. 100. <services> <service id="template_loader_project" class="ProjectTemplateLoader"> <argument type="service" id="event_dispatcher" /> <argument type="collection"><argument type="service" key="pdo" id="pdo" /></argument> </service> <service id="template_loader_filesystem" class="sfTemplateLoaderFilesystem"> <argument type="service" id="event_dispatcher" /> <argument>%template.filesystem_pattern%</argument> </service> <service id="template_loader_chain" class="sfTemplateLoaderChain"> <argument type="service" id="event_dispatcher" /> <argument type="collection"> <argument type="service" id="template_loader_project" /> <argument type="service" id="template_loader_filesystem" /> </argument> </service> <service id="template_loader_cache" class="sfFileCache"> <argument type="collection"><argument key="cache_dir">%application.dir%/cache</argument></argument> </service> <service id="template_loader" class="sfTemplateLoaderCache" lazy="true"> <argument type="service" id="event_dispatcher" /> <argument type="service" id="template_loader_chain" /> <argument type="service" id="template_cache" /> </service> </services> Symfony 2 | Fabien Potencier
  101. 101. <services> <service id="template_loader" class="sfTemplateLoaderCache" lazy="true"> <argument type="service" id="event_dispatcher" /> <argument type="service"> <service class="sfTemplateLoaderChain"> <argument type="service" id="event_dispatcher" /> <argument type="collection"> <argument type="service"> <service class="ProjectTemplateLoader"> <argument type="service" id="event_dispatcher" /> <argument type="collection"><argument type="service" key="pdo" id="pdo" /></argument> </service> </argument> <argument type="service"> <service class="sfTemplateLoaderFilesystem"> <argument type="service" id="event_dispatcher" /> <argument>%template.filesystem_patterns%</argument> </service> </argument> </argument> </service> </argument> <argument type="service"> <service class="sfFileCache"> <argument type="collection"><argument key="cache_dir">%application.dir%/cache</argument></argument> </service> </argument> </service> </services> Symfony 2 | Fabien Potencier
  102. 102. Symfony 2 | Fabien Potencier
  103. 103. Questions? Symfony 2 | Fabien Potencier
  104. 104. Sensio S.A. 92-98, boulevardVictor Hugo 92 115 Clichy Cedex FRANCE Tél. : +33 1 40 99 80 80 Contact Fabien Potencier fabien.potencier at sensio.com http://www.sensiolabs.com/ http://www.symfony-project.org/ http://fabien.potencier.org/ Symfony 2 | Fabien Potencier

×