<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.fabien.potencier.org/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:base="http://fabien.potencier.org/">
  <title>Fabien Potencier</title>
  <link href="http://fabien.potencier.org/" />
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>

      <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.fabien.potencier.org/aidedecamp" /><feedburner:info uri="aidedecamp" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
  <title>Sami: Yet another PHP API documentation generator</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/1NqPufqqSeg/sami-yet-another-php-api-documentation-generator" />
  <id>article-63</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-05-15T13:58:00+02:00</updated>
  <content type="html">
    &lt;p&gt;Today is my "&lt;em&gt;let open source some of my private Github repositories&lt;/em&gt;" day,
and more specifically, I'm releasing a bunch of code related to documentation.&lt;/p&gt;

&lt;p&gt;Earlier today, I've released the Sphinx
&lt;a href="https://github.com/fabpot/sphinx-php"&gt;extensions&lt;/a&gt; I'm using to generate the
&lt;a href="http://symfony.com/doc"&gt;Symfony&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;And now, I'm releasing my API documentation
&lt;a href="https://github.com/fabpot/Sami"&gt;generator&lt;/a&gt;. Yes, I know that PHP already has
a bunch of such generators, but I started to work on this project several
years ago, when the only viable option was the old phpdocumentor.&lt;/p&gt;

&lt;p&gt;Nowadays, &lt;a href="http://phpdoc.org/"&gt;phpDocumentor&lt;/a&gt; version 2 is probably the best
option out there as it has a good architecture, it works fine, it is
extensible, and quite a few big PHP projects is already using it. And that's
fine. I don't want to compete with it, I don't want to replace it, I'm just
open sourcing some code used by &lt;a href="http://api.symfony.com/"&gt;Symfony&lt;/a&gt;,
&lt;a href="http://silex.sensiolabs.org/api/index.html"&gt;Twig&lt;/a&gt;, and
&lt;a href="http://silex.sensiolabs.org/api/index.html"&gt;Silex&lt;/a&gt; because I'm not
comfortable with closed-source software. And to be totally honest and
transparent, I have not released the code before because it was not "good
enough".&lt;/p&gt;

&lt;p&gt;With this disclaimer out of the way, let's see what makes Sami "different"
(compared to phpdocumentor)?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It uses a PHP file for configuration to give a very flexible way of
tweaking the API generation;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It uses &lt;a href="http://twig.sensiolabs.org/"&gt;Twig&lt;/a&gt; for templating;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It uses a dependency injection container
(&lt;a href="https://github.com/fabpot/Pimple"&gt;Pimple&lt;/a&gt;) to let you override any
internal class;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It only works with PHP 5.3 (but it can generate documentation for PHP 5.2
projects);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It uses the excellent &lt;a href="https://github.com/nikic/PHP-Parser"&gt;PHP Parser&lt;/a&gt;
project for PHP code parsing;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is able to manage versions of your code to generate documentation for
all of them in a single tree (without the overhead of re-parsing everything
for each version of course).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Curious about what Sami generates? Have a look at the &lt;a href="http://api.symfony.com/"&gt;Symfony
API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;First, get Sami from &lt;a href="https://github.com/fabpot/Sami"&gt;Github&lt;/a&gt; (or integrate it
as a dependency in your project &lt;a href="http://packagist.org/packages/sami/sami"&gt;Composer&lt;/a&gt; file --
you are using &lt;a href="http://getcomposer.org/"&gt;Composer&lt;/a&gt;, right?):&lt;/p&gt;

&lt;pre class="text"&gt;https://github.com/fabpot/Sami
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;You can also download an &lt;a href="https://github.com/fabpot/Sami/downloads"&gt;archive&lt;/a&gt;
from Github.&lt;/p&gt;

&lt;p&gt;As Sami uses Composer to manage its dependencies, installing it is a matter of
running composer:&lt;/p&gt;

&lt;pre class="command-line"&gt;&lt;code&gt;$ composer.phar install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Check that everything worked as expected by executing the &lt;code&gt;sami.php&lt;/code&gt; file
without any arguments:&lt;/p&gt;

&lt;pre class="command-line"&gt;&lt;code&gt;$ php sami.php
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Configuration&lt;/h2&gt;

&lt;p&gt;Before generating documentation, you must create a configuration file. Here is
the simplest possible one:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Sami\Sami&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/path/to/symfony/src'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The configuration file must return an instance of &lt;code&gt;Sami\Sami&lt;/code&gt; and the first
argument of the constructor is the path to the code you want to generate
documentation for.&lt;/p&gt;

&lt;p&gt;Actually, instead of a directory, you can use any valid PHP iterator (and for
that matter any instance of the Symfony
&lt;a href="http://symfony.com/doc/current/components/finder.html"&gt;Finder&lt;/a&gt; class):&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
use Sami\Sami;
use Symfony\Component\Finder\Finder;
&amp;nbsp;
&lt;span class="re0"&gt;$iterator&lt;/span&gt; = Finder::&lt;span class="me2"&gt;create&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;files&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;name&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'*.php'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;exclude&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Resources'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;exclude&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Tests'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;in&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/path/to/symfony/src'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Sami&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$iterator&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Sami&lt;/code&gt; constructor optionally takes an array of options as a second
argument:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Sami&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$iterator&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'theme'&lt;/span&gt;                =&amp;gt; &lt;span class="st0"&gt;'symfony'&lt;/span&gt;,
    &lt;span class="st0"&gt;'title'&lt;/span&gt;                =&amp;gt; &lt;span class="st0"&gt;'Symfony2 API'&lt;/span&gt;,
    &lt;span class="st0"&gt;'build_dir'&lt;/span&gt;            =&amp;gt; __DIR__.&lt;span class="st0"&gt;'/build'&lt;/span&gt;,
    &lt;span class="st0"&gt;'cache_dir'&lt;/span&gt;            =&amp;gt; __DIR__.&lt;span class="st0"&gt;'/cache'&lt;/span&gt;,
    &lt;span class="st0"&gt;'default_opened_level'&lt;/span&gt; =&amp;gt; &lt;span class="nu0"&gt;2&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And here is how you can configure different versions:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
use Sami\Sami;
use Sami\Version\GitVersionCollection;
use Symfony\Component\Finder\Finder;
&amp;nbsp;
&lt;span class="re0"&gt;$iterator&lt;/span&gt; = Finder::&lt;span class="me2"&gt;create&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;files&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;name&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'*.php'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;exclude&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Resources'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;exclude&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Tests'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;in&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$dir&lt;/span&gt; = &lt;span class="st0"&gt;'/path/to/symfony/src'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;
&lt;span class="co1"&gt;// generate documentation for all v2.0.* tags, the 2.0 branch, and the master one&lt;/span&gt;
&lt;span class="re0"&gt;$versions&lt;/span&gt; = GitVersionCollection::&lt;span class="me2"&gt;create&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$dir&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;addFromTags&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'v2.0.*'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'2.0'&lt;/span&gt;, &lt;span class="st0"&gt;'2.0 branch'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'master'&lt;/span&gt;, &lt;span class="st0"&gt;'master branch'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Sami&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$iterator&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'theme'&lt;/span&gt;                =&amp;gt; &lt;span class="st0"&gt;'symfony'&lt;/span&gt;,
    &lt;span class="st0"&gt;'versions'&lt;/span&gt;             =&amp;gt; &lt;span class="re0"&gt;$versions&lt;/span&gt;,
    &lt;span class="st0"&gt;'title'&lt;/span&gt;                =&amp;gt; &lt;span class="st0"&gt;'Symfony2 API'&lt;/span&gt;,
    &lt;span class="st0"&gt;'build_dir'&lt;/span&gt;            =&amp;gt; __DIR__.&lt;span class="st0"&gt;'/../build/sf2/%version%'&lt;/span&gt;,
    &lt;span class="st0"&gt;'cache_dir'&lt;/span&gt;            =&amp;gt; __DIR__.&lt;span class="st0"&gt;'/../cache/sf2/%version%'&lt;/span&gt;,
    &lt;span class="st0"&gt;'default_opened_level'&lt;/span&gt; =&amp;gt; &lt;span class="nu0"&gt;2&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To generate documentation for a PHP 5.2 project, simply set the
&lt;code&gt;simulate_namespaces&lt;/code&gt; option to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Rendering&lt;/h2&gt;

&lt;p&gt;Now that we have a configuration file, let's generate the API documentation:&lt;/p&gt;

&lt;pre class="command-line"&gt;&lt;code&gt;$ php sami.php update /path/to/config.php
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The generated documentation can be found under the configured &lt;code&gt;build/&lt;/code&gt;
directory (note that the client side search engine does not work on Chrome due
to JavaScript execution restriction -- it works fine in Firefox).&lt;/p&gt;

&lt;p&gt;By default, Sami is configured to run in "incremental" mode. It means that
when running the &lt;code&gt;update&lt;/code&gt; command, Sami only re-generates the files that need
to be updated based on what has changed in your code since the last execution.&lt;/p&gt;

&lt;p&gt;Sami also detects problems in your phpdoc and can tell you what you need to
fix if you add the &lt;code&gt;-v&lt;/code&gt; option:&lt;/p&gt;

&lt;pre class="command-line"&gt;&lt;code&gt;$ php sami.php update /path/to/config.php -v
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Creating a Theme&lt;/h2&gt;

&lt;p&gt;If the default themes do not suit your needs, you can very easily create a new
one, or just override an existing one.&lt;/p&gt;

&lt;p&gt;A theme is just a directory with a &lt;code&gt;manifest.yml&lt;/code&gt; file that describes the
theme (this is a YAML file):&lt;/p&gt;

&lt;pre class="php"&gt;name:   symfony
parent: enhanced
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The above configuration creates a new &lt;code&gt;symfony&lt;/code&gt; theme based on the &lt;code&gt;enhanced&lt;/code&gt;
built-in theme. To override a template, just create a file with the same name
as the original one. For instance, here is how you can extend the default
class template to prefix the class name with "Class " in the class page title:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;&lt;span class="co2"&gt;# pages/class.twig #}&lt;/span&gt;
&amp;nbsp;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;% &lt;span class="kw2"&gt;extends&lt;/span&gt; &lt;span class="st0"&gt;'default/pages/class.twig'&lt;/span&gt; %&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;% block title %&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;&lt;span class="kw2"&gt;Class&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt; parent&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;% endblock %&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;If you are familiar with Twig, you will be able to very easily tweak every
aspect of the templates as everything has been well isolated in named Twig
blocks.&lt;/p&gt;

&lt;p&gt;A theme can also add more templates and static files. Here is the manifest for
the default theme:&lt;/p&gt;

&lt;pre class="php"&gt;name: &lt;span class="kw2"&gt;default&lt;/span&gt;
&amp;nbsp;
&lt;a href="http://www.php.net/static"&gt;&lt;span class="kw3"&gt;static&lt;/span&gt;&lt;/a&gt;:
    &lt;span class="st0"&gt;'stylesheet.css'&lt;/span&gt;:        &lt;span class="st0"&gt;'stylesheet.css'&lt;/span&gt;
&amp;nbsp;
&lt;a href="http://www.php.net/global"&gt;&lt;span class="kw3"&gt;global&lt;/span&gt;&lt;/a&gt;:
    &lt;span class="st0"&gt;'index.twig'&lt;/span&gt;:            &lt;span class="st0"&gt;'index.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'namespaces.twig'&lt;/span&gt;:       &lt;span class="st0"&gt;'namespaces-frame.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'classes.twig'&lt;/span&gt;:          &lt;span class="st0"&gt;'classes-frame.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'pages/opensearch.twig'&lt;/span&gt;: &lt;span class="st0"&gt;'opensearch.xml'&lt;/span&gt;
    &lt;span class="st0"&gt;'pages/index.twig'&lt;/span&gt;:      &lt;span class="st0"&gt;'doc-index.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'pages/namespaces.twig'&lt;/span&gt;: &lt;span class="st0"&gt;'namespaces.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'pages/interfaces.twig'&lt;/span&gt;: &lt;span class="st0"&gt;'interfaces.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'pages/classes.twig'&lt;/span&gt;:    &lt;span class="st0"&gt;'classes.html'&lt;/span&gt;
&amp;nbsp;
namespace:
    &lt;span class="st0"&gt;'namespace.twig'&lt;/span&gt;:        &lt;span class="st0"&gt;'%s/namespace-frame.html'&lt;/span&gt;
    &lt;span class="st0"&gt;'pages/namespace.twig'&lt;/span&gt;:  &lt;span class="st0"&gt;'%s.html'&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt;:
    &lt;span class="st0"&gt;'pages/class.twig'&lt;/span&gt;:      &lt;span class="st0"&gt;'%s.html'&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Files are contained into sections, depending on how Sami needs to treat them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;static&lt;/code&gt;: Files are copied as is (for assets like images, stylesheets, or
JavaScript files);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;global&lt;/code&gt;: Templates that do not depend on the current class context;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;namespace&lt;/code&gt;: Templates that should be generated for every namespace;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;class&lt;/code&gt;: Templates that should be generated for every class.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all there is to it for now. More documentation and a website is coming soon.&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/1NqPufqqSeg" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/63/sami-yet-another-php-api-documentation-generator</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 12)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/2xeMj6zRXu8/create-your-own-framework-on-top-of-the-symfony2-components-part-12" />
  <id>article-62</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-25T07:39:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the last installment of this series, we have emptied the
&lt;code&gt;Simplex\\Framework&lt;/code&gt; class by extending the &lt;code&gt;HttpKernel&lt;/code&gt; class from
Symfony. Seeing this empty class, you might be tempted to move some code from
the front controller to it:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/Framework.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\Routing;
use Symfony\Component\HttpKernel;
use Symfony\Component\EventDispatcher\EventDispatcher;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework &lt;span class="kw2"&gt;extends&lt;/span&gt; HttpKernel\HttpKernel
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; __construct&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\Controller\ControllerResolver&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="re0"&gt;$dispatcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; EventDispatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\RouterListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\ResponseListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'UTF-8'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        parent::__construct&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The front controller code would become more concise:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Having a more concise front controller means that you can have more than one
for a single application. Why would it be useful? To allow having different
configuration for the development environment and the production one for
instance. In the development environment, you might want to have error
reporting turned on and errors displayed in the browser to ease debugging:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;a href="http://www.php.net/ini_set"&gt;&lt;span class="kw3"&gt;ini_set&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'display_errors'&lt;/span&gt;, &lt;span class="nu0"&gt;1&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;a href="http://www.php.net/error_reporting"&gt;&lt;span class="kw3"&gt;error_reporting&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;-1&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;... but you certainly won't want that same configuration on the production
environment. Having two different front controllers gives you the opportunity
to have a slightly different configuration for each of them.&lt;/p&gt;

&lt;p&gt;So, moving code from the front controller to the framework class makes our
framework more configurable, but at the same time, it introduces a lot of
issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We are not able to register custom listeners anymore as the dispatcher is
not available outside the Framework class (an easy workaround could be the
adding of a &lt;code&gt;Framework::getEventDispatcher()&lt;/code&gt; method);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We have lost the flexibility we had before; you cannot change the
implementation of the &lt;code&gt;UrlMatcher&lt;/code&gt; or of the &lt;code&gt;ControllerResolver&lt;/code&gt; anymore;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Related to the previous point, we cannot test our framework easily anymore
as it's impossible to mock internal objects;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We cannot change the charset passed to ResponseListener anymore (a
workaround could be to pass it as a constructor argument).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The previous code did not exhibit the same issues because we used dependency
injection; all dependencies of our objects were injected into their
constructors (for instance, the event dispatcher were injected into the
framework so that we had total control of its creation and configuration).&lt;/p&gt;

&lt;p&gt;Does it means that we have to make a choice between flexibility,
customization, ease of testing and not having to copy and paste the same code
into each application front controller? As you might expect, there is a
solution. We can solve all these issues and some more by using the Symfony2
dependency injection container:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="st0"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;symfony/class-loader&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-foundation&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/routing&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-kernel&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/event-dispatcher&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/dependency-injection&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;,
    &lt;span class="st0"&gt;&amp;quot;autoload&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;psr-0&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt; &lt;span class="st0"&gt;&amp;quot;Simplex&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;src/&amp;quot;&lt;/span&gt;, &lt;span class="st0"&gt;&amp;quot;Calendar&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;src/&amp;quot;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Create a new file to host the dependency injection container configuration:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/container.php&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Reference;
&amp;nbsp;
&lt;span class="re0"&gt;$sc&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; DependencyInjection\ContainerBuilder&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'context'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\R&lt;/span&gt;outing&lt;span class="es0"&gt;\R&lt;/span&gt;equestContext'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'matcher'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\R&lt;/span&gt;outing&lt;span class="es0"&gt;\M&lt;/span&gt;atcher&lt;span class="es0"&gt;\U&lt;/span&gt;rlMatcher'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'context'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'resolver'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\H&lt;/span&gt;ttpKernel&lt;span class="es0"&gt;\C&lt;/span&gt;ontroller&lt;span class="es0"&gt;\C&lt;/span&gt;ontrollerResolver'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.router'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\H&lt;/span&gt;ttpKernel&lt;span class="es0"&gt;\E&lt;/span&gt;ventListener&lt;span class="es0"&gt;\R&lt;/span&gt;outerListener'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'matcher'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.response'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\H&lt;/span&gt;ttpKernel&lt;span class="es0"&gt;\E&lt;/span&gt;ventListener&lt;span class="es0"&gt;\R&lt;/span&gt;esponseListener'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'UTF-8'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.exception'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\H&lt;/span&gt;ttpKernel&lt;span class="es0"&gt;\E&lt;/span&gt;ventListener&lt;span class="es0"&gt;\E&lt;/span&gt;xceptionListener'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Calendar&lt;span class="es0"&gt;\\&lt;/span&gt;Controller&lt;span class="es0"&gt;\\&lt;/span&gt;ErrorController::exceptionAction'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'dispatcher'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\E&lt;/span&gt;ventDispatcher&lt;span class="es0"&gt;\E&lt;/span&gt;ventDispatcher'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;addMethodCall&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'addSubscriber'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.router'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;addMethodCall&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'addSubscriber'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.response'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;addMethodCall&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'addSubscriber'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.exception'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'framework'&lt;/span&gt;, &lt;span class="st0"&gt;'Simplex&lt;span class="es0"&gt;\F&lt;/span&gt;ramework'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'dispatcher'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'resolver'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$sc&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The goal of this file is to configure your objects and their dependencies.
Nothing is instantiated during this configuration step. This is purely a
static description of the objects you need to manipulate and how to create
them. Objects will be created on-demand when you access them from the
container or when the container needs them to create other objects.&lt;/p&gt;

&lt;p&gt;For instance, to create the router listener, we tell Symfony that its class
name is &lt;code&gt;Symfony\Component\HttpKernel\EventListener\RouterListeners&lt;/code&gt;, and
that its constructor takes a matcher object (&lt;code&gt;new Reference('matcher')&lt;/code&gt;). As
you can see, each object is referenced by a name, a string that uniquely
identifies each object. The name allows us to get an object and to reference
it in other object definitions.&lt;/p&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  By default, every time you get an object from the container, it returns the
  exact same instance. That's because a container manages your "global" objects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The front controller is now only about wiring everything together:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
&amp;nbsp;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&lt;span class="re0"&gt;$sc&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/container.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'framework'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;As all the objects are now created in the dependency injection container, the framework code should be the previous simple version:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/Framework.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\HttpKernel\HttpKernel;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework &lt;span class="kw2"&gt;extends&lt;/span&gt; HttpKernel
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  If you want a light alternative for your container, consider
  &lt;a href="https://github.com/fabpot/Pimple"&gt;Pimple&lt;/a&gt;, a simple dependency injection
  container in about 60 lines of PHP code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, here is how you can register a custom listener in the front controller:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.string_response'&lt;/span&gt;, &lt;span class="st0"&gt;'Simplex&lt;span class="es0"&gt;\S&lt;/span&gt;tringResponseListener'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getDefinition&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'dispatcher'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;addMethodCall&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'addSubscriber'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.string_response'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Beside describing your objects, the dependency injection container can also be
configured via parameters. Let's create one that defines if we are in debug
mode or not:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setParameter&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'debug'&lt;/span&gt;, &lt;span class="kw2"&gt;true&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getParameter&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'debug'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;These parameters can be used when defining object definitions. Let's make the
charset configurable:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'listener.response'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\H&lt;/span&gt;ttpKernel&lt;span class="es0"&gt;\E&lt;/span&gt;ventListener&lt;span class="es0"&gt;\R&lt;/span&gt;esponseListener'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'%charset%'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;After this change, you must set the charset before using the response listener
object:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setParameter&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'charset'&lt;/span&gt;, &lt;span class="st0"&gt;'UTF-8'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Instead of relying on the convention that the routes are defined by the
&lt;code&gt;$routes&lt;/code&gt; variables, let's use a parameter again:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;register&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'matcher'&lt;/span&gt;, &lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\R&lt;/span&gt;outing&lt;span class="es0"&gt;\M&lt;/span&gt;atcher&lt;span class="es0"&gt;\U&lt;/span&gt;rlMatcher'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    -&amp;gt;&lt;span class="me1"&gt;setArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'%routes%'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Reference&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'context'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And the related change in the front controller:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$sc&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setParameter&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'routes'&lt;/span&gt;, &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;We have obviously barely scratched the surface of what you can do with the
container: from class names as parameters, to overriding existing object
definitions, from scope support to dumping a container to a plain PHP class,
and much more. The Symfony dependency injection container is really powerful
and is able to manage any kind of PHP classes.&lt;/p&gt;

&lt;p&gt;Don't yell at me if you don't want to have a dependency injection container in
your framework. If you don't like it, don't use it. It's your framework, not
mine.&lt;/p&gt;

&lt;p&gt;This is (already) the last part of my series on creating a framework on top of
the Symfony2 components. I'm aware that many topics have not been covered in
great details, but hopefully it gives you enough information to get started on
your own and to better understand how the Symfony2 framework works internally.&lt;/p&gt;

&lt;p&gt;If you want to learn more, I highly recommend you to read the source code of
the Silex micro-framework, and especially its &lt;a href="https://github.com/fabpot/Silex/blob/master/src/Silex/Application.php"&gt;Application&lt;/a&gt; class.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

&lt;p&gt;~~ FIN ~~&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S.:&lt;/em&gt; If there is enough interest (leave a comment on this post), I might
write some more articles on specific topics (using a configuration file for
routing, using HttpKernel debugging tools, using the build-in client to
simulate a browser are some of the topics that come to my mind for instance).&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/2xeMj6zRXu8" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 11)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/vDmSnN58Svs/create-your-own-framework-on-top-of-the-symfony2-components-part-11" />
  <id>article-60</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-23T13:51:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you were to use our framework right now, you would probably have to add
support for custom error messages. Right now, we have 404 and 500 error
support but the responses are hardcoded in the framework itself. Making them
customizable is easy enough though: dispatch a new event and listen to it.
Doing it right means that the listener has to call a regular controller. But
what if the error controller throws an exception? You will end up in an
infinite loop. There should be an easier way, right?&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;HttpKernel&lt;/code&gt; class. Instead of solving the same problem over and
over again and instead of reinventing the wheel each time, the &lt;code&gt;HttpKernel&lt;/code&gt;
class is a generic, extensible, and flexible implementation of
&lt;code&gt;HttpKernelInterface&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This class is very similar to the framework class we have written so far: it
dispatches events at some strategic points during the handling of the request,
it uses a controller resolver to choose the controller to dispatch the request
to, and as an added bonus, it takes care of edge cases and provides great
feedback when a problem arises.&lt;/p&gt;

&lt;p&gt;Here is the new framework code:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/Framework.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\HttpKernel\HttpKernel;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework &lt;span class="kw2"&gt;extends&lt;/span&gt; HttpKernel
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And the new front controller:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;
use Symfony\Component\HttpKernel;
use Symfony\Component\EventDispatcher\EventDispatcher;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\Controller\ControllerResolver&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; EventDispatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\RouterListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;RouterListener&lt;/code&gt; is an implementation of the same logic we had in our
framework: it matches the incoming request and populates the request
attributes with route parameters.&lt;/p&gt;

&lt;p&gt;Our code is now much more concise and surprisingly more robust and more
powerful than ever. For instance, use the built-in &lt;code&gt;ExceptionListener&lt;/code&gt; to
make your error management configurable:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$errorHandler&lt;/span&gt; = &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;HttpKernel\Exception\FlattenException &lt;span class="re0"&gt;$exception&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$msg&lt;/span&gt; = &lt;span class="st0"&gt;'Something went wrong! ('&lt;/span&gt;.&lt;span class="re0"&gt;$exception&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getMessage&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;.&lt;span class="st0"&gt;')'&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$msg&lt;/span&gt;, &lt;span class="re0"&gt;$exception&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getStatusCode&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\ExceptionListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$errorHandler&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;ExceptionListener&lt;/code&gt; gives you a &lt;code&gt;FlattenException&lt;/code&gt; instance instead of the
thrown &lt;code&gt;Exception&lt;/code&gt; instance to ease exception manipulation and display. It
can take any valid controller as an exception handler, so you can create an
ErrorController class instead of using a Closure:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$listener&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\ExceptionListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Calendar&lt;span class="es0"&gt;\\&lt;/span&gt;Controller&lt;span class="es0"&gt;\\&lt;/span&gt;ErrorController::exceptionAction'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$listener&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The error controller reads as follows:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Calendar/Controller/ErrorController.php&lt;/span&gt;
&amp;nbsp;
namespace Calendar\Controller;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\FlattenException;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; ErrorController
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; exceptionAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;FlattenException &lt;span class="re0"&gt;$exception&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$msg&lt;/span&gt; = &lt;span class="st0"&gt;'Something went wrong! ('&lt;/span&gt;.&lt;span class="re0"&gt;$exception&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getMessage&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;.&lt;span class="st0"&gt;')'&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$msg&lt;/span&gt;, &lt;span class="re0"&gt;$exception&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getStatusCode&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Voilà! Clean and customizable error management without efforts. And of course,
if your controller throws an exception, HttpKernel will handle it nicely.&lt;/p&gt;

&lt;p&gt;In part 2, we have talked about the &lt;code&gt;Response::prepare()&lt;/code&gt; method, which
ensures that a Response is compliant with the HTTP specification. It is
probably a good idea to always call it just before sending the Response to the
client; that's what the &lt;code&gt;ResponseListener&lt;/code&gt; does:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\ResponseListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'UTF-8'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;This one was easy too! Let's take another one: do you want out of the box
support for streamed responses? Just subscribe to
&lt;code&gt;StreamedResponseListener&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\EventListener\StreamedResponseListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And in your controller, return a &lt;code&gt;StreamedResponse&lt;/code&gt; instance instead of a
&lt;code&gt;Response&lt;/code&gt; instance.&lt;/p&gt;

&lt;blockquote class="tip"&gt;&lt;p&gt;
  Read the &lt;a href="http://symfony.com/doc/current/book/internals.html#events"&gt;Internals&lt;/a&gt; chapter of the Symfony2 documentation to learn more
  about the events dispatched by HttpKernel and how they allow you to change the
  flow of a request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's create a listener, one that allows a controller to return a string
instead of a full Response object:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;class&lt;/span&gt; LeapYearController
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$leapyear&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; LeapYear&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$leapyear&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;isLeapYear&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="st0"&gt;'Yep, this is a leap year! '&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="st0"&gt;'Nope, this is not a leap year.'&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To implement this feature, we are going to listen to the &lt;code&gt;kernel.view&lt;/code&gt;
event, which is triggered just after the controller has been called. Its goal
is to convert the controller return value to a proper Response instance, but
only if needed:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/StringResponseListener.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpFoundation\Response;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; StringResponseListener implements EventSubscriberInterface
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; onView&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;GetResponseForControllerResultEvent &lt;span class="re0"&gt;$event&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getControllerResult&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/is_string"&gt;&lt;span class="kw3"&gt;is_string&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setResponse&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;a href="http://www.php.net/static"&gt;&lt;span class="kw3"&gt;static&lt;/span&gt;&lt;/a&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; getSubscribedEvents&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'kernel.view'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'onView'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The code is simple because the &lt;code&gt;kernel.view&lt;/code&gt; event is only triggered when
the controller return value is not a Response and because setting the response
on the event stops the event propagation (our listener cannot interfere with
other view listeners).&lt;/p&gt;

&lt;p&gt;Don't forget to register it in the front controller:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\StringResponseListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  If you forget to register the subscriber, HttpKernel will throw an exception
  with a nice message: &lt;code&gt;The controller must return a response (Nope, this is not
  a leap year. given).&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this point, our whole framework code is as compact as possible and it is
mainly composed of an assembly of existing libraries. Extending is a matter
of registering event listeners/subscribers.&lt;/p&gt;

&lt;p&gt;Hopefully, you now have a better understanding of why the simple looking
&lt;code&gt;HttpKernelInterface&lt;/code&gt; is so powerful. Its default implementation,
&lt;code&gt;HttpKernel&lt;/code&gt;, gives you access to a lot of cool features, ready to be used
out of the box, with no efforts. And because HttpKernel is actually the code
that powers the Symfony2 and Silex frameworks, you have the best of both
worlds: a custom framework, tailored to your needs, but based on a rock-solid
and well maintained low-level architecture that has been proven to work for
many websites; a code that has been audited for security issues and that has
proven to scale well.&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/vDmSnN58Svs" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 10)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/KEEHrRWsrZo/create-your-own-framework-on-top-of-the-symfony2-components-part-10" />
  <id>article-59</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-21T08:43:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the conclusion of the second part of this series, I've talked about one
great benefit of using the Symfony2 components: the &lt;em&gt;interoperability&lt;/em&gt; between
all frameworks and applications using them. Let's do a big step towards this
goal by making our framework implement &lt;code&gt;HttpKernelInterface&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;namespace Symfony\Component\HttpKernel;
&amp;nbsp;
&lt;span class="kw2"&gt;interface&lt;/span&gt; HttpKernelInterface
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="coMULTI"&gt;/**
     * @return Response A Response instance
     */&lt;/span&gt;
    &lt;span class="kw2"&gt;function&lt;/span&gt; handle&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$type&lt;/span&gt; = self::&lt;span class="me2"&gt;MASTER_REQUEST&lt;/span&gt;, &lt;span class="re0"&gt;$catch&lt;/span&gt; = &lt;span class="kw2"&gt;true&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;HttpKernelInterface&lt;/code&gt; is probably the most important piece of code in the
HttpKernel component, no kidding. Frameworks and applications that implement
this interface are fully interoperable. Moreover, a lot of great features will
come with it for free.&lt;/p&gt;

&lt;p&gt;Update your framework so that it implements this interface:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Framework.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\HttpKernel\HttpKernelInterface;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework implements HttpKernelInterface
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; handle&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$type&lt;/span&gt; = HttpKernelInterface::&lt;span class="me2"&gt;MASTER_REQUEST&lt;/span&gt;, &lt;span class="re0"&gt;$catch&lt;/span&gt; = &lt;span class="kw2"&gt;true&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="co1"&gt;// ...&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Even if this change looks trivial, it brings us a lot! Let's talk about one of
the most impressive one: transparent &lt;a href="http://symfony.com/doc/current/book/http_cache.html"&gt;HTTP caching&lt;/a&gt; support.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HttpCache&lt;/code&gt; class implements a fully-featured reverse proxy, written in
PHP; it implements &lt;code&gt;HttpKernelInterface&lt;/code&gt; and wraps another
&lt;code&gt;HttpKernelInterface&lt;/code&gt; instance:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\Store;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;, &lt;span class="re0"&gt;$matcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpCache&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$framework&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Store&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../cache'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;That's all it takes to add HTTP caching support to our framework. Isn't it
amazing?&lt;/p&gt;

&lt;p&gt;Configuring the cache needs to be done via HTTP cache headers. For instance,
to cache a response for 10 seconds, use the &lt;code&gt;Response::setTtl()&lt;/code&gt; method::&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="co1"&gt;// example.com/src/Calendar/Controller/LeapYearController.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$leapyear&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; LeapYear&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$leapyear&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;isLeapYear&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Yep, this is a leap year!'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; &lt;span class="kw1"&gt;else&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Nope, this is not a leap year.'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setTtl&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;10&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$response&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="tip"&gt;&lt;p&gt;
  If, like me, you are running your framework from the command line by
  simulating requests (&lt;code&gt;Request::create('/is_leap_year/2012')&lt;/code&gt;), you can easily
  debug Response instances by dumping their string representation (&lt;code&gt;echo
  $response;&lt;/code&gt;) as it displays all headers as well as the response content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To validate that it works correctly, add a random number to the response
content and check that the number only changes every 10 seconds:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Yep, this is a leap year! '&lt;/span&gt;.&lt;a href="http://www.php.net/rand"&gt;&lt;span class="kw3"&gt;rand&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  When deploying to your production environment, keep using the Symfony2 reverse
  proxy (great for shared hosting) or even better, switch to a more efficient
  reverse proxy like &lt;a href="https://www.varnish-cache.org/"&gt;Varnish&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using HTTP cache headers to manage your application cache is very powerful and
allows you to tune finely your caching strategy as you can use both the
expiration and the validation models of the HTTP specification. If you are not
comfortable with these concepts, I highly recommend you to read the &lt;a href="http://symfony.com/doc/current/book/http_cache.html"&gt;HTTP
caching&lt;/a&gt; chapter of the Symfony2 documentation.&lt;/p&gt;

&lt;p&gt;The Response class contains many other methods that let you configure the
HTTP cache very easily. One of the most powerful is &lt;code&gt;setCache()&lt;/code&gt; as it
abstracts the most frequently used caching strategies into one simple array:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$date&lt;/span&gt; = date_create_from_format&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Y-m-d H:i:s'&lt;/span&gt;, &lt;span class="st0"&gt;'2005-10-15 10:00:00'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setCache&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'public'&lt;/span&gt;        =&amp;gt; &lt;span class="kw2"&gt;true&lt;/span&gt;,
    &lt;span class="st0"&gt;'etag'&lt;/span&gt;          =&amp;gt; &lt;span class="st0"&gt;'abcde'&lt;/span&gt;,
    &lt;span class="st0"&gt;'last_modified'&lt;/span&gt; =&amp;gt; &lt;span class="re0"&gt;$date&lt;/span&gt;,
    &lt;span class="st0"&gt;'max_age'&lt;/span&gt;       =&amp;gt; &lt;span class="nu0"&gt;10&lt;/span&gt;,
    &lt;span class="st0"&gt;'s_maxage'&lt;/span&gt;      =&amp;gt; &lt;span class="nu0"&gt;10&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="co1"&gt;// it is equivalent to the following code&lt;/span&gt;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setPublic&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setEtag&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'abcde'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setLastModified&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$date&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setMaxAge&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;10&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setSharedMaxAge&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;10&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;When using the validation model, the &lt;code&gt;isNotModified()&lt;/code&gt; method allows you to
easily cut on the response time by short-circuiting the response generation as
early as possible:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setETag&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'whatever_you_compute_as_an_etag'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;isNotModified&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$response&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'The computed content of the response'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$response&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Using HTTP caching is great, but what if you cannot cache the whole page? What
if you can cache everything but some sidebar that is more dynamic that the
rest of the content? Edge Side Includes (&lt;a href="http://en.wikipedia.org/wiki/Edge_Side_Includes"&gt;ESI&lt;/a&gt;) to the rescue! Instead of
generating the whole content in one go, ESI allows you to mark a region of a
page as being the content of a sub-request call:&lt;/p&gt;

&lt;pre class="php"&gt;This is the content of your page
&amp;nbsp;
Is &lt;span class="nu0"&gt;2012&lt;/span&gt; a leap year? &amp;lt;esi:&lt;span class="kw1"&gt;include&lt;/span&gt; src=&lt;span class="st0"&gt;&amp;quot;/leapyear/2012&amp;quot;&lt;/span&gt; /&amp;gt;
&amp;nbsp;
Some other content
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;For ESI tags to be supported by HttpCache, you need to pass it an instance of
the &lt;code&gt;ESI&lt;/code&gt; class. The &lt;code&gt;ESI&lt;/code&gt; class automatically parses ESI tags and makes
sub-requests to convert them to their proper content:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\HttpKernel\HttpCache\ESI;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpCache&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$framework&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Store&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../cache'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; ESI&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  For ESI to work, you need to use a reverse proxy that supports it like the
  Symfony2 implementation. &lt;a href="https://www.varnish-cache.org/"&gt;Varnish&lt;/a&gt; is the best alternative and it is
  Open-Source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When using complex HTTP caching strategies and/or many ESI include tags, it
can be hard to understand why and when a resource should be cached or not. To
ease debugging, you can enable the debug mode:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpCache&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$framework&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Store&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../cache'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; ESI&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'debug'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;true&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The debug mode adds a &lt;code&gt;X-Symfony-Cache&lt;/code&gt; header to each response that
describes what the cache layer did:&lt;/p&gt;

&lt;pre class="php"&gt;X-Symfony-Cache:  GET /is_leap_year/&lt;span class="nu0"&gt;2012&lt;/span&gt;: stale, invalid, store
&amp;nbsp;
X-Symfony-Cache:  GET /is_leap_year/&lt;span class="nu0"&gt;2012&lt;/span&gt;: fresh
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;HttpCache has many features like support for the
&lt;code&gt;stale-while-revalidate&lt;/code&gt; and &lt;code&gt;stale-if-error&lt;/code&gt; HTTP Cache-Control
extensions as defined in RFC 5861.&lt;/p&gt;

&lt;p&gt;With the addition of a single interface, our framework can now benefit from
the many features built into the HttpKernel component; HTTP caching being just
one of them but an important one as it can make your applications fly!&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/KEEHrRWsrZo" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 9)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/tWQZJiws95w/create-your-own-framework-on-top-of-the-symfony2-components-part-9" />
  <id>article-58</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-19T13:09:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our framework is still missing a major characteristic of any good framework:
&lt;em&gt;extensibility&lt;/em&gt;. Being extensible means that the developer should be able to
easily hook into the framework life cycle to modify the way the request is
handled.&lt;/p&gt;

&lt;p&gt;What kind of hooks are we talking about? Authentication or caching for
instance. To be flexible, hooks must be plug-and-play; the ones you "register"
for an application are different from the next one depending on your specific
needs. Many software have a similar concept like Drupal or Wordpress. In some
languages, there is even a standard like &lt;a href="http://www.python.org/dev/peps/pep-0333/#middleware-components-that-play-both-sides"&gt;WSGI&lt;/a&gt; in Python or &lt;a href="http://rack.rubyforge.org/"&gt;Rack&lt;/a&gt; in Ruby.&lt;/p&gt;

&lt;p&gt;As there is no standard for PHP, we are going to use a well-known design
pattern, the &lt;em&gt;Observer&lt;/em&gt;, to allow any kind of behaviors to be attached to our
framework; the Symfony2 EventDispatcher Component implements a lightweight
version of this pattern:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="st0"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;symfony/class-loader&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-foundation&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/routing&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-kernel&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/event-dispatcher&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;,
    &lt;span class="st0"&gt;&amp;quot;autoload&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;psr-0&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt; &lt;span class="st0"&gt;&amp;quot;Simplex&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;src/&amp;quot;&lt;/span&gt;, &lt;span class="st0"&gt;&amp;quot;Calendar&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;src/&amp;quot;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;How does it work? The &lt;em&gt;dispatcher&lt;/em&gt;, the central object of the event dispatcher
system, notifies &lt;em&gt;listeners&lt;/em&gt; of an &lt;em&gt;event&lt;/em&gt; dispatched to it. Put another way:
your code dispatches an event to the dispatcher, the dispatcher notifies all
registered listeners for the event, and each listener do whatever it wants
with the event.&lt;/p&gt;

&lt;p&gt;As an example, let's create a listener that transparently adds the Google
Analytics code to all responses.&lt;/p&gt;

&lt;p&gt;To make it work, the framework must dispatch an event just before returning
the Response instance:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/Framework.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    protected &lt;span class="re0"&gt;$matcher&lt;/span&gt;;
    protected &lt;span class="re0"&gt;$resolver&lt;/span&gt;;
    protected &lt;span class="re0"&gt;$dispatcher&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; __construct&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;EventDispatcher &lt;span class="re0"&gt;$dispatcher&lt;/span&gt;, UrlMatcherInterface &lt;span class="re0"&gt;$matcher&lt;/span&gt;, ControllerResolverInterface &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;matcher&lt;/span&gt; = &lt;span class="re0"&gt;$matcher&lt;/span&gt;;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;dispatcher&lt;/span&gt; = &lt;span class="re0"&gt;$dispatcher&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; handle&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
            &lt;span class="re0"&gt;$controller&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getController&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
            &lt;span class="re0"&gt;$arguments&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$controller&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
            &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;a href="http://www.php.net/call_user_func_array"&gt;&lt;span class="kw3"&gt;call_user_func_array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$controller&lt;/span&gt;, &lt;span class="re0"&gt;$arguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;\Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="co1"&gt;// dispatch a response event&lt;/span&gt;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;dispatch&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; ResponseEvent&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;, &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$response&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Each time the framework handles a Request, a &lt;code&gt;ResponseEvent&lt;/code&gt; event is
now dispatched:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/ResponseEvent.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\EventDispatcher\Event;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; ResponseEvent &lt;span class="kw2"&gt;extends&lt;/span&gt; Event
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;private&lt;/span&gt; &lt;span class="re0"&gt;$request&lt;/span&gt;;
    &lt;span class="kw2"&gt;private&lt;/span&gt; &lt;span class="re0"&gt;$response&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; __construct&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Response &lt;span class="re0"&gt;$response&lt;/span&gt;, Request &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;response&lt;/span&gt; = &lt;span class="re0"&gt;$response&lt;/span&gt;;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;request&lt;/span&gt; = &lt;span class="re0"&gt;$request&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; getResponse&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;response&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; getRequest&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;request&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The last step is the creation of the dispatcher in the front controller and
the registration of a listener for the &lt;code&gt;response&lt;/code&gt; event:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\EventDispatcher\EventDispatcher;
&amp;nbsp;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; EventDispatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addListener&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt;, &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Simplex\ResponseEvent &lt;span class="re0"&gt;$event&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getResponse&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;isRedirection&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
        || &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Type'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="kw2"&gt;false&lt;/span&gt; === &lt;a href="http://www.php.net/strpos"&gt;&lt;span class="kw3"&gt;strpos&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Type'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="st0"&gt;'html'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
        || &lt;span class="st0"&gt;'html'&lt;/span&gt; !== &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getRequestFormat&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;.&lt;span class="st0"&gt;'GA CODE'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;, &lt;span class="re0"&gt;$matcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  The listener is just a proof of concept and you should add the Google
  Analytics code just before the body tag.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see, &lt;code&gt;addListener()&lt;/code&gt; associates a valid PHP callback to a named
event (&lt;code&gt;response&lt;/code&gt;); the event name must be the same as the one used in the
&lt;code&gt;dispatch()&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;In the listener, we add the Google Analytics code only if the response is not
a redirection, if the requested format is HTML, and if the response content
type is HTML (these conditions demonstrate the ease of manipulating the
Request and Response data from your code).&lt;/p&gt;

&lt;p&gt;So far so good, but let's add another listener on the same event. Let's say
that I want to set the &lt;code&gt;Content-Length&lt;/code&gt; of the Response if it is not already
set:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addListener&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt;, &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Simplex\ResponseEvent &lt;span class="re0"&gt;$event&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getResponse&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$headers&lt;/span&gt; = &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;!&lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Length'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &amp;amp;&amp;amp; !&lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Transfer-Encoding'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;set&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Length'&lt;/span&gt;, &lt;a href="http://www.php.net/strlen"&gt;&lt;span class="kw3"&gt;strlen&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Depending on whether you have added this piece of code before the previous
listener registration or after it, you will have the wrong or the right value
for the &lt;code&gt;Content-Length&lt;/code&gt; header. Sometimes, the order of the listeners
matter but by default, all listeners are registered with the same priority,
&lt;code&gt;0&lt;/code&gt;. To tell the dispatcher to run a listener early, change the priority to
a positive number; negative numbers can be used for low priority listeners.
Here, we want the &lt;code&gt;Content-Length&lt;/code&gt; listener to be executed last, so change
the priority to &lt;code&gt;-255&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addListener&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt;, &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Simplex\ResponseEvent &lt;span class="re0"&gt;$event&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getResponse&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$headers&lt;/span&gt; = &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;!&lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Length'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &amp;amp;&amp;amp; !&lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Transfer-Encoding'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;set&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Length'&lt;/span&gt;, &lt;a href="http://www.php.net/strlen"&gt;&lt;span class="kw3"&gt;strlen&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;, &lt;span class="nu0"&gt;-255&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="tip"&gt;&lt;p&gt;
  When creating your framework, think about priorities (reserve some numbers for
  internal listeners for instance) and document them thoroughly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's refactor the code a bit by moving the Google listener to its own class:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/GoogleListener.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; GoogleListener
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; onResponse&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;ResponseEvent &lt;span class="re0"&gt;$event&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getResponse&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;isRedirection&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
            || &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Type'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="kw2"&gt;false&lt;/span&gt; === &lt;a href="http://www.php.net/strpos"&gt;&lt;span class="kw3"&gt;strpos&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Type'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="st0"&gt;'html'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
            || &lt;span class="st0"&gt;'html'&lt;/span&gt; !== &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getRequestFormat&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
        &lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;setContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;.&lt;span class="st0"&gt;'GA CODE'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And do the same with the other listener:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/ContentLengthListener.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; ContentLengthListener
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; onResponse&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;ResponseEvent &lt;span class="re0"&gt;$event&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getResponse&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="re0"&gt;$headers&lt;/span&gt; = &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;!&lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Length'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &amp;amp;&amp;amp; !&lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;has&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Transfer-Encoding'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;set&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Length'&lt;/span&gt;, &lt;a href="http://www.php.net/strlen"&gt;&lt;span class="kw3"&gt;strlen&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Our front controller should now look like the following:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; EventDispatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addListener&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\ContentLengthListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="st0"&gt;'onResponse'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="nu0"&gt;-255&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addListener&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\GoogleListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="st0"&gt;'onResponse'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Even if the code is now nicely wrapped in classes, there is still a slight
issue: the knowledge of the priorities is "hardcoded" in the front controller,
instead of being in the listeners themselves. For each application, you have
to remember to set the appropriate priorities. Moreover, the listener method
names are also exposed here, which means that refactoring our listeners would
mean changing all the applications that rely on those listeners. Of course,
there is a solution: use subscribers instead of listeners:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dispatcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; EventDispatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\ContentLengthListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$dispatcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;addSubscriber&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\GoogleListener&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;A subscriber knowns about all the events it is interested in and pass this
information to the dispatcher via the &lt;code&gt;getSubscribedEvents()&lt;/code&gt; method. Have a
look at the new version of the &lt;code&gt;GoogleListener&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/GoogleListener.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; GoogleListener implements EventSubscriberInterface
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;a href="http://www.php.net/static"&gt;&lt;span class="kw3"&gt;static&lt;/span&gt;&lt;/a&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; getSubscribedEvents&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'onResponse'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And here is the new version of &lt;code&gt;ContentLengthListener&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/ContentLengthListener.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; ContentLengthListener implements EventSubscriberInterface
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;a href="http://www.php.net/static"&gt;&lt;span class="kw3"&gt;static&lt;/span&gt;&lt;/a&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; getSubscribedEvents&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'response'&lt;/span&gt; =&amp;gt; &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'onResponse'&lt;/span&gt;, &lt;span class="nu0"&gt;-255&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="tip"&gt;&lt;p&gt;
  A single subscriber can host as many listeners as you want on as many events
  as needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make your framework truly flexible, don't hesitate to add more events; and
to make it more awesome out of the box, add more listeners. Again, this series
is not about creating a generic framework, but one that is tailored to your
needs. Stop whenever you see fit, and further evolve the code from there.&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/tWQZJiws95w" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 8)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/zrknV5peB1M/create-your-own-framework-on-top-of-the-symfony2-components-part-8" />
  <id>article-57</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-17T10:39:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some watchful readers pointed out some subtle but nonetheless important bugs
in the framework we have built yesterday. When creating a framework, you must
be sure that it behaves as advertised. If not, all the applications based on
it will exhibit the same bugs. The good news is that whenever you fix a bug,
you are fixing a bunch of applications too.&lt;/p&gt;

&lt;p&gt;Today's mission is to write unit tests for the framework we have created by
using &lt;a href="http://www.phpunit.de/manual/current/en/index.html"&gt;PHPUnit&lt;/a&gt;. Create a PHPUnit configuration file in
&lt;code&gt;example.com/phpunit.xml.dist&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&amp;lt;?xml version=&lt;span class="st0"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; encoding=&lt;span class="st0"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class="kw2"&gt;?&amp;gt;&lt;/span&gt;
&amp;nbsp;
&amp;lt;phpunit backupGlobals=&lt;span class="st0"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;
         backupStaticAttributes=&lt;span class="st0"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;
         colors=&lt;span class="st0"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
         convertErrorsToExceptions=&lt;span class="st0"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
         convertNoticesToExceptions=&lt;span class="st0"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
         convertWarningsToExceptions=&lt;span class="st0"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
         processIsolation=&lt;span class="st0"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;
         stopOnFailure=&lt;span class="st0"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;
         syntaxCheck=&lt;span class="st0"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;
         bootstrap=&lt;span class="st0"&gt;&amp;quot;vendor/.composer/autoload.php&amp;quot;&lt;/span&gt;
&amp;gt;
    &amp;lt;testsuites&amp;gt;
        &amp;lt;testsuite name=&lt;span class="st0"&gt;&amp;quot;Test Suite&amp;quot;&lt;/span&gt;&amp;gt;
            &amp;lt;directory&amp;gt;./tests&amp;lt;/directory&amp;gt;
        &amp;lt;/testsuite&amp;gt;
    &amp;lt;/testsuites&amp;gt;
&amp;lt;/phpunit&amp;gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;This configuration defines sensible defaults for most PHPUnit settings; more
interesting, the autoloader is used to bootstrap the tests, and tests will be
stored under the &lt;code&gt;example.com/tests/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now, let's write a test for "not found" resources. To avoid the creation of
all dependencies when writing tests and to really just unit-test what we want,
we are going to use &lt;a href="http://www.phpunit.de/manual/current/en/test-doubles.html"&gt;test doubles&lt;/a&gt;. Test doubles are easier to create when we
rely on interfaces instead of concrete classes. Fortunately, Symfony2 provides
such interfaces for core objects like the URL matcher and the controller
resolver. Modify the framework to make use of them:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/Framework.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
&lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    protected &lt;span class="re0"&gt;$matcher&lt;/span&gt;;
    protected &lt;span class="re0"&gt;$resolver&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; __construct&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;UrlMatcherInterface &lt;span class="re0"&gt;$matcher&lt;/span&gt;, ControllerResolverInterface &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;matcher&lt;/span&gt; = &lt;span class="re0"&gt;$matcher&lt;/span&gt;;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="co1"&gt;// ...&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;We are now ready to write our first test:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/tests/Simplex/Tests/FrameworkTest.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex\Tests;
&amp;nbsp;
use Simplex\Framework;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; FrameworkTest &lt;span class="kw2"&gt;extends&lt;/span&gt; \PHPUnit_Framework_TestCase
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; testNotFoundHandling&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getFrameworkForException&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; ResourceNotFoundException&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Request&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;assertEquals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;404&lt;/span&gt;, &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getStatusCode&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    protected &lt;span class="kw2"&gt;function&lt;/span&gt; getFrameworkForException&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$exception&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getMock&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\R&lt;/span&gt;outing&lt;span class="es0"&gt;\M&lt;/span&gt;atcher&lt;span class="es0"&gt;\U&lt;/span&gt;rlMatcherInterface'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="re0"&gt;$matcher&lt;/span&gt;
            -&amp;gt;&lt;span class="me1"&gt;expects&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;once&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
            -&amp;gt;&lt;span class="me1"&gt;method&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'match'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
            -&amp;gt;&lt;span class="me1"&gt;will&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;throwException&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$exception&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
        ;
        &lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getMock&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\H&lt;/span&gt;ttpKernel&lt;span class="es0"&gt;\C&lt;/span&gt;ontroller&lt;span class="es0"&gt;\C&lt;/span&gt;ontrollerResolverInterface'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;This test simulates a request that does not match any route. As such, the
&lt;code&gt;match()&lt;/code&gt; method returns a &lt;code&gt;ResourceNotFoundException&lt;/code&gt; exception and we
are testing that our framework converts this exception to a 404 response.&lt;/p&gt;

&lt;p&gt;Executing this test is as simple as running &lt;code&gt;phpunit&lt;/code&gt; from the
&lt;code&gt;example.com&lt;/code&gt; directory:&lt;/p&gt;

&lt;pre class="command-line"&gt;&lt;code&gt;$ phpunit
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  I do not explain how the code works in details as this is not the goal of this
  series, but if you don't understand what the hell is going on, I highly
  recommend you to read PHPUnit documentation on &lt;a href="http://www.phpunit.de/manual/current/en/test-doubles.html"&gt;test doubles&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the test ran, you should see a green bar. If not, you have a bug
either in the test or in the framework code!&lt;/p&gt;

&lt;p&gt;Adding a unit test for any exception thrown in a controller is just as easy:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; testErrorHandling&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getFrameworkForException&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; \RuntimeException&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Request&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;assertEquals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;500&lt;/span&gt;, &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getStatusCode&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Last, but not the least, let's write a test for when we actually have a proper
Response:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
&amp;nbsp;
&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; testControllerResponse&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getMock&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Symfony&lt;span class="es0"&gt;\C&lt;/span&gt;omponent&lt;span class="es0"&gt;\R&lt;/span&gt;outing&lt;span class="es0"&gt;\M&lt;/span&gt;atcher&lt;span class="es0"&gt;\U&lt;/span&gt;rlMatcherInterface'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$matcher&lt;/span&gt;
        -&amp;gt;&lt;span class="me1"&gt;expects&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;once&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
        -&amp;gt;&lt;span class="me1"&gt;method&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'match'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
        -&amp;gt;&lt;span class="me1"&gt;will&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;returnValue&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
            &lt;span class="st0"&gt;'_route'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'foo'&lt;/span&gt;,
            &lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'Fabien'&lt;/span&gt;,
            &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$name&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
                &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Hello '&lt;/span&gt;.&lt;span class="re0"&gt;$name&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
            &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
        &lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    ;
    &lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; ControllerResolver&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; Request&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;assertEquals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;200&lt;/span&gt;, &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getStatusCode&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;assertContains&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Hello Fabien'&lt;/span&gt;, &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getContent&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;In this test, we simulate a route that matches and returns a simple
controller. We check that the response status is 200 and that its content is
the one we have set in the controller.&lt;/p&gt;

&lt;p&gt;To check that we have covered all possible use cases, run the PHPUnit test
coverage feature (you need to enable &lt;a href="http://xdebug.org/"&gt;XDebug&lt;/a&gt; first):&lt;/p&gt;

&lt;pre class="command-line"&gt;&lt;code&gt;$ phpunit --coverage-html=cov/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Open &lt;code&gt;example.com/cov/src_Simplex_Framework.php.html&lt;/code&gt; in a browser and check
that all the lines for the Framework class are green (it means that they have
been visited when the tests were executed).&lt;/p&gt;

&lt;p&gt;Thanks to the simple object-oriented code that we have written so far, we have
been able to write unit-tests to cover all possible use cases of our
framework; test doubles ensured that we were actually testing our code and not
Symfony2 code.&lt;/p&gt;

&lt;p&gt;Now that we are confident (again) about the code we have written, we can
safely think about the next batch of features we want to add to our framework.&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/zrknV5peB1M" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 7)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/ewu8fC2I2TM/create-your-own-framework-on-top-of-the-symfony2-components-part-7" />
  <id>article-56</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-15T10:53:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One down-side of our framework right now is that we need to copy and paste the
code in &lt;code&gt;front.php&lt;/code&gt; each time we create a new website. 40 lines of code is
not that much, but it would be nice if we could wrap this code into a proper
class. It would bring us better &lt;em&gt;reusability&lt;/em&gt; and easier testing to name just
a few benefits.&lt;/p&gt;

&lt;p&gt;If you have a closer look at the code, &lt;code&gt;front.php&lt;/code&gt; has one input, the
Request, and one output, the Response. Our framework class will follow this
simple principle: the logic is about creating the Response associated with a
Request.&lt;/p&gt;

&lt;p&gt;As the Symfony2 components requires PHP 5.3, let's create our very own
namespace for our framework: &lt;code&gt;Simplex&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Move the request handling logic into its own &lt;code&gt;Simplex\Framework&lt;/code&gt; class:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Simplex/Framework.php&lt;/span&gt;
&amp;nbsp;
namespace Simplex;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; Framework
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    protected &lt;span class="re0"&gt;$matcher&lt;/span&gt;;
    protected &lt;span class="re0"&gt;$resolver&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; __construct&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;UrlMatcher &lt;span class="re0"&gt;$matcher&lt;/span&gt;, ControllerResolver &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;matcher&lt;/span&gt; = &lt;span class="re0"&gt;$matcher&lt;/span&gt;;
        &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; handle&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
            &lt;span class="re0"&gt;$controller&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getController&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
            &lt;span class="re0"&gt;$arguments&lt;/span&gt; = &lt;span class="re0"&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$controller&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;a href="http://www.php.net/call_user_func_array"&gt;&lt;span class="kw3"&gt;call_user_func_array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$controller&lt;/span&gt;, &lt;span class="re0"&gt;$arguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;\Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And update &lt;code&gt;example.com/web/front.php&lt;/code&gt; accordingly:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$context&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;fromRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\Controller\ControllerResolver&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$framework&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Simplex\Framework&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;, &lt;span class="re0"&gt;$resolver&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="re0"&gt;$framework&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;handle&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To wrap up the refactoring, let's move everything but routes definition from
&lt;code&gt;example.com/src/app.php&lt;/code&gt; into yet another namespace: &lt;code&gt;Calendar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the classes defined under the &lt;code&gt;Simplex&lt;/code&gt; and &lt;code&gt;Calendar&lt;/code&gt; namespaces to
be autoloaded, update the &lt;code&gt;composer.json&lt;/code&gt; file:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="st0"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;symfony/class-loader&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-foundation&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/routing&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-kernel&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;,
    &lt;span class="st0"&gt;&amp;quot;autoload&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;psr-0&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt; &lt;span class="st0"&gt;&amp;quot;Simplex&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;src/&amp;quot;&lt;/span&gt;, &lt;span class="st0"&gt;&amp;quot;Calendar&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;src/&amp;quot;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  For the autoloader to be updated, run &lt;code&gt;php composer.phar update&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Move the controller to &lt;code&gt;Calendar\Controller\LeapYearController&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Calendar/Controller/LeapYearController.php&lt;/span&gt;
&amp;nbsp;
namespace Calendar\Controller;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Calendar\Model\LeapYear;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; LeapYearController
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$leapyear&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; LeapYear&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$leapyear&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;isLeapYear&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Yep, this is a leap year!'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Nope, this is not a leap year.'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;And move the &lt;code&gt;is_leap_year()&lt;/code&gt; function to its own class too:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/Calendar/Model/LeapYear.php&lt;/span&gt;
&amp;nbsp;
namespace Calendar\Model;
&amp;nbsp;
&lt;span class="kw2"&gt;class&lt;/span&gt; LeapYear
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; isLeapYear&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt; = &lt;span class="kw2"&gt;null&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;null&lt;/span&gt; === &lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="re0"&gt;$year&lt;/span&gt; = &lt;a href="http://www.php.net/date"&gt;&lt;span class="kw3"&gt;date&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Y'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="nu0"&gt;0&lt;/span&gt; == &lt;span class="re0"&gt;$year&lt;/span&gt; % &lt;span class="nu0"&gt;400&lt;/span&gt; || &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;0&lt;/span&gt; == &lt;span class="re0"&gt;$year&lt;/span&gt; % &lt;span class="nu0"&gt;4&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="nu0"&gt;0&lt;/span&gt; != &lt;span class="re0"&gt;$year&lt;/span&gt; % &lt;span class="nu0"&gt;100&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Don't forget to update the &lt;code&gt;example.com/src/app.php&lt;/code&gt; file accordingly:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'leap_year'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/is_leap_year/{year}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'year'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;null&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'Calendar&lt;span class="es0"&gt;\\&lt;/span&gt;Controller&lt;span class="es0"&gt;\\&lt;/span&gt;LeapYearController::indexAction'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To sum up, here is the new file layout:&lt;/p&gt;

&lt;pre class="php"&gt;example.com
??? composer.json
?   src
?   ??? app.php
?   ??? Simplex
?       ??? Framework.php
?   ??? Calendar
?       ??? Controller
?       ?   ??? LeapYearController.php
?       ??? Model
?           ??? LeapYear.php
??? vendor
??? web
    ??? front.php
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;That's it! Our application has now four different layers and each of them has
a well defined goal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;web/front.php&lt;/code&gt;: The front controller; the only exposed PHP code that makes
the interface with the client (it gets the Request and sends the Response)
and provides the boiler-plate code to initialize the framework and our
application;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;src/Simplex&lt;/code&gt;: The reusable framework code that abstracts the handling of
incoming Requests (by the way, it makes your controllers/templates easily
testable -- more about that later on);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;src/Calendar&lt;/code&gt;: Our application specific code (the controllers and the
model);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;src/app.php&lt;/code&gt;: The application configuration/framework customization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/ewu8fC2I2TM" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 6)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/_FI45SVYqGw/create-your-own-framework-on-top-of-the-symfony2-components-part-6" />
  <id>article-55</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-13T11:14:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You might think that our framework is already pretty solid and you are
probably right. But let's see how we can improve it nonetheless.&lt;/p&gt;

&lt;p&gt;Right now, all our examples use procedural code, but remember that controllers
can be any valid PHP callbacks. Let's convert our controller to a proper
class:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;class&lt;/span&gt; LeapYearController
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;is_leap_year&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'year'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Yep, this is a leap year!'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Nope, this is not a leap year.'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Update the route definition accordingly:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'leap_year'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/is_leap_year/{year}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'year'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;null&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;new&lt;/span&gt; LeapYearController&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="st0"&gt;'indexAction'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The move is pretty straightforward and makes a lot of sense as soon as you
create more pages but you might have noticed a non-desirable side-effect...
The &lt;code&gt;LeapYearController&lt;/code&gt; class is &lt;em&gt;always&lt;/em&gt; instantiated, even if the
requested URL does not match the &lt;code&gt;leap_year&lt;/code&gt; route. This is bad for one main
reason: performance wise, all controllers for all routes must now be
instantiated for every request. It would be better if controllers were
lazy-loaded so that only the controller associated with the matched route is
instantiated.&lt;/p&gt;

&lt;p&gt;To solve this issue, and a bunch more, let's install and use the HttpKernel
component:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="st0"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;symfony/class-loader&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-foundation&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/routing&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-kernel&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The HttpKernel component has many interesting features, but the one we need
right now is the &lt;em&gt;controller resolver&lt;/em&gt;. A controller resolver knows how to
determine the controller to execute and the arguments to pass to it, based on
a Request object. All controller resolvers implement the following interface:&lt;/p&gt;

&lt;pre class="php"&gt;namespace Symfony\Component\HttpKernel\Controller;
&amp;nbsp;
&lt;span class="kw2"&gt;interface&lt;/span&gt; ControllerResolverInterface
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;function&lt;/span&gt; getController&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw2"&gt;function&lt;/span&gt; getArguments&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$controller&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;getController()&lt;/code&gt; method relies on the same convention as the one we
have defined earlier: the &lt;code&gt;_controller&lt;/code&gt; request attribute must contain the
controller associated with the Request. Besides the built-in PHP callbacks,
&lt;code&gt;getController()&lt;/code&gt; also supports strings composed of a class name followed by
two colons and a method name as a valid callback, like 'class::method':&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'leap_year'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/is_leap_year/{year}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'year'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;null&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'LeapYearController::indexAction'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To make this code work, modify the framework code to use the controller
resolver from HttpKernel:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\HttpKernel;
&amp;nbsp;
&lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\Controller\ControllerResolver&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$controller&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getController&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$arguments&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$controller&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;a href="http://www.php.net/call_user_func_array"&gt;&lt;span class="kw3"&gt;call_user_func_array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$controller&lt;/span&gt;, &lt;span class="re0"&gt;$arguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  As an added bonus, the controller resolver properly handles the error
  management for you: when you forget to define a &lt;code&gt;_controller&lt;/code&gt; attribute for a
  Route for instance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's see how the controller arguments are guessed. &lt;code&gt;getArguments()&lt;/code&gt;
introspects the controller signature to determine which arguments to pass to
it by using the native PHP &lt;a href="http://php.net/reflection"&gt;reflection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;indexAction()&lt;/code&gt; method needs the Request object as an argument.
``getArguments()` knows when to inject it properly if it is type-hinted
correctly:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// won't work&lt;/span&gt;
&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;More interesting, &lt;code&gt;getArguments()&lt;/code&gt; is also able to inject any Request
attribute; the argument just needs to have the same name as the corresponding
attribute:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;You can also inject the Request and some attributes at the same time (as the
matching is done on the argument name or a type hint, the arguments order does
not matter):&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Request &lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;, Request &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Finally, you can also define default values for any argument that matches an
optional attribute of the Request:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt; = &lt;span class="nu0"&gt;2012&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Let's just inject the &lt;code&gt;$year&lt;/code&gt; request attribute for our controller:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;class&lt;/span&gt; LeapYearController
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw2"&gt;public&lt;/span&gt; &lt;span class="kw2"&gt;function&lt;/span&gt; indexAction&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;is_leap_year&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Yep, this is a leap year!'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Nope, this is not a leap year.'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The controller resolver also takes care of validating the controller callable
and its arguments. In case of a problem, it throws an exception with a nice
message explaining the problem (the controller class does not exist, the
method is not defined, an argument has no matching attribute, ...).&lt;/p&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  With the great flexibility of the default controller resolver, you might
  wonder why someone would want to create another one (why would there be an
  interface if not). Two examples: in Symfony2, &lt;code&gt;getController()&lt;/code&gt; is enhanced to
  support &lt;a href="http://symfony.com/doc/current/cookbook/controller/service.html"&gt;controllers as services&lt;/a&gt;; and in &lt;a href="http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html"&gt;FrameworkExtraBundle&lt;/a&gt;,
  &lt;code&gt;getArguments()&lt;/code&gt; is enhanced to support parameter converters, where request
  attributes are converted to objects automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's conclude with the new version of our framework:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;
use Symfony\Component\HttpKernel;
&amp;nbsp;
&lt;span class="kw2"&gt;function&lt;/span&gt; render_template&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;a href="http://www.php.net/extract"&gt;&lt;span class="kw3"&gt;extract&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;all&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;a href="http://www.php.net/ob_start"&gt;&lt;span class="kw3"&gt;ob_start&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="kw1"&gt;include&lt;/span&gt; &lt;a href="http://www.php.net/sprintf"&gt;&lt;span class="kw3"&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../src/pages/%s.php'&lt;/span&gt;, &lt;span class="re0"&gt;$_route&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/ob_get_clean"&gt;&lt;span class="kw3"&gt;ob_get_clean&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$context&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;fromRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$resolver&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; HttpKernel\Controller\ControllerResolver&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$controller&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getController&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$arguments&lt;/span&gt; = &lt;span class="re0"&gt;$resolver&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getArguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;, &lt;span class="re0"&gt;$controller&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;a href="http://www.php.net/call_user_func_array"&gt;&lt;span class="kw3"&gt;call_user_func_array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$controller&lt;/span&gt;, &lt;span class="re0"&gt;$arguments&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Routing\Exception\ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Think about it once more: our framework is more robust and more flexible than
ever and it still has less than 40 lines of code.&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/_FI45SVYqGw" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 5)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/DyaJ_-Yr--8/create-your-own-framework-on-top-of-the-symfony2-components-part-5" />
  <id>article-54</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-11T15:02:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The astute reader has noticed that our framework hardcodes the way specific
"code" (the templates) is run. For simple pages like the ones we have created
so far, that's not a problem, but if you want to add more logic, you would be
forced to put the logic into the template itself, which is probably not a good
idea, especially if you still have the separation of concerns principle in
mind.&lt;/p&gt;

&lt;p&gt;Let's separate the template code from the logic by adding a new layer: the
controller: &lt;em&gt;The controller mission is to generate a Response based on the
information conveyed by the client Request.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Change the template rendering part of the framework to read as follows:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;
try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;a href="http://www.php.net/call_user_func"&gt;&lt;span class="kw3"&gt;call_user_func&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'render_template'&lt;/span&gt;, &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Routing\Exception\ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;As the rendering is now done by an external function (&lt;code&gt;render_template()&lt;/code&gt;
here), we need to pass to it the attributes extracted from the URL. We could
have passed them as an additional argument to &lt;code&gt;render_template()&lt;/code&gt;, but
instead, let's use another feature of the &lt;code&gt;Request&lt;/code&gt; class called
&lt;em&gt;attributes&lt;/em&gt;: Request attributes lets you attach additional information about
the Request that is not directly related to the HTTP Request data.&lt;/p&gt;

&lt;p&gt;You can now create the &lt;code&gt;render_template()&lt;/code&gt; function, a generic controller
that renders a template when there is no specific logic. To keep the same
template as before, request attributes are extracted before the template is
rendered:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;function&lt;/span&gt; render_template&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;a href="http://www.php.net/extract"&gt;&lt;span class="kw3"&gt;extract&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;all&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, EXTR_SKIP&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;a href="http://www.php.net/ob_start"&gt;&lt;span class="kw3"&gt;ob_start&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="kw1"&gt;include&lt;/span&gt; &lt;a href="http://www.php.net/sprintf"&gt;&lt;span class="kw3"&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../src/pages/%s.php'&lt;/span&gt;, &lt;span class="re0"&gt;$_route&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/ob_get_clean"&gt;&lt;span class="kw3"&gt;ob_get_clean&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;As &lt;code&gt;render_template&lt;/code&gt; is used as an argument to the PHP &lt;code&gt;call_user_func()&lt;/code&gt;
function, we can replace it with any valid PHP &lt;a href="http://php.net/callback#language.types.callback"&gt;callbacks&lt;/a&gt;. This allows us to
use a function, an anonymous function, or a method of a class as a
controller... your choice.&lt;/p&gt;

&lt;p&gt;As a convention, for each route, the associated controller is configured via
the &lt;code&gt;_controller&lt;/code&gt; route attribute:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello/{name}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'World'&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'render_template'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;a href="http://www.php.net/call_user_func"&gt;&lt;span class="kw3"&gt;call_user_func&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'_controller'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Routing\Exception\ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;A route can now be associated with any controller and of course, within a
controller, you can still use the &lt;code&gt;render_template()&lt;/code&gt; to render a template:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello/{name}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'World'&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;return&lt;/span&gt; render_template&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;This is rather flexible as you can change the Response object afterwards and
you can even pass additional arguments to the template:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello/{name}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'World'&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="co1"&gt;// $foo will be available in the template&lt;/span&gt;
        &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;set&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'foo'&lt;/span&gt;, &lt;span class="st0"&gt;'bar'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="re0"&gt;$response&lt;/span&gt; = render_template&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="co1"&gt;// change some header&lt;/span&gt;
        &lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;headers&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;set&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Content-Type'&lt;/span&gt;, &lt;span class="st0"&gt;'text/plain'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$response&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Here is the updated and improved version of our framework:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;
&amp;nbsp;
&lt;span class="kw2"&gt;function&lt;/span&gt; render_template&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;a href="http://www.php.net/extract"&gt;&lt;span class="kw3"&gt;extract&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;all&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, EXTR_SKIP&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;a href="http://www.php.net/ob_start"&gt;&lt;span class="kw3"&gt;ob_start&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="kw1"&gt;include&lt;/span&gt; &lt;a href="http://www.php.net/sprintf"&gt;&lt;span class="kw3"&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../src/pages/%s.php'&lt;/span&gt;, &lt;span class="re0"&gt;$_route&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/ob_get_clean"&gt;&lt;span class="kw3"&gt;ob_get_clean&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$context&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;fromRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;a href="http://www.php.net/call_user_func"&gt;&lt;span class="kw3"&gt;call_user_func&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'_controller'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Routing\Exception\ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To celebrate the birth of our new framework, let's create a brand new
application that needs some simple logic. Our application has one page that
says whether a given year is a leap year or not. When calling
&lt;code&gt;/is_leap_year&lt;/code&gt;, you get the answer for the current year, but you can
also specify a year like in &lt;code&gt;/is_leap_year/2009&lt;/code&gt;. Being generic, the
framework does not need to be modified in any way, just create a new
&lt;code&gt;app.php&lt;/code&gt; file:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/app.php&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\Routing;
use Symfony\Component\HttpFoundation\Response;
&amp;nbsp;
&lt;span class="kw2"&gt;function&lt;/span&gt; is_leap_year&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$year&lt;/span&gt; = &lt;span class="kw2"&gt;null&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;null&lt;/span&gt; === &lt;span class="re0"&gt;$year&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="re0"&gt;$year&lt;/span&gt; = &lt;a href="http://www.php.net/date"&gt;&lt;span class="kw3"&gt;date&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Y'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
    &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="nu0"&gt;0&lt;/span&gt; == &lt;span class="re0"&gt;$year&lt;/span&gt; % &lt;span class="nu0"&gt;400&lt;/span&gt; || &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="nu0"&gt;0&lt;/span&gt; == &lt;span class="re0"&gt;$year&lt;/span&gt; % &lt;span class="nu0"&gt;4&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="nu0"&gt;0&lt;/span&gt; != &lt;span class="re0"&gt;$year&lt;/span&gt; % &lt;span class="nu0"&gt;100&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RouteCollection&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'leap_year'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/is_leap_year/{year}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'year'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;null&lt;/span&gt;,
    &lt;span class="st0"&gt;'_controller'&lt;/span&gt; =&amp;gt; &lt;span class="kw2"&gt;function&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;is_leap_year&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;attributes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;get&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'year'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
            &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Yep, this is a leap year!'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
        &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
        &lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Nope, this is not a leap year.'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$routes&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;is_leap_year()&lt;/code&gt; function returns &lt;code&gt;true&lt;/code&gt; when the given year is a leap
year, &lt;code&gt;false&lt;/code&gt; otherwise. If the year is null, the current year is tested.
The controller is simple: it gets the year from the request attributes, pass
it to the &lt;code&gt;is_leap_year()&lt;/code&gt; function, and according to the return value it
creates a new Response object.&lt;/p&gt;

&lt;p&gt;As always, you can decide to stop here and use the framework as is; it's
probably all you need to create simple websites like those fancy one-page
&lt;a href="http://kottke.org/08/02/single-serving-sites"&gt;websites&lt;/a&gt; and hopefully a few others.&lt;/p&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/DyaJ_-Yr--8" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5</feedburner:origLink></entry>
      <entry>
  <title>Create your own framework... on top of the Symfony2 Components (part 4)</title>
  <link href="http://feeds.fabien.potencier.org/~r/aidedecamp/~3/ysfEA0yqd50/create-your-own-framework-on-top-of-the-symfony2-components-part-4" />
  <id>article-53</id>
  <author>
    <name>Fabien Potencier</name>
    <author_email>fabien.potencier@sensio.com</author_email>
  </author>
  <updated>2012-01-09T09:27:00+01:00</updated>
  <content type="html">
    &lt;blockquote class="note"&gt;&lt;p&gt;
  This article is part of a series of articles that explains how to create a framework with
  the Symfony2 Components:
  &lt;a href="http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1"&gt;1&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2"&gt;2&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/52/create-your-own-framework-on-top-of-the-symfony2-components-part-3"&gt;3&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4"&gt;4&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/54/create-your-own-framework-on-top-of-the-symfony2-components-part-5"&gt;5&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-6"&gt;6&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/56/create-your-own-framework-on-top-of-the-symfony2-components-part-7"&gt;7&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/57/create-your-own-framework-on-top-of-the-symfony2-components-part-8"&gt;8&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/58/create-your-own-framework-on-top-of-the-symfony2-components-part-9"&gt;9&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/59/create-your-own-framework-on-top-of-the-symfony2-components-part-10"&gt;10&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/60/create-your-own-framework-on-top-of-the-symfony2-components-part-11"&gt;11&lt;/a&gt;,
  &lt;a href="http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12"&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before we start with today's topic, let's refactor our current framework just
a little to make templates even more readable:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$map&lt;/span&gt; = &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
    &lt;span class="st0"&gt;'/hello'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'hello'&lt;/span&gt;,
    &lt;span class="st0"&gt;'/bye'&lt;/span&gt;   =&amp;gt; &lt;span class="st0"&gt;'bye'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$path&lt;/span&gt; = &lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="kw1"&gt;if&lt;/span&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/isset"&gt;&lt;span class="kw3"&gt;isset&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$map&lt;/span&gt;&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="re0"&gt;$path&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;a href="http://www.php.net/ob_start"&gt;&lt;span class="kw3"&gt;ob_start&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;a href="http://www.php.net/extract"&gt;&lt;span class="kw3"&gt;extract&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;query&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;all&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, EXTR_SKIP&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="kw1"&gt;include&lt;/span&gt; &lt;a href="http://www.php.net/sprintf"&gt;&lt;span class="kw3"&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../src/pages/%s.php'&lt;/span&gt;, &lt;span class="re0"&gt;$map&lt;/span&gt;&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="re0"&gt;$path&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/ob_get_clean"&gt;&lt;span class="kw3"&gt;ob_get_clean&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; &lt;span class="kw1"&gt;else&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;As we now extract the request query parameters, simplify the &lt;code&gt;hello.php&lt;/code&gt;
template as follows:&lt;/p&gt;

&lt;pre class="php"&gt;&amp;lt;!-- example.com/src/pages/hello.php --&amp;gt;
&amp;nbsp;
&lt;span class="me1"&gt;Hello&lt;/span&gt; &lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt; &lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;a href="http://www.php.net/htmlspecialchars"&gt;&lt;span class="kw3"&gt;htmlspecialchars&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$name&lt;/span&gt;, ENT_QUOTES, &lt;span class="st0"&gt;'UTF-8'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="kw2"&gt;?&amp;gt;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Now, we are in good shape to add new features.&lt;/p&gt;

&lt;p&gt;One very important aspect of any website is the form of its URLs. Thanks to
the URL map, we have decoupled the URL from the code that generates the
associated response, but it is not yet flexible enough. For instance, we might
want to support dynamic paths to allow embedding data directly into the URL
instead of relying on a query string:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="co2"&gt;# Before&lt;/span&gt;
/hello?name=Fabien
&amp;nbsp;
&lt;span class="co2"&gt;# After&lt;/span&gt;
/hello/Fabien
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;To support this feature, we are going to use the Symfony2 Routing component.
As always, add it to &lt;code&gt;composer.json&lt;/code&gt; and run the &lt;code&gt;php composer.phar
update&lt;/code&gt; command to install it:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="st0"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;: &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
        &lt;span class="st0"&gt;&amp;quot;symfony/class-loader&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/http-foundation&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;,
        &lt;span class="st0"&gt;&amp;quot;symfony/routing&amp;quot;&lt;/span&gt;: &lt;span class="st0"&gt;&amp;quot;2.1.*&amp;quot;&lt;/span&gt;
    &lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;From now on, we are going to use the generated Composer autoloader instead of
our own &lt;code&gt;autoload.php&lt;/code&gt;. Remove the &lt;code&gt;autoload.php&lt;/code&gt; file and replace its
reference in &lt;code&gt;front.php&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="co1"&gt;// ...&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Instead of an array for the URL map, the Routing component relies on a
&lt;code&gt;RouteCollection&lt;/code&gt; instance:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\Routing\RouteCollection;
&amp;nbsp;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; RouteCollection&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Let's add a route that describe the &lt;code&gt;/hello/SOMETHING&lt;/code&gt; URL and add another
one for the simple &lt;code&gt;/bye&lt;/code&gt; one:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\Routing\Route;
&amp;nbsp;
&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello/{name}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'World'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'bye'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/bye'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;Each entry in the collection is defined by a name (&lt;code&gt;hello&lt;/code&gt;) and a &lt;code&gt;Route&lt;/code&gt;
instance, which is defined by a route pattern (&lt;code&gt;/hello/{name}&lt;/code&gt;) and an array
of default values for route attributes (&lt;code&gt;array('name' =&amp;gt; 'World')&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  Read the official
  &lt;a href="http://symfony.com/doc/current/components/routing.html"&gt;documentation&lt;/a&gt; --
  available soon -- for the Routing component to learn more about its many
  features like URL generation, attribute requirements, HTTP method
  enforcements, loaders for YAML or XML files, dumpers to PHP or Apache rewrite
  rules for enhanced performance, and much more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Based on the information stored in the &lt;code&gt;RouteCollection&lt;/code&gt; instance, a
&lt;code&gt;UrlMatcher&lt;/code&gt; instance can match URL paths:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcher;
&amp;nbsp;
&lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$context&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;fromRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$attributes&lt;/span&gt; = &lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;match()&lt;/code&gt; method takes a request path and returns an array of attributes
(notice that the matched route is automatically stored under the special
&lt;code&gt;_route&lt;/code&gt; attribute):&lt;/p&gt;

&lt;pre class="php"&gt;&lt;a href="http://www.php.net/print_r"&gt;&lt;span class="kw3"&gt;print_r&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/bye'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
  &lt;span class="st0"&gt;'_route'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'bye'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;a href="http://www.php.net/print_r"&gt;&lt;span class="kw3"&gt;print_r&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello/Fabien'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
  &lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'Fabien'&lt;/span&gt;,
  &lt;span class="st0"&gt;'_route'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'hello'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;a href="http://www.php.net/print_r"&gt;&lt;span class="kw3"&gt;print_r&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt; &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;
  &lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'World'&lt;/span&gt;,
  &lt;span class="st0"&gt;'_route'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'hello'&lt;/span&gt;,
&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="note"&gt;&lt;p&gt;
  Even if we don't strictly need the request context in our examples, it is used
  in real-world applications to enforce method requirements and more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The URL matcher throws an exception when none of the routes match:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/not-found'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="co1"&gt;// throws a Symfony\Component\Routing\Exception\ResourceNotFoundException&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;With this knowledge in mind, let's write the new version of our framework:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/web/front.php&lt;/span&gt;
&amp;nbsp;
&lt;span class="kw1"&gt;require_once&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../vendor/.composer/autoload.php'&lt;/span&gt;;
&amp;nbsp;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;
&amp;nbsp;
&lt;span class="re0"&gt;$request&lt;/span&gt; = Request::&lt;span class="me2"&gt;createFromGlobals&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw1"&gt;include&lt;/span&gt; __DIR__.&lt;span class="st0"&gt;'/../src/app.php'&lt;/span&gt;;
&amp;nbsp;
&lt;span class="re0"&gt;$context&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RequestContext&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$context&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;fromRequest&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$matcher&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\UrlMatcher&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
try &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;a href="http://www.php.net/extract"&gt;&lt;span class="kw3"&gt;extract&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$matcher&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;match&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;getPathInfo&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, EXTR_SKIP&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;a href="http://www.php.net/ob_start"&gt;&lt;span class="kw3"&gt;ob_start&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class="kw1"&gt;include&lt;/span&gt; &lt;a href="http://www.php.net/sprintf"&gt;&lt;span class="kw3"&gt;sprintf&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;__DIR__.&lt;span class="st0"&gt;'/../src/pages/%s.php'&lt;/span&gt;, &lt;span class="re0"&gt;$_route&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.php.net/ob_get_clean"&gt;&lt;span class="kw3"&gt;ob_get_clean&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Routing\Exception\ResourceNotFoundException &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'Not Found'&lt;/span&gt;, &lt;span class="nu0"&gt;404&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt; catch &lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;Exception &lt;span class="re0"&gt;$e&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="br0"&gt;&amp;#123;&lt;/span&gt;
    &lt;span class="re0"&gt;$response&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Response&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'An error occurred'&lt;/span&gt;, &lt;span class="nu0"&gt;500&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="br0"&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class="re0"&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;send&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;There are a few new things in the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Route names are used for template names;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;500&lt;/code&gt; errors are now managed correctly;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Request attributes are extracted to keep our templates simple:&lt;/p&gt;

&lt;pre class="php"&gt;&amp;lt;!-- example.com/src/pages/hello.php --&amp;gt;
&amp;nbsp;
&lt;span class="me1"&gt;Hello&lt;/span&gt; &lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt; &lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;a href="http://www.php.net/htmlspecialchars"&gt;&lt;span class="kw3"&gt;htmlspecialchars&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$name&lt;/span&gt;, ENT_QUOTES, &lt;span class="st0"&gt;'UTF-8'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="kw2"&gt;?&amp;gt;&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Routes configuration has been moved to its own file:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="kw2"&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span class="co1"&gt;// example.com/src/app.php&lt;/span&gt;
&amp;nbsp;
use Symfony\Component\Routing;
&amp;nbsp;
&lt;span class="re0"&gt;$routes&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\RouteCollection&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/hello/{name}'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'World'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="re0"&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;add&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'bye'&lt;/span&gt;, &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Route&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'/bye'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;span class="kw1"&gt;return&lt;/span&gt; &lt;span class="re0"&gt;$routes&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;We now have a clear separation between the configuration (everything
specific to our application in &lt;code&gt;app.php&lt;/code&gt;) and the framework (the generic
code that powers our application in &lt;code&gt;front.php&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With less than 30 lines of code, we have a new framework, more powerful and
more flexible than the previous one. Enjoy!&lt;/p&gt;

&lt;p&gt;Using the Routing component has one big additional benefit: the ability to
generate URLs based on Route definitions. When using both URL matching and URL
generation in your code, changing the URL patterns should have no other
impact. Want to know how to use the generator? Insanely easy:&lt;/p&gt;

&lt;pre class="php"&gt;use Symfony\Component\Routing;
&amp;nbsp;
&lt;span class="re0"&gt;$generator&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Generator\UrlGenerator&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;, &lt;span class="re0"&gt;$context&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;span class="re0"&gt;$generator&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;generate&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'Fabien'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="co1"&gt;// outputs /hello/Fabien&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;p&gt;The code should be self-explanatory; and thanks to the context, you can even
generate absolute URLs:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;span class="re0"&gt;$generator&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;generate&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'hello'&lt;/span&gt;, &lt;a href="http://www.php.net/array"&gt;&lt;span class="kw3"&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;'name'&lt;/span&gt; =&amp;gt; &lt;span class="st0"&gt;'Fabien'&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;, &lt;span class="kw2"&gt;true&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&lt;span class="co1"&gt;// outputs something like http://example.com/somewhere/hello/Fabien&lt;/span&gt;
&amp;nbsp;&lt;/pre&gt;

&lt;blockquote class="tip"&gt;&lt;p&gt;
  Concerned about performance? Based on your route definitions, create a highly
  optimized URL matcher class that can replace the default &lt;code&gt;UrlMatcher&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dumper&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\Dumper\PhpMatcherDumper&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;span class="re0"&gt;$dumper&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;dump&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;
  
  &lt;p&gt;Want even more performance? Dump your routes as a set of Apache
  rewrite rules:&lt;/p&gt;

&lt;pre class="php"&gt;&lt;span class="re0"&gt;$dumper&lt;/span&gt; = &lt;span class="kw2"&gt;new&lt;/span&gt; Routing\Matcher\Dumper\ApacheMatcherDumper&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="re0"&gt;$routes&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&lt;a href="http://www.php.net/echo"&gt;&lt;span class="kw3"&gt;echo&lt;/span&gt;&lt;/a&gt; &lt;span class="re0"&gt;$dumper&lt;/span&gt;-&amp;gt;&lt;span class="me1"&gt;dump&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;&lt;/pre&gt;
&lt;/blockquote&gt;
  &lt;img src="http://feeds.feedburner.com/~r/aidedecamp/~4/ysfEA0yqd50" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://fabien.potencier.org/article/53/create-your-own-framework-on-top-of-the-symfony2-components-part-4</feedburner:origLink></entry>
  </feed>

