The Symfony Components – Fabien Potencier
Serial entrepreneur
Developer by passion
Founder of Sensio
Creator and lead developer of Symfony
On Twitter @fabpot
On github http://www.github.com/fabpot

            http://fabien.potencier.org/
             The Symfony Components – Fabien Potencier
Standalone components for PHP 5.3

       No dependency between them

Used extensively in Symfony 2, the framework

              The Symfony Components – Fabien Potencier
Low-level libraries
needed by most websites

      The Symfony Components – Fabien Potencier
Event Dispatcher                                              Stable

Output Escaper                                                Stable
                                                                       Extracted from symfony 1
YAML                                                          Stable

Routing                                                       Beta

Console                                                       Stable
Dependency Injection Container                                Stable   Written from scratch
                                                                       for Symfony 2
Request Handler                                               Stable

Templating                                                    Stable

                  The Symfony Components – Fabien Potencier
YAML
Event Dispatcher
                                                              PHP Quebec 2009
Templating
Dependency Injection Container
Console
Routing                                                       ConFoo 2010
Output Escaper
Request Handler
                  The Symfony Components – Fabien Potencier
Download / Installation




The Symfony Components – Fabien Potencier
git clone git://github.com/symfony/symfony.git




                                                            Main repository


                The Symfony Components – Fabien Potencier
svn checkout http://svn.symfony-project.org/branches/2.0/


                                                                  Git Mirror
                                                                Synchronized
                                                               every 15 minutes


                   The Symfony Components – Fabien Potencier
curl -O http://github.com/symfony/symfony/tarball/master
tar zxpf symfony-symfony-XXXXXXX.tar.gz

curl -O http://github.com/symfony/symfony/zipball/master
unzip symfony-symfony-XXXXXXX.zip



                                                               Nightly build


                   The Symfony Components – Fabien Potencier
app/
  .../
     Symfony/
       Components/
       Foundation/
       Framework/
        The Symfony Components – Fabien Potencier
Autoloading Classes




The Symfony Components – Fabien Potencier
Before PHP 5.3
PEAR naming convention
      The Symfony Components – Fabien Potencier
PEAR_Log                >      PEAR/Log.php
            Zend_Log                >      Zend/Log.php
  Swift_Mime_Message                >      Swift/Mime/Message.php
Doctrine_Pager_Range                >      Doctrine/Pager/Range.php
       Twig_Node_For                >      Twig/Node/For.php




               The Symfony Components – Fabien Potencier
PEAR_Log                >      PEAR/Log.php
            Zend_Log                >      Zend/Log.php
  Swift_Mime_Message                >      Swift/Mime/Message.php
Doctrine_Pager_Range                >      Doctrine/Pager/Range.php
       Twig_Node_For                >      Twig/Node/For.php

                                                           Vendor name

               The Symfony Components – Fabien Potencier
As of PHP 5.3
    PHP 5.3 technical
interoperability standards
       The Symfony Components – Fabien Potencier
SymfonyFoundationKernel > Symfony/Foundation/Kernel.php
     DoctrineDBALDriver > Doctrine/DBAL/Driver.php
pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php




                         The Symfony Components – Fabien Potencier
SymfonyFoundationKernel > Symfony/Foundation/Kernel.php
     DoctrineDBALDriver > Doctrine/DBAL/Driver.php
pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php




                                                                     Vendor name

                         The Symfony Components – Fabien Potencier
PHP 5.3 technical interoperability standards

             « … describes the mandatory requirements
                       that must be adhered to
                   for autoloader interoperability »


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




                      The Symfony Components – Fabien Potencier
use SymfonyFoundationUniversalClassLoader;




              The Symfony Components – Fabien Potencier
require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use SymfonyFoundationUniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespace(
   'Symfony', __DIR__.'/src/symfony/src'
);
$loader->register();

// use any Symfony class




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

                                                                PHP 5.3 technical
                                                            interoperability standards


                The Symfony Components – Fabien Potencier
$loader->registerPrefixes(array(
  'Swift_' => '/path/to/swiftmailer/lib/classes',
  'Zend_' => '/path/to/vendor/zend/library',
));


                                                             PEAR style


                 The Symfony Components – Fabien Potencier
require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use SymfonyFoundationUniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
  'Symfony' => '/path/to/symfony/src',
  'Doctrine' => '/path/to/doctrine/lib',
));
$loader->registerPrefixes(array(
  'Swift_' => '/path/to/swiftmailer/lib/classes',
  'Zend_' => '/path/to/vendor/zend/library',
));
$loader->register();

// use any class

                     The Symfony Components – Fabien Potencier
Console




The Symfony Components – Fabien Potencier
Console




The Symfony Components – Fabien Potencier
Automate things
   code generators
     deployment

   The Symfony Components – Fabien Potencier
Long running tasks
          deployment
get « things » from the Internet

        The Symfony Components – Fabien Potencier
Batches
cleanup a database from time to time
    migrate a DB to a new schema

          The Symfony Components – Fabien Potencier
These tasks should never
  be run from a browser

       The Symfony Components – Fabien Potencier
But PHP is
a web language, right?
      The Symfony Components – Fabien Potencier
So, why not use the right tool
         for the job?

   … like Perl or Python?
         The Symfony Components – Fabien Potencier
Don’t want to use/learn another language
          Want to share code


            The Symfony Components – Fabien Potencier
PHP natively supports
 the CLI environment

      The Symfony Components – Fabien Potencier
<?php

// ...



         The Symfony Components – Fabien Potencier
#!/usr/bin/env php
<?php

// ...
                                                      $ ./foo …

          The Symfony Components – Fabien Potencier
$ ./foobar Fabien

$name = $argv[1];
echo 'Hello '.$name;


          The Symfony Components – Fabien Potencier
… but the complexity lies in the details



            The Symfony Components – Fabien Potencier
option / arguments handling
          exit codes
             shell
     output colorization
             tests
       error messages
              …
     The Symfony Components – Fabien Potencier
$ ./life foo "foo bar" --foo foobar -b

Array
(
    [0]   =>   ./life
    [1]   =>   foo
    [2]   =>   foo bar
    [3]   =>   --foo
    [4]   =>   foobar
    [5]   =>   -b
)

                    The Symfony Components – Fabien Potencier
don’t reinvent the wheel…
     use a “framework”

       The Symfony Components – Fabien Potencier
Console




The Symfony Components – Fabien Potencier
Let’s create a CLI tool
  to get the weather
anywhere in the world
      The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
use LifeYahooWeather;

$weather = new YahooWeather('API_KEY', $argv[1]);
echo $weather->getTitle()."n";

$attrs = $weather->getCurrentConditions();

echo "Current conditions:n";
echo sprintf(" %s, %sCn", $attrs['text'], $attrs['temp']);

$attrs = $weather->getForecast();

echo sprintf("nForecast for %sn", $attrs['date']);
echo sprintf(" %s, low: %s, high: %sn", $attrs['text'],
$attrs['low'], $attrs['high']);


                         The Symfony Components – Fabien Potencier
use SymfonyComponentsConsoleApplication;

$application = new Application();
$application->run();




                The Symfony Components – Fabien Potencier
$command = new Command('weather');
$command->setCode(
   function ($input, $output)
   {
     // do something
   }
);

$application->addCommand($command);


                The Symfony Components – Fabien Potencier
use SymfonyComponentsConsoleApplication;

$application = new Application();
$application->addCommand(new WeatherCommand());
$application->run();




                The Symfony Components – Fabien Potencier
use SymfonyComponentsConsoleCommandCommand;
use SymfonyComponentsConsoleInputInputInterface;
use SymfonyComponentsConsoleOutputOutputInterface;

class WeatherCommand extends Command
{
  protected function configure()
  {
    $this->setName('weather');
  }

  protected function execute(InputInterface $input, OutputInterface
$output)
  {
    // do something
  }
}


                        The Symfony Components – Fabien Potencier
Console

    The Output



The Symfony Components – Fabien Potencier
$output->writeln($weather->getTitle());




                  The Symfony Components – Fabien Potencier
$output->writeln(
   sprintf('<info>%s</info>', $weather->getTitle())
);

$output->writeln("<comment>Conditions</comment>");




                  The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
Console

    Getting help



The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
$application = new Application('Life Tool', '0.1');




                  The Symfony Components – Fabien Potencier
class WeatherCommand extends Command
{
  protected function configure()
  {
    $this->setName('weather')
      ->setDescription('Displays weather forecast')
      ->setHelp(<<<EOF
The <info>weather</info> command displays
weather forecast for a given city:

  <info>./life weather Paris</info>

You can also change the default degree unit
with the <comment>--unit</comment> option:

  <info>./life weather Paris --unit=c</info>
  <info>./life weather Paris -u c</info>
EOF
    );
  }

                         The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
$ ./life weather
$ ./life weath
$ ./life w
      The Symfony Components – Fabien Potencier
Console

    The Input



The Symfony Components – Fabien Potencier
class WeatherCommand extends Command
{
  protected function configure()
  {
    $definition = array(
      new InputArgument('place',
InputArgument::OPTIONAL, 'The place name', 'Paris'),

       new InputOption('unit', 'u',
InputOption::PARAMETER_REQUIRED, 'The degree unit',
'c'),
    );

    $this->setDefinition($definition);

                   The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
protected function execute(InputInterface $input,
OutputInterface $output)
{
  $city = $input->getArgument('place');
  $unit = $input->getOption('unit');

    $output->writeln("<comment>Conditions</comment>");
}




                    The Symfony Components – Fabien Potencier
Console

    Error codes / Exit status



The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
protected function execute(InputInterface $input,
OutputInterface $output)
{
  $city = $input->getArgument('place');
  $unit = $input->getOption('unit');

    $output->writeln("<comment>Conditions</comment>");

    return 120;
}



                    The Symfony Components – Fabien Potencier
Console

    Interact with the user



The Symfony Components – Fabien Potencier
protected function interact($input, $output)
{
  $city = $this->dialog->ask(
     $output,
     '<comment>Which city?</comment> (Paris)',
     'Paris’
  );

    $input->setArgument('place', $city);
}



                    The Symfony Components – Fabien Potencier
./life weather --no-interaction




           The Symfony Components – Fabien Potencier
dialog
  ask()
  askConfirmation()
  askAndValidate()

formatter
  formatSection()
  formatBlock()

... your own



                The Symfony Components – Fabien Potencier
class WeatherHelper extends Helper
{
  public function __construct()
  {
    Output::setStyle('weather_hot', array('bg' => 'red', 'fg' => 'yellow'));
    Output::setStyle('weather_cold', array('bg' => 'blue', 'fg' => 'white'));
  }

    public function formatTemperature($temperature, $unit)
    {
      $style = $temperature < 0 ? 'weather_cold' : 'weather_hot';

    return sprintf("<%s> %s%s </%s>", $style, $temperature, strtoupper($unit),
$style);
  }

    public function getName()
    {
      return 'weather';
    }
}

                                The Symfony Components – Fabien Potencier
$output->writeln(sprintf(
  " %s, low: %s, high: %s",
  $attrs['text'],
  $this->weather->formatTemperature(
    $attrs['low'],
    $input->getOption('unit')),
  $this->weather->formatTemperature(
    $attrs['high'],
    $input->getOption('unit'))
));



                  The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
Console

    Testing



The Symfony Components – Fabien Potencier
$input = new ArrayInput(
   array('place' => 'Paris', '--unit' => 'C')
);
$application->run($input);

$input = new StringInput('Paris --unit=C');
$application->run($input);



                The Symfony Components – Fabien Potencier
$stream = fopen('php://memory', 'a', false);
$output = new StreamOutput($stream);

$application->run($input, $output);

rewind($output->getStream());
echo stream_get_contents($output->getStream());



                The Symfony Components – Fabien Potencier
$application = new Application();

// for testing
$application->setCatchExceptions(false);
$application->setAutoExit(false);



             The Symfony Components – Fabien Potencier
echo $application->asXml();




           The Symfony Components – Fabien Potencier
$command = new WeatherCommand();
echo $command->asXml();




           The Symfony Components – Fabien Potencier
Create a PHAR archive
  out of your CLI tool
    for distribution
     The Symfony Components – Fabien Potencier
$pharFile = 'life.phar’;
if (file_exists($pharFile))
  unlink($pharFile);

$phar = new Phar($pharFile, 0, $this->application->getName());
$phar->setSignatureAlgorithm(Phar::SHA1);
$phar->startBuffering();

// CLI Component files
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../symfony/src/Symfony/Components/
Console'), RecursiveIteratorIterator::LEAVES_ONLY) as $file)
{
  $phar['Symfony/Components/Console'.str_replace(__DIR__.'/../symfony/src/Symfony/Components/Console', '', $file)] =
file_get_contents($file);
}
// Life stuff
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../Life'),
RecursiveIteratorIterator::LEAVES_ONLY) as $file)
{
  $phar['Life'.str_replace(__DIR__.'/../Life', '', $file)] = file_get_contents($file);
}
// Autoloader
$phar['Symfony/Foundation/UniversalClassLoader.php'] = file_get_contents(__DIR__.'/../symfony/src/Symfony/Foundation/
UniversalClassLoader.php');

// Stubs
$phar['_cli_stub.php'] = $this->getCliStub();
$phar['_web_stub.php'] = $this->getWebStub();
$phar->setDefaultStub('_cli_stub.php', '_web_stub.php');
$phar->stopBuffering();
$phar->compressFiles(Phar::GZ);
unset($phar);

                                       The Symfony Components – Fabien Potencier
git clone http://github.com/fabpot/confoo2010




                The Symfony Components – Fabien Potencier
Routing

    Pretty and Smart URLs



The Symfony Components – Fabien Potencier
http://example.com/article.php?id=44

http://example.com/article/confoo-2010




            The Symfony Components – Fabien Potencier
Routing is a two-way process
   Matching incoming requests (URLs)
           Generating URLs


           The Symfony Components – Fabien Potencier
The architecture
is difficult to get right

     The Symfony Components – Fabien Potencier
Symfony one is built
with performance in mind

      The Symfony Components – Fabien Potencier
Routing

    Describing your routes



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingRouteCollection;
use SymfonyComponentsRoutingRoute;

$routes = new RouteCollection();
$route = new Route(
   '/',
   array('to' => function () { echo "Home!"; })
);
$routes->addRoute('home', $route);


                The Symfony Components – Fabien Potencier
$route = new Route(
   '/:year/:month/:day/:slug',
   array('to' => function ($params) { var_export
($params); }),
   array('year' => 'd{4}')
);
$routes->addRoute('blog_post', $route);



                The Symfony Components – Fabien Potencier
Routing

    Matching URLs



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingMatcherUrlMatcher;

$matcher = new UrlMatcher($routes);

if (false === $params = $matcher->match('/'))
{
  throw new Exception('No route matches.');
}

$params['to']();


                   The Symfony Components – Fabien Potencier
$params = $matcher->match('/2010/03/10/confoo');
if (false === $params)
{
  throw new Exception('No route matches.');
}

$params['to']($params);



                The Symfony Components – Fabien Potencier
array (
  'to' =>
  Closure::__set_state(array(
  )),
  'year' => '2010',
  'month' => '03',
  'day' => '10',
  'slug' => 'confoo',
  '_route' => 'blog_post',
)

                The Symfony Components – Fabien Potencier
$params = $matcher->match('/yyyy/03/10/confoo');
if (false === $params)
{
  throw new Exception('No route matches.');
}

$params['to']($params);

Uncaught exception 'Exception' with message 'No
route matches.'


                The Symfony Components – Fabien Potencier
Routing

    Generating URLs



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingGeneratorUrlGenerator;

$generator = new UrlGenerator($routes);

echo $generator->generate('home', array());




                  The Symfony Components – Fabien Potencier
$params =    array(
   'year'    => 2010,
   'month'   => 10,
   'day'     => 10,
   'slug'    => 'another-one'
);

echo $generator->generate('blog_post', $params);



                   The Symfony Components – Fabien Potencier
$params =    array(
   'year'    => 'yyyy',
   'month'   => 10,
   'day'     => 10,
);

echo $generator->generate('blog_post', $params);

Uncaught exception 'InvalidArgumentException'
with message 'The "blog_post" route has some
missing mandatory parameters (:slug).'

                   The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingGeneratorUrlGenerator;

$generator = new UrlGenerator($routes);

echo $generator->generate('home', array('foo' =>
'bar'));


/?foo=bar



                  The Symfony Components – Fabien Potencier
$generator = new   UrlGenerator($routes, array(
  'base_url' =>    '/myapp',
  'host'      =>   'www.example.com',
  'is_secure' =>   false,
));

echo $generator->generate('home', array(), true);


http://www.example.com/myapp/


                   The Symfony Components – Fabien Potencier
The context
        makes the routing
decoupled from the rest of the world

                      base_url
                        host
                     is_secure
                       method

      The Symfony Components – Fabien Potencier
Routing

    Describing your routes with XML or YAML



The Symfony Components – Fabien Potencier
home:
  pattern: /
  defaults: { controller: home, action: index }

blog_post:
  pattern: /:year/:month/:day/:slug
  defaults:
    controller: blog
    action:     show
  requirements:
    year: d{4}


                The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingLoaderYamlFileLoader;

$loader = new YamlFileLoader();

$routes = $loader->load('routes.yml');




                  The Symfony Components – Fabien Potencier
<?xml version="1.0" encoding="UTF-8" ?>

<routes xmlns="http://www.symfony-project.org/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.symfony-project.org/schema/routing
http://www.symfony-project.org/schema/routing/routing-1.0.xsd">

  <route id="blog_post" pattern="/:year/:month/:day/:slug">
    <default key="controller">blog</default>
    <default key="action">show</default>
    <requirement key="year">d{4}</requirement>
  </route>

  <route id="home" pattern="/">
    <default key="controller">home</default>
    <default key="action">index</default>
  </route>
</routes>

                       The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingLoaderXmlFileLoader;

$loader = new XmlFileLoader();

$routes = $loader->load('routes.xml');




                  The Symfony Components – Fabien Potencier
<?xml version="1.0" encoding="UTF-8" ?>

<routes>
  <route id="home" pattern="/">
    <default key="controller">home</default>
    <default key="action">index</default>
  </route>

  <import resource="blog.yml" prefix="/blog" />
  <import resource="forum.xml" prefix="/forum" />
</routes>

                 The Symfony Components – Fabien Potencier
home:
  pattern: /
  defaults: { controller: home, action: index }

import:
  - { resource: blog.yml, prefix: /blog }
  - { resource: forum.xml, prefix: /forum }



                The Symfony Components – Fabien Potencier
$yamlLoader = new YamlFileLoader();
$xmlLoader = new XmlFileLoader();

$routes = new RouteCollection();
$route = new Route(
   '/',
   array('to' => function () { echo "Home!"; })
);
$routes->addRoute('home', $route);

$routes->addCollection(
  $yamlLoader->load('blog.yml'), '/blog');

$routes->addCollection(
  $xmlLoader->load('forum.xml'), '/forum');
                   The Symfony Components – Fabien Potencier
/blog/2010/03/10/confoo
 prefix                                      pattern




         The Symfony Components – Fabien Potencier
Routing

    Make it simple & fast



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingRouter;

$router = new Router($loader, $options, $context);




                  The Symfony Components – Fabien Potencier
$loader = function ()
{
  $routes = new RouteCollection();
  // ...

  return $routes;
};

$context = array(
   'base_url' => '/myapp',
   'host'      => 'www.example.com',
   'is_secure' => false,
);

$options = array(
   'cache_dir' => '/tmp/routing',
   'debug'     => true,
);
                       The Symfony Components – Fabien Potencier
$router = new Router($loader, $options, $context);

if (false === $params = $router->match('/'))
{
  throw new Exception('No route matches.');
}

echo $router->generate('home', array());




                  The Symfony Components – Fabien Potencier
class ProjectUrlMatcher extends SymfonyComponentsRouting
MatcherUrlMatcher
{
  // ...

    public function match($url)
    {
      $url = $this->normalizeUrl($url);

      if (preg_match('#^/$#x', $url, $matches))
        return array_merge($this->mergeDefaults($matches, array
(    'to' => 'foo',)), array('_route' => 'home'));

        return false;
    }
}

                        The Symfony Components – Fabien Potencier
class ProjectUrlGenerator extends SymfonyComponentsRoutingGeneratorUrlGenerator
{
  // ...

  public function generate($name, array $parameters, $absolute = false)
  {
    if (!method_exists($this, $method = 'get'.$name.'RouteInfo'))
    {
      throw new InvalidArgumentException(sprintf('Route "%s" does not exist.', $name));
    }

    list($variables, $defaults, $requirements, $tokens) = $this->$method();

    return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters,
$name, $absolute);
  }

  protected function gethomeRouteInfo()
  {
    return array(array (), array_merge($this->defaults, array ( 'to' => 'foo',)), array
(), array ( 0 =>    array (    0 => 'text',    1 => '/',    2 => '',   3 => NULL, ),));
  }
}

                              The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingFileResource;

$loader = function ()
{
  $routes = new RouteCollection();
  // ...

  $routes->addResource(new FileResource(__FILE__));

  return $routes;
};


                    The Symfony Components – Fabien Potencier
Routing

    Make it really fast



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingMatcherDumper
ApacheMatcherDumper;

$dumper = new ApacheMatcherDumper($routes);

echo $dumper->dump();




                The Symfony Components – Fabien Potencier
RewriteCond %{PATH_INFO} ^/$
RewriteRule .* index.php
[QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo
]




                The Symfony Components – Fabien Potencier
$options = array(
   'cache_dir'     => '/tmp/routing',
   'debug'         => true,
   'matcher_class' => 'SymfonyComponents
RoutingMatcherApacheUrlMatcher',
);




                The Symfony Components – Fabien Potencier
Output Escaper




The Symfony Components – Fabien Potencier
Provides XSS protection
 for your PHP templates

      The Symfony Components – Fabien Potencier
Wraps template variables
Works for
   strings
   arrays
   objects
      properties
      methods
      __call(), __get(), …
      Iterators, Coutables, …
      …
Works for deep method calls
                         The Symfony Components – Fabien Potencier
use SymfonyComponentsOutputEscaperEscaper;

$title = 'Foo <br />';

echo Escaper::escape('htmlspecialchars', $title);




                     The Symfony Components – Fabien Potencier
use SymfonyComponentsOutputEscaperEscaper;

$article = array(
   'title' => 'Foo <br />',
   'author' => array(
     'name' => 'Fabien <br/>',
   )
);

$article = Escaper::escape('htmlspecialchars', $article);

echo $article['title']."n";
echo $article['author']['name']."n";


                      The Symfony Components – Fabien Potencier
class Article
{
  protected $title;
  protected $author;

    public $full_title;    public property

    public function __construct($title, Author $author)
    {
      $this->title = $title;
      $this->full_title = $title;
      $this->author = $author;
    }
                                                                         public method
    public function getTitle() { return $this->title; }
    public function getAuthor() { return $this->author; }                     public method returning
    public function __get($key) { return $this->$key; }                       another object
    public function __call($method, $arguments)
    {                                                                       magic __get()
      return $this->{'get'.$method}();     magic __call()
    }
}
                             The Symfony Components – Fabien Potencier
class Author
{
  protected $name;

    public function __construct($name) { $this->name = $name; }
    public function getName() { return $this->name; }
}




                       The Symfony Components – Fabien Potencier
use SymfonyComponentsOutputEscaperEscaper;

$article = new Article(
   'foo <br />',
   new Author('Fabien <br />')
);

$article = Escaper::escape('htmlspecialchars', $article);

echo   $article->getTitle()."n";
echo   $article->getAuthor()->getName()."n";
echo   $article->full_title."n";
echo   $article->title."n";
echo   $article->title()."n";


                       The Symfony Components – Fabien Potencier
explicitly ask
                                                              for raw data


echo $article->getHtmlContent('raw');



echo $article->getTitle('js');
                                             change the default
                                             escaping strategy



                The Symfony Components – Fabien Potencier
Request Handler




The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;

$request = new Request();
$request->getPathInfo();
$request->getPreferredLanguage(array('en', 'fr'));
$request->isXmlHttpRequest();




                 The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;

$request = new   Request(array(
  'request' =>   $_POST,
  'query'   =>   $_GET,
  'path'    =>   array(),
  'server' =>    $_SERVER,
));



                  The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerResponse;

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

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



                  The Symfony Components – Fabien Potencier
Request Handler

    Framework to build Frameworks



The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;
use SymfonyComponentsRequestHandlerResponse;
use SymfonyComponentsRequestHandlerRequestHandler;

$handler = new RequestHandler($dispatcher);

$request = new Request();
$response = $handler->handle($request);
$response->send();



                  The Symfony Components – Fabien Potencier
use SymfonyComponentsEventDispatcherEventDispatcher;
use SymfonyComponentsEventDispatcherEvent;

$dispatcher = new EventDispatcher();
$dispatcher->connect('core.load_controller', function (Event $event)
{
  $event->setReturnValue(array(
    function ($request) { return new Response('Hello!'); },
    array($event['request'])
  ));

  return true;
});




                         The Symfony Components – Fabien Potencier
Request Handler

    A small Framework



The Symfony Components – Fabien Potencier
$framework = new Framework(array(
  '/' => function ($request)
  {
    $content = 'Hello '.
      $request->getParameter('name');

    return new Response($content);
  }
));
$framework->run();

                The Symfony Components – Fabien Potencier
class Framework
{
  protected $map;

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

    public function run()
    {
      $dispatcher = new EventDispatcher();
      $dispatcher->connect('core.load_controller', array($this, 'loadController'));

        $handler = new RequestHandler($dispatcher);
        $response = $handler->handle(new Request());
        $response->send();
    }
}



                                The Symfony Components – Fabien Potencier
public function loadController(Event $event)
{
  $request = $event['request'];

    $routes = new RouteCollection();
    foreach ($this->map as $pattern => $to)
    {
      $route = new Route($pattern, array('to' => $to));
      $routes->addRoute(str_replace('/', '_', $pattern), $route);
    }

    $matcher = new UrlMatcher($routes, array(
      'base_url' => $request->getBaseUrl(),
      'method'    => $request->getMethod(),
      'host'      => $request->getHost(),
      'is_secure' => $request->isSecure(),
    ));

    $parameters = $matcher->match($request->getPathInfo());
    if (false === $parameters)
    {
      return false;
    }

    $request->setPathParameters($parameters);

    $event->setReturnValue(array($parameters['to'], array($request)));

    return true;
}
                                      The Symfony Components – Fabien Potencier
$framework = new Framework(array(
  '/' => function ($request)
  {
    $content = 'Hello '.
      $request->getParameter('name');

    return new Response($content);
  }
));
$framework->run();

                The Symfony Components – Fabien Potencier
Questions?




The Symfony Components – Fabien Potencier
Sensio S.A.
        92-98, boulevard Victor Hugo
            92 115 Clichy Cedex
                  FRANCE
             Tél. : +33 1 40 99 80 80

                  Contact
              Fabien Potencier
       fabien.potencier at sensio.com




   http://www.sensiolabs.com/
http://www.symfony-project.org/
 http://fabien.potencier.org/


The Symfony Components – Fabien Potencier

Symfony Components

  • 1.
    The Symfony Components– Fabien Potencier
  • 2.
    Serial entrepreneur Developer bypassion Founder of Sensio Creator and lead developer of Symfony On Twitter @fabpot On github http://www.github.com/fabpot http://fabien.potencier.org/ The Symfony Components – Fabien Potencier
  • 3.
    Standalone components forPHP 5.3 No dependency between them Used extensively in Symfony 2, the framework The Symfony Components – Fabien Potencier
  • 4.
    Low-level libraries needed bymost websites The Symfony Components – Fabien Potencier
  • 5.
    Event Dispatcher Stable Output Escaper Stable Extracted from symfony 1 YAML Stable Routing Beta Console Stable Dependency Injection Container Stable Written from scratch for Symfony 2 Request Handler Stable Templating Stable The Symfony Components – Fabien Potencier
  • 6.
    YAML Event Dispatcher PHP Quebec 2009 Templating Dependency Injection Container Console Routing ConFoo 2010 Output Escaper Request Handler The Symfony Components – Fabien Potencier
  • 7.
    Download / Installation TheSymfony Components – Fabien Potencier
  • 8.
    git clone git://github.com/symfony/symfony.git Main repository The Symfony Components – Fabien Potencier
  • 9.
    svn checkout http://svn.symfony-project.org/branches/2.0/ Git Mirror Synchronized every 15 minutes The Symfony Components – Fabien Potencier
  • 10.
    curl -O http://github.com/symfony/symfony/tarball/master tarzxpf symfony-symfony-XXXXXXX.tar.gz curl -O http://github.com/symfony/symfony/zipball/master unzip symfony-symfony-XXXXXXX.zip Nightly build The Symfony Components – Fabien Potencier
  • 11.
    app/ .../ Symfony/ Components/ Foundation/ Framework/ The Symfony Components – Fabien Potencier
  • 12.
    Autoloading Classes The SymfonyComponents – Fabien Potencier
  • 13.
    Before PHP 5.3 PEARnaming convention The Symfony Components – Fabien Potencier
  • 14.
    PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Doctrine_Pager_Range > Doctrine/Pager/Range.php Twig_Node_For > Twig/Node/For.php The Symfony Components – Fabien Potencier
  • 15.
    PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Doctrine_Pager_Range > Doctrine/Pager/Range.php Twig_Node_For > Twig/Node/For.php Vendor name The Symfony Components – Fabien Potencier
  • 16.
    As of PHP5.3 PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  • 17.
    SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php The Symfony Components – Fabien Potencier
  • 18.
    SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php Vendor name The Symfony Components – Fabien Potencier
  • 19.
    PHP 5.3 technicalinteroperability standards « … describes the mandatory requirements that must be adhered to for autoloader interoperability » http://groups.google.com/group/php-standards/web/psr-0-final-proposal The Symfony Components – Fabien Potencier
  • 20.
    use SymfonyFoundationUniversalClassLoader; The Symfony Components – Fabien Potencier
  • 21.
    require_once '.../Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader= new UniversalClassLoader(); $loader->registerNamespace( 'Symfony', __DIR__.'/src/symfony/src' ); $loader->register(); // use any Symfony class The Symfony Components – Fabien Potencier
  • 22.
    $loader->registerNamespaces(array( 'Symfony'=> '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', 'pdepend' => '/path/to/reflection/source', )); PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  • 23.
    $loader->registerPrefixes(array( 'Swift_'=> '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); PEAR style The Symfony Components – Fabien Potencier
  • 24.
    require_once '.../Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader= new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', )); $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); $loader->register(); // use any class The Symfony Components – Fabien Potencier
  • 25.
    Console The Symfony Components– Fabien Potencier
  • 26.
    Console The Symfony Components– Fabien Potencier
  • 27.
    Automate things code generators deployment The Symfony Components – Fabien Potencier
  • 28.
    Long running tasks deployment get « things » from the Internet The Symfony Components – Fabien Potencier
  • 29.
    Batches cleanup a databasefrom time to time migrate a DB to a new schema The Symfony Components – Fabien Potencier
  • 30.
    These tasks shouldnever be run from a browser The Symfony Components – Fabien Potencier
  • 31.
    But PHP is aweb language, right? The Symfony Components – Fabien Potencier
  • 32.
    So, why notuse the right tool for the job? … like Perl or Python? The Symfony Components – Fabien Potencier
  • 33.
    Don’t want touse/learn another language Want to share code The Symfony Components – Fabien Potencier
  • 34.
    PHP natively supports the CLI environment The Symfony Components – Fabien Potencier
  • 35.
    <?php // ... The Symfony Components – Fabien Potencier
  • 36.
    #!/usr/bin/env php <?php // ... $ ./foo … The Symfony Components – Fabien Potencier
  • 37.
    $ ./foobar Fabien $name= $argv[1]; echo 'Hello '.$name; The Symfony Components – Fabien Potencier
  • 38.
    … but thecomplexity lies in the details The Symfony Components – Fabien Potencier
  • 39.
    option / argumentshandling exit codes shell output colorization tests error messages … The Symfony Components – Fabien Potencier
  • 40.
    $ ./life foo"foo bar" --foo foobar -b Array ( [0] => ./life [1] => foo [2] => foo bar [3] => --foo [4] => foobar [5] => -b ) The Symfony Components – Fabien Potencier
  • 41.
    don’t reinvent thewheel… use a “framework” The Symfony Components – Fabien Potencier
  • 42.
    Console The Symfony Components– Fabien Potencier
  • 43.
    Let’s create aCLI tool to get the weather anywhere in the world The Symfony Components – Fabien Potencier
  • 44.
    The Symfony Components– Fabien Potencier
  • 45.
    use LifeYahooWeather; $weather =new YahooWeather('API_KEY', $argv[1]); echo $weather->getTitle()."n"; $attrs = $weather->getCurrentConditions(); echo "Current conditions:n"; echo sprintf(" %s, %sCn", $attrs['text'], $attrs['temp']); $attrs = $weather->getForecast(); echo sprintf("nForecast for %sn", $attrs['date']); echo sprintf(" %s, low: %s, high: %sn", $attrs['text'], $attrs['low'], $attrs['high']); The Symfony Components – Fabien Potencier
  • 46.
    use SymfonyComponentsConsoleApplication; $application =new Application(); $application->run(); The Symfony Components – Fabien Potencier
  • 47.
    $command = newCommand('weather'); $command->setCode( function ($input, $output) { // do something } ); $application->addCommand($command); The Symfony Components – Fabien Potencier
  • 48.
    use SymfonyComponentsConsoleApplication; $application =new Application(); $application->addCommand(new WeatherCommand()); $application->run(); The Symfony Components – Fabien Potencier
  • 49.
    use SymfonyComponentsConsoleCommandCommand; use SymfonyComponentsConsoleInputInputInterface; useSymfonyComponentsConsoleOutputOutputInterface; class WeatherCommand extends Command { protected function configure() { $this->setName('weather'); } protected function execute(InputInterface $input, OutputInterface $output) { // do something } } The Symfony Components – Fabien Potencier
  • 50.
    Console The Output The Symfony Components – Fabien Potencier
  • 51.
    $output->writeln($weather->getTitle()); The Symfony Components – Fabien Potencier
  • 52.
    $output->writeln( sprintf('<info>%s</info>', $weather->getTitle()) ); $output->writeln("<comment>Conditions</comment>"); The Symfony Components – Fabien Potencier
  • 53.
    The Symfony Components– Fabien Potencier
  • 54.
    The Symfony Components– Fabien Potencier
  • 55.
    Console Getting help The Symfony Components – Fabien Potencier
  • 56.
    The Symfony Components– Fabien Potencier
  • 57.
    $application = newApplication('Life Tool', '0.1'); The Symfony Components – Fabien Potencier
  • 58.
    class WeatherCommand extendsCommand { protected function configure() { $this->setName('weather') ->setDescription('Displays weather forecast') ->setHelp(<<<EOF The <info>weather</info> command displays weather forecast for a given city: <info>./life weather Paris</info> You can also change the default degree unit with the <comment>--unit</comment> option: <info>./life weather Paris --unit=c</info> <info>./life weather Paris -u c</info> EOF ); } The Symfony Components – Fabien Potencier
  • 59.
    The Symfony Components– Fabien Potencier
  • 60.
    The Symfony Components– Fabien Potencier
  • 61.
    $ ./life weather $./life weath $ ./life w The Symfony Components – Fabien Potencier
  • 62.
    Console The Input The Symfony Components – Fabien Potencier
  • 63.
    class WeatherCommand extendsCommand { protected function configure() { $definition = array( new InputArgument('place', InputArgument::OPTIONAL, 'The place name', 'Paris'), new InputOption('unit', 'u', InputOption::PARAMETER_REQUIRED, 'The degree unit', 'c'), ); $this->setDefinition($definition); The Symfony Components – Fabien Potencier
  • 64.
    The Symfony Components– Fabien Potencier
  • 65.
    protected function execute(InputInterface$input, OutputInterface $output) { $city = $input->getArgument('place'); $unit = $input->getOption('unit'); $output->writeln("<comment>Conditions</comment>"); } The Symfony Components – Fabien Potencier
  • 66.
    Console Error codes / Exit status The Symfony Components – Fabien Potencier
  • 67.
    The Symfony Components– Fabien Potencier
  • 68.
    The Symfony Components– Fabien Potencier
  • 69.
    protected function execute(InputInterface$input, OutputInterface $output) { $city = $input->getArgument('place'); $unit = $input->getOption('unit'); $output->writeln("<comment>Conditions</comment>"); return 120; } The Symfony Components – Fabien Potencier
  • 70.
    Console Interact with the user The Symfony Components – Fabien Potencier
  • 71.
    protected function interact($input,$output) { $city = $this->dialog->ask( $output, '<comment>Which city?</comment> (Paris)', 'Paris’ ); $input->setArgument('place', $city); } The Symfony Components – Fabien Potencier
  • 72.
    ./life weather --no-interaction The Symfony Components – Fabien Potencier
  • 73.
    dialog ask() askConfirmation() askAndValidate() formatter formatSection() formatBlock() ... your own The Symfony Components – Fabien Potencier
  • 74.
    class WeatherHelper extendsHelper { public function __construct() { Output::setStyle('weather_hot', array('bg' => 'red', 'fg' => 'yellow')); Output::setStyle('weather_cold', array('bg' => 'blue', 'fg' => 'white')); } public function formatTemperature($temperature, $unit) { $style = $temperature < 0 ? 'weather_cold' : 'weather_hot'; return sprintf("<%s> %s%s </%s>", $style, $temperature, strtoupper($unit), $style); } public function getName() { return 'weather'; } } The Symfony Components – Fabien Potencier
  • 75.
    $output->writeln(sprintf( "%s, low: %s, high: %s", $attrs['text'], $this->weather->formatTemperature( $attrs['low'], $input->getOption('unit')), $this->weather->formatTemperature( $attrs['high'], $input->getOption('unit')) )); The Symfony Components – Fabien Potencier
  • 76.
    The Symfony Components– Fabien Potencier
  • 77.
    Console Testing The Symfony Components – Fabien Potencier
  • 78.
    $input = newArrayInput( array('place' => 'Paris', '--unit' => 'C') ); $application->run($input); $input = new StringInput('Paris --unit=C'); $application->run($input); The Symfony Components – Fabien Potencier
  • 79.
    $stream = fopen('php://memory','a', false); $output = new StreamOutput($stream); $application->run($input, $output); rewind($output->getStream()); echo stream_get_contents($output->getStream()); The Symfony Components – Fabien Potencier
  • 80.
    $application = newApplication(); // for testing $application->setCatchExceptions(false); $application->setAutoExit(false); The Symfony Components – Fabien Potencier
  • 81.
    echo $application->asXml(); The Symfony Components – Fabien Potencier
  • 82.
    $command = newWeatherCommand(); echo $command->asXml(); The Symfony Components – Fabien Potencier
  • 83.
    Create a PHARarchive out of your CLI tool for distribution The Symfony Components – Fabien Potencier
  • 84.
    $pharFile = 'life.phar’; if(file_exists($pharFile)) unlink($pharFile); $phar = new Phar($pharFile, 0, $this->application->getName()); $phar->setSignatureAlgorithm(Phar::SHA1); $phar->startBuffering(); // CLI Component files foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../symfony/src/Symfony/Components/ Console'), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { $phar['Symfony/Components/Console'.str_replace(__DIR__.'/../symfony/src/Symfony/Components/Console', '', $file)] = file_get_contents($file); } // Life stuff foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../Life'), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { $phar['Life'.str_replace(__DIR__.'/../Life', '', $file)] = file_get_contents($file); } // Autoloader $phar['Symfony/Foundation/UniversalClassLoader.php'] = file_get_contents(__DIR__.'/../symfony/src/Symfony/Foundation/ UniversalClassLoader.php'); // Stubs $phar['_cli_stub.php'] = $this->getCliStub(); $phar['_web_stub.php'] = $this->getWebStub(); $phar->setDefaultStub('_cli_stub.php', '_web_stub.php'); $phar->stopBuffering(); $phar->compressFiles(Phar::GZ); unset($phar); The Symfony Components – Fabien Potencier
  • 85.
    git clone http://github.com/fabpot/confoo2010 The Symfony Components – Fabien Potencier
  • 86.
    Routing Pretty and Smart URLs The Symfony Components – Fabien Potencier
  • 87.
  • 88.
    Routing is atwo-way process Matching incoming requests (URLs) Generating URLs The Symfony Components – Fabien Potencier
  • 89.
    The architecture is difficultto get right The Symfony Components – Fabien Potencier
  • 90.
    Symfony one isbuilt with performance in mind The Symfony Components – Fabien Potencier
  • 91.
    Routing Describing your routes The Symfony Components – Fabien Potencier
  • 92.
    use SymfonyComponentsRoutingRouteCollection; use SymfonyComponentsRoutingRoute; $routes= new RouteCollection(); $route = new Route( '/', array('to' => function () { echo "Home!"; }) ); $routes->addRoute('home', $route); The Symfony Components – Fabien Potencier
  • 93.
    $route = newRoute( '/:year/:month/:day/:slug', array('to' => function ($params) { var_export ($params); }), array('year' => 'd{4}') ); $routes->addRoute('blog_post', $route); The Symfony Components – Fabien Potencier
  • 94.
    Routing Matching URLs The Symfony Components – Fabien Potencier
  • 95.
    use SymfonyComponentsRoutingMatcherUrlMatcher; $matcher =new UrlMatcher($routes); if (false === $params = $matcher->match('/')) { throw new Exception('No route matches.'); } $params['to'](); The Symfony Components – Fabien Potencier
  • 96.
    $params = $matcher->match('/2010/03/10/confoo'); if(false === $params) { throw new Exception('No route matches.'); } $params['to']($params); The Symfony Components – Fabien Potencier
  • 97.
    array ( 'to' => Closure::__set_state(array( )), 'year' => '2010', 'month' => '03', 'day' => '10', 'slug' => 'confoo', '_route' => 'blog_post', ) The Symfony Components – Fabien Potencier
  • 98.
    $params = $matcher->match('/yyyy/03/10/confoo'); if(false === $params) { throw new Exception('No route matches.'); } $params['to']($params); Uncaught exception 'Exception' with message 'No route matches.' The Symfony Components – Fabien Potencier
  • 99.
    Routing Generating URLs The Symfony Components – Fabien Potencier
  • 100.
    use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator =new UrlGenerator($routes); echo $generator->generate('home', array()); The Symfony Components – Fabien Potencier
  • 101.
    $params = array( 'year' => 2010, 'month' => 10, 'day' => 10, 'slug' => 'another-one' ); echo $generator->generate('blog_post', $params); The Symfony Components – Fabien Potencier
  • 102.
    $params = array( 'year' => 'yyyy', 'month' => 10, 'day' => 10, ); echo $generator->generate('blog_post', $params); Uncaught exception 'InvalidArgumentException' with message 'The "blog_post" route has some missing mandatory parameters (:slug).' The Symfony Components – Fabien Potencier
  • 103.
    use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator =new UrlGenerator($routes); echo $generator->generate('home', array('foo' => 'bar')); /?foo=bar The Symfony Components – Fabien Potencier
  • 104.
    $generator = new UrlGenerator($routes, array( 'base_url' => '/myapp', 'host' => 'www.example.com', 'is_secure' => false, )); echo $generator->generate('home', array(), true); http://www.example.com/myapp/ The Symfony Components – Fabien Potencier
  • 105.
    The context makes the routing decoupled from the rest of the world base_url host is_secure method The Symfony Components – Fabien Potencier
  • 106.
    Routing Describing your routes with XML or YAML The Symfony Components – Fabien Potencier
  • 107.
    home: pattern:/ defaults: { controller: home, action: index } blog_post: pattern: /:year/:month/:day/:slug defaults: controller: blog action: show requirements: year: d{4} The Symfony Components – Fabien Potencier
  • 108.
    use SymfonyComponentsRoutingLoaderYamlFileLoader; $loader =new YamlFileLoader(); $routes = $loader->load('routes.yml'); The Symfony Components – Fabien Potencier
  • 109.
    <?xml version="1.0" encoding="UTF-8"?> <routes xmlns="http://www.symfony-project.org/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.symfony-project.org/schema/routing http://www.symfony-project.org/schema/routing/routing-1.0.xsd"> <route id="blog_post" pattern="/:year/:month/:day/:slug"> <default key="controller">blog</default> <default key="action">show</default> <requirement key="year">d{4}</requirement> </route> <route id="home" pattern="/"> <default key="controller">home</default> <default key="action">index</default> </route> </routes> The Symfony Components – Fabien Potencier
  • 110.
    use SymfonyComponentsRoutingLoaderXmlFileLoader; $loader =new XmlFileLoader(); $routes = $loader->load('routes.xml'); The Symfony Components – Fabien Potencier
  • 111.
    <?xml version="1.0" encoding="UTF-8"?> <routes> <route id="home" pattern="/"> <default key="controller">home</default> <default key="action">index</default> </route> <import resource="blog.yml" prefix="/blog" /> <import resource="forum.xml" prefix="/forum" /> </routes> The Symfony Components – Fabien Potencier
  • 112.
    home: pattern:/ defaults: { controller: home, action: index } import: - { resource: blog.yml, prefix: /blog } - { resource: forum.xml, prefix: /forum } The Symfony Components – Fabien Potencier
  • 113.
    $yamlLoader = newYamlFileLoader(); $xmlLoader = new XmlFileLoader(); $routes = new RouteCollection(); $route = new Route( '/', array('to' => function () { echo "Home!"; }) ); $routes->addRoute('home', $route); $routes->addCollection( $yamlLoader->load('blog.yml'), '/blog'); $routes->addCollection( $xmlLoader->load('forum.xml'), '/forum'); The Symfony Components – Fabien Potencier
  • 114.
    /blog/2010/03/10/confoo prefix pattern The Symfony Components – Fabien Potencier
  • 115.
    Routing Make it simple & fast The Symfony Components – Fabien Potencier
  • 116.
    use SymfonyComponentsRoutingRouter; $router =new Router($loader, $options, $context); The Symfony Components – Fabien Potencier
  • 117.
    $loader = function() { $routes = new RouteCollection(); // ... return $routes; }; $context = array( 'base_url' => '/myapp', 'host' => 'www.example.com', 'is_secure' => false, ); $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, ); The Symfony Components – Fabien Potencier
  • 118.
    $router = newRouter($loader, $options, $context); if (false === $params = $router->match('/')) { throw new Exception('No route matches.'); } echo $router->generate('home', array()); The Symfony Components – Fabien Potencier
  • 119.
    class ProjectUrlMatcher extendsSymfonyComponentsRouting MatcherUrlMatcher { // ... public function match($url) { $url = $this->normalizeUrl($url); if (preg_match('#^/$#x', $url, $matches)) return array_merge($this->mergeDefaults($matches, array ( 'to' => 'foo',)), array('_route' => 'home')); return false; } } The Symfony Components – Fabien Potencier
  • 120.
    class ProjectUrlGenerator extendsSymfonyComponentsRoutingGeneratorUrlGenerator { // ... public function generate($name, array $parameters, $absolute = false) { if (!method_exists($this, $method = 'get'.$name.'RouteInfo')) { throw new InvalidArgumentException(sprintf('Route "%s" does not exist.', $name)); } list($variables, $defaults, $requirements, $tokens) = $this->$method(); return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute); } protected function gethomeRouteInfo() { return array(array (), array_merge($this->defaults, array ( 'to' => 'foo',)), array (), array ( 0 => array ( 0 => 'text', 1 => '/', 2 => '', 3 => NULL, ),)); } } The Symfony Components – Fabien Potencier
  • 121.
    use SymfonyComponentsRoutingFileResource; $loader =function () { $routes = new RouteCollection(); // ... $routes->addResource(new FileResource(__FILE__)); return $routes; }; The Symfony Components – Fabien Potencier
  • 122.
    Routing Make it really fast The Symfony Components – Fabien Potencier
  • 123.
    use SymfonyComponentsRoutingMatcherDumper ApacheMatcherDumper; $dumper =new ApacheMatcherDumper($routes); echo $dumper->dump(); The Symfony Components – Fabien Potencier
  • 124.
    RewriteCond %{PATH_INFO} ^/$ RewriteRule.* index.php [QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo ] The Symfony Components – Fabien Potencier
  • 125.
    $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, 'matcher_class' => 'SymfonyComponents RoutingMatcherApacheUrlMatcher', ); The Symfony Components – Fabien Potencier
  • 126.
    Output Escaper The SymfonyComponents – Fabien Potencier
  • 127.
    Provides XSS protection for your PHP templates The Symfony Components – Fabien Potencier
  • 128.
    Wraps template variables Worksfor strings arrays objects properties methods __call(), __get(), … Iterators, Coutables, … … Works for deep method calls The Symfony Components – Fabien Potencier
  • 129.
    use SymfonyComponentsOutputEscaperEscaper; $title ='Foo <br />'; echo Escaper::escape('htmlspecialchars', $title); The Symfony Components – Fabien Potencier
  • 130.
    use SymfonyComponentsOutputEscaperEscaper; $article =array( 'title' => 'Foo <br />', 'author' => array( 'name' => 'Fabien <br/>', ) ); $article = Escaper::escape('htmlspecialchars', $article); echo $article['title']."n"; echo $article['author']['name']."n"; The Symfony Components – Fabien Potencier
  • 131.
    class Article { protected $title; protected $author; public $full_title; public property public function __construct($title, Author $author) { $this->title = $title; $this->full_title = $title; $this->author = $author; } public method public function getTitle() { return $this->title; } public function getAuthor() { return $this->author; } public method returning public function __get($key) { return $this->$key; } another object public function __call($method, $arguments) { magic __get() return $this->{'get'.$method}(); magic __call() } } The Symfony Components – Fabien Potencier
  • 132.
    class Author { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } The Symfony Components – Fabien Potencier
  • 133.
    use SymfonyComponentsOutputEscaperEscaper; $article =new Article( 'foo <br />', new Author('Fabien <br />') ); $article = Escaper::escape('htmlspecialchars', $article); echo $article->getTitle()."n"; echo $article->getAuthor()->getName()."n"; echo $article->full_title."n"; echo $article->title."n"; echo $article->title()."n"; The Symfony Components – Fabien Potencier
  • 134.
    explicitly ask for raw data echo $article->getHtmlContent('raw'); echo $article->getTitle('js'); change the default escaping strategy The Symfony Components – Fabien Potencier
  • 135.
    Request Handler The SymfonyComponents – Fabien Potencier
  • 136.
    use SymfonyComponentsRequestHandlerRequest; $request =new Request(); $request->getPathInfo(); $request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest(); The Symfony Components – Fabien Potencier
  • 137.
    use SymfonyComponentsRequestHandlerRequest; $request =new Request(array( 'request' => $_POST, 'query' => $_GET, 'path' => array(), 'server' => $_SERVER, )); The Symfony Components – Fabien Potencier
  • 138.
    use SymfonyComponentsRequestHandlerResponse; $response =new Response('Hello World', 200, array('Content-Type' => 'text/plain')); $response->send(); $response->setHeader('Content-Type', 'text/plain'); $response->setCookie('foo', 'bar'); $response->setContent('Hello World'); $response->setStatusCode(200); The Symfony Components – Fabien Potencier
  • 139.
    Request Handler Framework to build Frameworks The Symfony Components – Fabien Potencier
  • 140.
    use SymfonyComponentsRequestHandlerRequest; use SymfonyComponentsRequestHandlerResponse; useSymfonyComponentsRequestHandlerRequestHandler; $handler = new RequestHandler($dispatcher); $request = new Request(); $response = $handler->handle($request); $response->send(); The Symfony Components – Fabien Potencier
  • 141.
    use SymfonyComponentsEventDispatcherEventDispatcher; use SymfonyComponentsEventDispatcherEvent; $dispatcher= new EventDispatcher(); $dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function ($request) { return new Response('Hello!'); }, array($event['request']) )); return true; }); The Symfony Components – Fabien Potencier
  • 142.
    Request Handler A small Framework The Symfony Components – Fabien Potencier
  • 143.
    $framework = newFramework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  • 144.
    class Framework { protected $map; public function __construct($map) { $this->map = $map; } public function run() { $dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', array($this, 'loadController')); $handler = new RequestHandler($dispatcher); $response = $handler->handle(new Request()); $response->send(); } } The Symfony Components – Fabien Potencier
  • 145.
    public function loadController(Event$event) { $request = $event['request']; $routes = new RouteCollection(); foreach ($this->map as $pattern => $to) { $route = new Route($pattern, array('to' => $to)); $routes->addRoute(str_replace('/', '_', $pattern), $route); } $matcher = new UrlMatcher($routes, array( 'base_url' => $request->getBaseUrl(), 'method' => $request->getMethod(), 'host' => $request->getHost(), 'is_secure' => $request->isSecure(), )); $parameters = $matcher->match($request->getPathInfo()); if (false === $parameters) { return false; } $request->setPathParameters($parameters); $event->setReturnValue(array($parameters['to'], array($request))); return true; } The Symfony Components – Fabien Potencier
  • 146.
    $framework = newFramework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  • 147.
  • 148.
    Sensio S.A. 92-98, boulevard Victor Hugo 92 115 Clichy Cedex FRANCE Tél. : +33 1 40 99 80 80 Contact Fabien Potencier fabien.potencier at sensio.com http://www.sensiolabs.com/ http://www.symfony-project.org/ http://fabien.potencier.org/ The Symfony Components – Fabien Potencier