SlideShare a Scribd company logo
Symfony 2

 Fabien Potencier
Who am I?
•  Founder of Sensio
   –  Web Agency
   –  Since 1998
   –  70 people
   –  Open-Source Specialists
   –  Big corporate customers


•  Creator and lead developer of symfony
How many of you have used symfony?
         1.0? 1.1? 1.2?
symfony 1.0
•  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 1.2

•  Decoupled but cohesive components: the symfony platform

   –  Forms, Routing, Cache, YAML, ORMs, …

•  Controller still based on Mojavi

   –  View, Filter Chain, …

•  Could have been named 2.0 ;)
symfony platform                                 >= 1.1
                                                                                  2.0


    sfRequest    sfRouting     sfLogger   sfI18N    sfUser      sfResponse




sfYAML   sfDatabase   sfForm    sfEventDispatcher   sfStorage     sfCache    sfOutputEscaper



             sfValidator     sfWidget                            sfCoreAutoload
                                                                                   platform
symfony platform



require_once '/path/to/sfCoreAutoload.class.php';
sfCoreAutoload::register();
$config = sfYaml::load(<<<EOF
config:
   key: value
   foo: [bar, foobar]
   bar: { bar: foo }
EOF
);

print_r($config);
echo sfYaml::dump($config);
$cache = new sfSQLiteCache(array(
  'database' => dirname(__FILE__).'/cache.db'
));
$cache->set('foo', 'bar');
echo $cache->get('foo');
Symfony 2 is an evolution of symfony 1


•  Same symfony platform

•  Different controller implementation

•  Oh! Symfony now takes a capital S!!!
Symfony 2 main goals


   Flexibility
       Fast
     Smart
Symfony 2: New components


Dependency Injection Container
   Templating Framework
     Controller Handling
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
symfony 1: Not fast enough?
symfony 1 is
  one of the slowest framework
     when you test it against
a simple Hello World application
1644&

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

1344&

1144&

1444&

 ;44&

 :44&
                                                                      x 19.5
 944&

 844&


        Hello World
 744&

 644&

 544&    Benchmark
 344&
                                     ()"#*&
 144&                                                                  x 2.3
                                                           +,&           -./0)%.&123&
   4&
               based on numbers from http://paul-m-jones.com/?p=315
Conclusion?
Don’t use symfony
for your next « Hello World » website

            Use PHP ;)
By the way,

      the fastest implemention
of a Hello World application with PHP:

  die('Hello World');
But symfony 1 is probably fast enough
        for your next website
… 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
… and recently
dailymotion.com announced
  its migration to Symfony

 sf-to.org/dailymotion
Secondmost popular video sharing website
 One of the top 50 websites in the world
     42 million unique users in December
…and of course
many other smaller websites…
Symfony 2: Faster?
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 core is so light and flexible
      that its raw performance
            is outstanding
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();
    $this->dispatcher->connect('application.load_controller', array($this, 'loadController'));
  }

    public function run()


                                                                                               Hello World
    {
      $request = new sfWebRequest($this->dispatcher);


                                                                                                  Symfony 2.0
      $handler = new sfRequestHandler($this->dispatcher);

                                                                                             with
      $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;
    }
}
7922&

7822&   !"#$%&!'!&
                                                                        Hello World
                      ()$*+&
7022&
                                                                         Benchmark
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
Twitto ?!
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();                            twitt o.org
Don’t use Twitto for your next website
            It is a joke ;)
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
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 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 kernel:

The Request Handler
Symfony 2 secret weapon:

  The Request Handler
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

        Web Request                                  Web Response
                                  Request Handler
The Request Handler


$handler = new sfRequestHandler($dispatcher);

$request = new sfWebRequest($dispatcher);
$response = $handler->handle($request);

$response->send();
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
class sfRequestHandler
{
  protected $dispatcher = null;

    public function __construct(sfEventDispatcher $dispatcher)
    {
      $this->dispatcher = $dispatcher;
    }




                                                                                                                                                                                           sfRequestHandler
    public function handle($request)
    {
      try
      {
        return $this->handleRaw($request);




                                                                                                                                                                                            s less than 100
      }
      catch (Exception $e)



                                                                                                                                                                                           i
      {
        $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.exception', array('request' => $request, 'exception' => $e)));
        if ($event->isProcessed())
        {




                                                                                                                                                                                             lines of PHP
          return $this->filterResponse($event->getReturnValue(), 'An "application.exception" listener returned a non response object.');
        }

            throw $e;
        }
    }




                                                                                                                                                                                                 code!
    public function handleRaw($request)
    {
      $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.request', array('request' => $request)));
      if ($event->isProcessed())
      {
        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;
    }
}
Request Handler Events
application.request

application.load_controller

application.controller

application.view

application.response

application.exception
application.response




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



•  The very first event notified

•  It can act as a short-circuit event

•  If one listener returns a Response object, it stops the processing
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
application.view




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




The request handler catches all exceptions
       and give a chance to listeners
        to return a Response object
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
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();
    $this->dispatcher->connect('application.load_controller', array($this, 'loadController'));
  }

    public function run()


                                                                                               Hello World
    {
      $request = new sfWebRequest($this->dispatcher);


                                                                                                  Symfony 2.0
      $handler = new sfRequestHandler($this->dispatcher);

                                                                                             with
      $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;
    }
}
require_once '/path/to/sfCore2Autoload.class.php';
sfCore2Autoload::register();
$app = new HelloApplication();
$app->run()->send();
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
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;
}
public function run()
 {
   $request = new sfWebRequest($this->dispatcher);
   $handler = new sfRequestHandler($this->dispatcher);
   $response = $handler->handle($request);

     return $response;
 }
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: The Templating Framework
New Templating Framework
•  4 components
   –  Template Engine
   –  Template Renderers
   –  Template Loaders
   –  Template Storages



•  Independant library
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'));
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');
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),
));
Template Embedding



Hello <?php echo $name ?>

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

<?php $this->render('smarty:embedded') ?>
Template Inheritance
<?php $this->decorator('layout') ?>

Hello <?php echo $name ?>

<html>
  <head>
  </head>
  <body>
    <?php $this->output('content') ?>
  </body>
</html>
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() ?>
Template Multiple Inheritance



A layout can be decorated by another layout

       Each layout can override slots
Templating: An example
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 }}
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
articles/content.php



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

<p>
  {{ content }}
</p>
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)
) ?>
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') ?>
base.php
<html>
  <head>
    <title>
       <?php $this->output('title') ?>
    </title>
    <?php $this->output('head') ?>
  </head>
  <body>
    <?php $this->output('content') ?>
  </body>
</html>
Template Renderer



$t = new sfTemplateEngine($dispatcher, $loader, array(
  'user' => new ProjectTemplateRenderer($dispatcher),
  'php' => new sfTemplateRendererPhp($dispatcher),
));
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;
  }
}
Template Loaders



$loader = new sfTemplateLoaderFilesystem($dispatcher,
  array(
    '/path/to/project/templates/%s.php',
    '/path/to/cms/templates/%s.php'
  ));
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'
  )),
));
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;
    }
}
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 }}")');
Template Loader Cache



$loader = new sfTemplateLoaderCache(
   $dispatcher,
   $loader,
   new sfFileCache(array('dir' => 'path/to/cache'))
);
$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: Dependency Injection Container
« Dependency Injection is where
  components are given their dependencies
   through their constructors, methods, or
            directly into fields. »
http://www.picocontainer.org/injection.html
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
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" : ''));
    }
}
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);
  }
}
DI Hello World example




$output = new FancyOutput();
$message = new Message($output, array('with_newline' => true));
$message->say('Hello World');
A DI container facilitates
objects description and object relationships,
    configures and instantiates objects
DI Container Hello World example

$container = new sfServiceContainer();

$outputDef = new sfServiceDefinition('FancyOutput');
$container->setServiceDefinition('output', $outputDef);

$msgDef = new sfServiceDefinition(
   'Message',
   array(new sfServiceReference('output'), array('with_newline' => true))
);
$container->setServiceDefinition('message', $msgDef);

$container->message->say('Hello World!');
$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
$message = $container->message;


                     is roughly equivalent to

                  $output = new FancyOutput();
$message = new Message($output, array('with_newline' => true));!
$container = new sfServiceContainer();

$msgDef = new sfServiceDefinition(
   'Message',
   array(new sfServiceReference('output'), array('with_newline' => true))
);
$outputDef = new sfServiceDefinition('FancyOutput');                        PHP
$container->setServiceDefinition('message', $msgDef);
$container->setServiceDefinition('output', $outputDef);




<services>
  <service id="output" class="FancyOutput" />
                                                                            XML
  <service id="message" class="Message">
    <argument type="service" id="output" />
    <argument type="collection">
      <argument key="with_newline">true</argument>
    </argument>
  </service>
</services>

$container = new sfServiceContainer(new sfServiceLoaderXml());
$container->load('services.xml');
<services>
  <parameters>
    <parameter key="output.class">FancyOutput</parameter>
    <parameter key="message.options" type="collection">
      <parameter key="with_newline">true</parameter>
    </parameter>
  </parameters>

  <service id="output" class="%output.class%" />

  <service id="message" class="Message">
    <argument type="service" id="output" />
    <argument>%message.options%</argument>
  </service>
</services>

$container = new sfServiceContainer(new sfServiceLoaderXml());
$container->load('services.xml');
<services>
 <import resource="config.xml" />

  <service id="output" class="%output.class%" />
  <service id="message" class="Message">
    <argument type="service" id="output" />
    <argument>%message.options%</argument>
  </service>
</services>

<services>
  <parameters>
    <parameter key="output.class">FancyOutput</parameter>
    <parameter key="message.options" type="collection">
      <parameter key="with_newline">true</parameter>
    </parameter>
  </parameters>
</services>

$container = new sfServiceContainer(new sfServiceLoaderXml());
$container->load('services.xml');
<services>
 <import resource="config.yml" class="sfServiceLoaderYamlParameters" />

  <service id="output" class="%output.class%" />
  <service id="message" class="Message">
    <argument type="service" id="output" />
    <argument>%message.options%</argument>
  </service>
</services>

output.class: FancyOutput

message.options:
  with_newline: true

$container = new sfServiceContainer(new sfServiceLoaderXml());
$container->load('services.xml');
$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...'));
$pdo = new PDO('sqlite::memory:');



<service id="pdo" class="PDO">
  <argument>sqlite::memory:</argument>
</service>
$container = new sfServiceContainer(new sfServiceLoaderXml());
$container->load(dirname(__FILE__).'/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...'));
<services>
  <import resource="config.yml" class="sfServiceLoaderYamlParameters" />
  <import resource="template_loader.xml" />

  <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>
<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>
<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>
Questions?
Sensio S.A.
     92-98, boulevard Victor 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/

More Related Content

What's hot (20)

PDF
Rich Model And Layered Architecture in SF2 Application
Kirill Chebunin
 
PDF
Beyond symfony 1.2 (Symfony Camp 2008)
Fabien Potencier
 
PPTX
Looping the Loop with SPL Iterators
Mark Baker
 
PPTX
Real time voice call integration - Confoo 2012
Michael Peacock
 
PDF
News of the Symfony2 World
Fabien Potencier
 
KEY
Perl Web Client
Flavio Poletti
 
PPTX
Dealing with Continuous Data Processing, ConFoo 2012
Michael Peacock
 
PDF
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
PDF
Php Enums
Ayesh Karunaratne
 
PDF
PHP 8.1: Enums
Ayesh Karunaratne
 
KEY
dotCloud and go
Flavio Poletti
 
PDF
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
Javier Eguiluz
 
PDF
Design how your objects talk through mocking
Konstantin Kudryashov
 
KEY
循環参照のはなし
Masahiro Honma
 
PDF
Decoupling with Design Patterns and Symfony2 DIC
Konstantin Kudryashov
 
PDF
What's new in PHP 8.0?
Nikita Popov
 
PDF
Dirty Secrets of the PHP SOAP Extension
Adam Trachtenberg
 
PDF
How I started to love design patterns
Samuel ROZE
 
PDF
CLI, the other SAPI phpnw11
Combell NV
 
PDF
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 
Rich Model And Layered Architecture in SF2 Application
Kirill Chebunin
 
Beyond symfony 1.2 (Symfony Camp 2008)
Fabien Potencier
 
Looping the Loop with SPL Iterators
Mark Baker
 
Real time voice call integration - Confoo 2012
Michael Peacock
 
News of the Symfony2 World
Fabien Potencier
 
Perl Web Client
Flavio Poletti
 
Dealing with Continuous Data Processing, ConFoo 2012
Michael Peacock
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
PHP 8.1: Enums
Ayesh Karunaratne
 
dotCloud and go
Flavio Poletti
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
Javier Eguiluz
 
Design how your objects talk through mocking
Konstantin Kudryashov
 
循環参照のはなし
Masahiro Honma
 
Decoupling with Design Patterns and Symfony2 DIC
Konstantin Kudryashov
 
What's new in PHP 8.0?
Nikita Popov
 
Dirty Secrets of the PHP SOAP Extension
Adam Trachtenberg
 
How I started to love design patterns
Samuel ROZE
 
CLI, the other SAPI phpnw11
Combell NV
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 

Viewers also liked (6)

PDF
Sympal The Flexible Symfony Cms
narkoza
 
PDF
What S New In Doctrine
narkoza
 
PDF
Building A Platform From Open Source At Yahoo
narkoza
 
PDF
Symfony Live 09 Symfony 2
narkoza
 
PDF
антонич б. і. зелена євангелія. львів, 1938
narkoza
 
PDF
Entrepreneurship support - an entrepreneur's perspective
Salim Virani
 
Sympal The Flexible Symfony Cms
narkoza
 
What S New In Doctrine
narkoza
 
Building A Platform From Open Source At Yahoo
narkoza
 
Symfony Live 09 Symfony 2
narkoza
 
антонич б. і. зелена євангелія. львів, 1938
narkoza
 
Entrepreneurship support - an entrepreneur's perspective
Salim Virani
 
Ad

Similar to Symfony 2 (PHP Quebec 2009) (20)

PDF
Symfony 2 (PHP day 2009)
Fabien Potencier
 
PDF
Symfony2 San Francisco Meetup 2009
Fabien Potencier
 
PDF
When symfony met promises
Marc Morera
 
PDF
Using HttpKernelInterface for Painless Integration
CiaranMcNulty
 
PDF
The symfony platform: Create your very own framework (PHP Quebec 2008)
Fabien Potencier
 
PDF
symfony on action - WebTech 207
patter
 
PPTX
Zend server 6 using zf2, 2013 webinar
Yonni Mendes
 
PDF
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
PDF
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Kacper Gunia
 
PDF
Forget about index.php and build you applications around HTTP!
Kacper Gunia
 
PPTX
Creating your own framework on top of Symfony2 Components
Deepak Chandani
 
KEY
Phpne august-2012-symfony-components-friends
Michael Peacock
 
PDF
Burn down the silos! Helping dev and ops gel on high availability websites
Lindsay Holmwood
 
PDF
Building Testable PHP Applications
chartjes
 
PPTX
Harmonious Development: Via Vagrant and Puppet
Achieve Internet
 
KEY
Fatc
Wade Arnold
 
PDF
Living With Legacy Code
Rowan Merewood
 
ODP
From Code to Cloud - PHP on Red Hat's OpenShift
Eric D. Schabell
 
KEY
Anatomy of a PHP Request ( UTOSC 2010 )
Joseph Scott
 
PDF
Hands-on with the Symfony2 Framework
Ryan Weaver
 
Symfony 2 (PHP day 2009)
Fabien Potencier
 
Symfony2 San Francisco Meetup 2009
Fabien Potencier
 
When symfony met promises
Marc Morera
 
Using HttpKernelInterface for Painless Integration
CiaranMcNulty
 
The symfony platform: Create your very own framework (PHP Quebec 2008)
Fabien Potencier
 
symfony on action - WebTech 207
patter
 
Zend server 6 using zf2, 2013 webinar
Yonni Mendes
 
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Kacper Gunia
 
Forget about index.php and build you applications around HTTP!
Kacper Gunia
 
Creating your own framework on top of Symfony2 Components
Deepak Chandani
 
Phpne august-2012-symfony-components-friends
Michael Peacock
 
Burn down the silos! Helping dev and ops gel on high availability websites
Lindsay Holmwood
 
Building Testable PHP Applications
chartjes
 
Harmonious Development: Via Vagrant and Puppet
Achieve Internet
 
Living With Legacy Code
Rowan Merewood
 
From Code to Cloud - PHP on Red Hat's OpenShift
Eric D. Schabell
 
Anatomy of a PHP Request ( UTOSC 2010 )
Joseph Scott
 
Hands-on with the Symfony2 Framework
Ryan Weaver
 
Ad

More from Fabien Potencier (20)

PDF
Varnish
Fabien Potencier
 
PDF
Look beyond PHP
Fabien Potencier
 
PDF
Dependency injection in PHP 5.3/5.4
Fabien Potencier
 
PDF
Dependency injection-zendcon-2010
Fabien Potencier
 
PDF
Caching on the Edge
Fabien Potencier
 
PDF
Design patterns revisited with PHP 5.3
Fabien Potencier
 
PDF
The state of Symfony2 - SymfonyDay 2010
Fabien Potencier
 
PDF
PhpBB meets Symfony2
Fabien Potencier
 
PDF
Dependency injection - phpday 2010
Fabien Potencier
 
PDF
Symfony2 - WebExpo 2010
Fabien Potencier
 
PDF
Symfony2 - WebExpo 2010
Fabien Potencier
 
PDF
Symfony2 - OSIDays 2010
Fabien Potencier
 
PDF
Dependency Injection IPC 201
Fabien Potencier
 
PDF
Caching on the Edge with Symfony2
Fabien Potencier
 
PDF
Unit and Functional Testing with Symfony2
Fabien Potencier
 
PDF
Dependency Injection - ConFoo 2010
Fabien Potencier
 
PDF
Dependency Injection
Fabien Potencier
 
PDF
Symfony Components
Fabien Potencier
 
PDF
PHP 5.3 in practice
Fabien Potencier
 
PDF
Symfony2 revealed
Fabien Potencier
 
Look beyond PHP
Fabien Potencier
 
Dependency injection in PHP 5.3/5.4
Fabien Potencier
 
Dependency injection-zendcon-2010
Fabien Potencier
 
Caching on the Edge
Fabien Potencier
 
Design patterns revisited with PHP 5.3
Fabien Potencier
 
The state of Symfony2 - SymfonyDay 2010
Fabien Potencier
 
PhpBB meets Symfony2
Fabien Potencier
 
Dependency injection - phpday 2010
Fabien Potencier
 
Symfony2 - WebExpo 2010
Fabien Potencier
 
Symfony2 - WebExpo 2010
Fabien Potencier
 
Symfony2 - OSIDays 2010
Fabien Potencier
 
Dependency Injection IPC 201
Fabien Potencier
 
Caching on the Edge with Symfony2
Fabien Potencier
 
Unit and Functional Testing with Symfony2
Fabien Potencier
 
Dependency Injection - ConFoo 2010
Fabien Potencier
 
Dependency Injection
Fabien Potencier
 
Symfony Components
Fabien Potencier
 
PHP 5.3 in practice
Fabien Potencier
 
Symfony2 revealed
Fabien Potencier
 

Recently uploaded (20)

PDF
Rethinking Security Operations - SOC Evolution Journey.pdf
Haris Chughtai
 
PDF
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
PDF
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PDF
Impact of IEEE Computer Society in Advancing Emerging Technologies including ...
Hironori Washizaki
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PPTX
Top Managed Service Providers in Los Angeles
Captain IT
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
Ampere Offers Energy-Efficient Future For AI And Cloud
ShapeBlue
 
PDF
Persuasive AI: risks and opportunities in the age of digital debate
Speck&Tech
 
PDF
Français Patch Tuesday - Juillet
Ivanti
 
PPTX
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
PDF
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
PDF
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
PPTX
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
PDF
CloudStack GPU Integration - Rohit Yadav
ShapeBlue
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PDF
Wojciech Ciemski for Top Cyber News MAGAZINE. June 2025
Dr. Ludmila Morozova-Buss
 
PPTX
Top iOS App Development Company in the USA for Innovative Apps
SynapseIndia
 
Rethinking Security Operations - SOC Evolution Journey.pdf
Haris Chughtai
 
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
Impact of IEEE Computer Society in Advancing Emerging Technologies including ...
Hironori Washizaki
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
Top Managed Service Providers in Los Angeles
Captain IT
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
Ampere Offers Energy-Efficient Future For AI And Cloud
ShapeBlue
 
Persuasive AI: risks and opportunities in the age of digital debate
Speck&Tech
 
Français Patch Tuesday - Juillet
Ivanti
 
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
CloudStack GPU Integration - Rohit Yadav
ShapeBlue
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
Wojciech Ciemski for Top Cyber News MAGAZINE. June 2025
Dr. Ludmila Morozova-Buss
 
Top iOS App Development Company in the USA for Innovative Apps
SynapseIndia
 

Symfony 2 (PHP Quebec 2009)

  • 1. Symfony 2 Fabien Potencier
  • 2. Who am I? •  Founder of Sensio –  Web Agency –  Since 1998 –  70 people –  Open-Source Specialists –  Big corporate customers •  Creator and lead developer of symfony
  • 3. How many of you have used symfony? 1.0? 1.1? 1.2?
  • 4. symfony 1.0 •  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, …
  • 5. symfony 1.2 •  Decoupled but cohesive components: the symfony platform –  Forms, Routing, Cache, YAML, ORMs, … •  Controller still based on Mojavi –  View, Filter Chain, … •  Could have been named 2.0 ;)
  • 6. symfony platform >= 1.1 2.0 sfRequest sfRouting sfLogger sfI18N sfUser sfResponse sfYAML sfDatabase sfForm sfEventDispatcher sfStorage sfCache sfOutputEscaper sfValidator sfWidget sfCoreAutoload platform
  • 8. $config = sfYaml::load(<<<EOF config: key: value foo: [bar, foobar] bar: { bar: foo } EOF ); print_r($config); echo sfYaml::dump($config);
  • 9. $cache = new sfSQLiteCache(array( 'database' => dirname(__FILE__).'/cache.db' )); $cache->set('foo', 'bar'); echo $cache->get('foo');
  • 10. Symfony 2 is an evolution of symfony 1 •  Same symfony platform •  Different controller implementation •  Oh! Symfony now takes a capital S!!!
  • 11. Symfony 2 main goals Flexibility Fast Smart
  • 12. Symfony 2: New components Dependency Injection Container Templating Framework Controller Handling
  • 13. 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
  • 14. symfony 1: Not fast enough?
  • 15. symfony 1 is one of the slowest framework when you test it against a simple Hello World application
  • 16. 1644& 1544& !"#$%&!'!& 1344& 1144& 1444& ;44& :44& x 19.5 944& 844& Hello World 744& 644& 544& Benchmark 344& ()"#*& 144& x 2.3 +,& -./0)%.&123& 4& based on numbers from http://paul-m-jones.com/?p=315
  • 18. Don’t use symfony for your next « Hello World » website Use PHP ;)
  • 19. By the way, the fastest implemention of a Hello World application with PHP: die('Hello World');
  • 20. But symfony 1 is probably fast enough for your next website
  • 21. … 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
  • 22. … and recently dailymotion.com announced its migration to Symfony sf-to.org/dailymotion
  • 23. Secondmost popular video sharing website One of the top 50 websites in the world 42 million unique users in December
  • 24. …and of course many other smaller websites…
  • 26. Symfony 2 core is so light and flexible that you can easily customize it to have outstanding performance for a Hello World application
  • 27. Symfony 2 core is so light and flexible that its raw performance is outstanding
  • 28. 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(); $this->dispatcher->connect('application.load_controller', array($this, 'loadController')); } public function run() Hello World { $request = new sfWebRequest($this->dispatcher); Symfony 2.0 $handler = new sfRequestHandler($this->dispatcher); with $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; } }
  • 29. 7922& 7822& !"#$%&!'!& Hello World ()$*+& 7022& Benchmark 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
  • 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(); twitt o.org
  • 32. Don’t use Twitto for your next website It is a joke ;)
  • 33. 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
  • 34. 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 ;))
  • 35. symfony platform 2.0 sfRequestHandler sfRequest sfRouting sfLogger sfI18N sfUser sfTemplate sfResponse sfValidator sfForm sfWidget sfCache sfDatabase sfStorage sfYAML sfOutputEscaper sfServiceContainer sfEventDispatcher sfCoreAutoload platform
  • 36. Symfony 2 kernel: The Request Handler
  • 37. Symfony 2 secret weapon: The Request Handler
  • 38. 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 Web Request Web Response Request Handler
  • 39. The Request Handler $handler = new sfRequestHandler($dispatcher); $request = new sfWebRequest($dispatcher); $response = $handler->handle($request); $response->send();
  • 40. 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
  • 41. class sfRequestHandler { protected $dispatcher = null; public function __construct(sfEventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } sfRequestHandler public function handle($request) { try { return $this->handleRaw($request); s less than 100 } catch (Exception $e) i { $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.exception', array('request' => $request, 'exception' => $e))); if ($event->isProcessed()) { lines of PHP return $this->filterResponse($event->getReturnValue(), 'An "application.exception" listener returned a non response object.'); } throw $e; } } code! public function handleRaw($request) { $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'application.request', array('request' => $request))); if ($event->isProcessed()) { 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; } }
  • 43. application.response As the very last event notified, a listener can modify the Response object just before it is returned to the user
  • 44. application.request •  The very first event notified •  It can act as a short-circuit event •  If one listener returns a Response object, it stops the processing
  • 45. 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
  • 46. application.view The controller must return a Response object except if a listener can convert the controller return value to a Response
  • 47. application.exception The request handler catches all exceptions and give a chance to listeners to return a Response object
  • 48. 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
  • 49. 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(); $this->dispatcher->connect('application.load_controller', array($this, 'loadController')); } public function run() Hello World { $request = new sfWebRequest($this->dispatcher); Symfony 2.0 $handler = new sfRequestHandler($this->dispatcher); with $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; } }
  • 51. $app = new HelloApplication(); $app->run()->send();
  • 52. 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
  • 53. public function loadController(sfEvent $event) { $event->setReturnValue(array( array($this, 'hello'), array($this->dispatcher, $event['request']) )); return true; }
  • 54. public function hello($dispatcher, $request) { $response = new sfWebResponse($dispatcher); $response->setContent('Hello World'); return $response; }
  • 55. public function run() { $request = new sfWebRequest($this->dispatcher); $handler = new sfRequestHandler($this->dispatcher); $response = $handler->handle($request); return $response; }
  • 56. 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
  • 57. Symfony 2: The Templating Framework
  • 58. New Templating Framework •  4 components –  Template Engine –  Template Renderers –  Template Loaders –  Template Storages •  Independant library
  • 59. 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'));
  • 60. 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');
  • 61. 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), ));
  • 62. Template Embedding Hello <?php echo $name ?> <?php $this->render('embedded', array('name' => $name)) ?> <?php $this->render('smarty:embedded') ?>
  • 63. Template Inheritance <?php $this->decorator('layout') ?> Hello <?php echo $name ?> <html> <head> </head> <body> <?php $this->output('content') ?> </body> </html>
  • 64. 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() ?>
  • 65. Template Multiple Inheritance A layout can be decorated by another layout Each layout can override slots
  • 67. 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 }}
  • 68. 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
  • 70. 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) ) ?>
  • 71. 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') ?>
  • 72. base.php <html> <head> <title> <?php $this->output('title') ?> </title> <?php $this->output('head') ?> </head> <body> <?php $this->output('content') ?> </body> </html>
  • 73. Template Renderer $t = new sfTemplateEngine($dispatcher, $loader, array( 'user' => new ProjectTemplateRenderer($dispatcher), 'php' => new sfTemplateRendererPhp($dispatcher), ));
  • 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; } }
  • 75. Template Loaders $loader = new sfTemplateLoaderFilesystem($dispatcher, array( '/path/to/project/templates/%s.php', '/path/to/cms/templates/%s.php' ));
  • 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' )), ));
  • 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; } }
  • 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 }}")');
  • 79. Template Loader Cache $loader = new sfTemplateLoaderCache( $dispatcher, $loader, new sfFileCache(array('dir' => 'path/to/cache')) );
  • 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...'));
  • 81. Symfony 2: Dependency Injection Container
  • 82. « Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. » http://www.picocontainer.org/injection.html
  • 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
  • 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" : '')); } }
  • 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); } }
  • 86. DI Hello World example $output = new FancyOutput(); $message = new Message($output, array('with_newline' => true)); $message->say('Hello World');
  • 87. A DI container facilitates objects description and object relationships, configures and instantiates objects
  • 88. DI Container Hello World example $container = new sfServiceContainer(); $outputDef = new sfServiceDefinition('FancyOutput'); $container->setServiceDefinition('output', $outputDef); $msgDef = new sfServiceDefinition( 'Message', array(new sfServiceReference('output'), array('with_newline' => true)) ); $container->setServiceDefinition('message', $msgDef); $container->message->say('Hello World!');
  • 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
  • 90. $message = $container->message; is roughly equivalent to $output = new FancyOutput(); $message = new Message($output, array('with_newline' => true));!
  • 91. $container = new sfServiceContainer(); $msgDef = new sfServiceDefinition( 'Message', array(new sfServiceReference('output'), array('with_newline' => true)) ); $outputDef = new sfServiceDefinition('FancyOutput'); PHP $container->setServiceDefinition('message', $msgDef); $container->setServiceDefinition('output', $outputDef); <services> <service id="output" class="FancyOutput" /> XML <service id="message" class="Message"> <argument type="service" id="output" /> <argument type="collection"> <argument key="with_newline">true</argument> </argument> </service> </services> $container = new sfServiceContainer(new sfServiceLoaderXml()); $container->load('services.xml');
  • 92. <services> <parameters> <parameter key="output.class">FancyOutput</parameter> <parameter key="message.options" type="collection"> <parameter key="with_newline">true</parameter> </parameter> </parameters> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> $container = new sfServiceContainer(new sfServiceLoaderXml()); $container->load('services.xml');
  • 93. <services> <import resource="config.xml" /> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> <services> <parameters> <parameter key="output.class">FancyOutput</parameter> <parameter key="message.options" type="collection"> <parameter key="with_newline">true</parameter> </parameter> </parameters> </services> $container = new sfServiceContainer(new sfServiceLoaderXml()); $container->load('services.xml');
  • 94. <services> <import resource="config.yml" class="sfServiceLoaderYamlParameters" /> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> output.class: FancyOutput message.options: with_newline: true $container = new sfServiceContainer(new sfServiceLoaderXml()); $container->load('services.xml');
  • 95. $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...'));
  • 96. $pdo = new PDO('sqlite::memory:'); <service id="pdo" class="PDO"> <argument>sqlite::memory:</argument> </service>
  • 97. $container = new sfServiceContainer(new sfServiceLoaderXml()); $container->load(dirname(__FILE__).'/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...'));
  • 98. <services> <import resource="config.yml" class="sfServiceLoaderYamlParameters" /> <import resource="template_loader.xml" /> <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>
  • 99. <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>
  • 100. <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>
  • 102. Sensio S.A. 92-98, boulevard Victor 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/