0
The Symfony Components – Fabien Potencier
Serial entrepreneur
Developer by passion
Founder of Sensio
Creator and lead developer of Symfony
On Twitter @fabpot
On git...
Standalone components for PHP 5.3

       No dependency between them

Used extensively in Symfony 2, the framework

      ...
Low-level libraries
needed by most websites

      The Symfony Components – Fabien Potencier
Event Dispatcher                                              Stable

Output Escaper                                      ...
YAML
Event Dispatcher
                                                              PHP Quebec 2009
Templating
Dependency ...
Download / Installation




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




                                                            Main reposi...
svn checkout http://svn.symfony-project.org/branches/2.0/


                                                              ...
curl -O http://github.com/symfony/symfony/tarball/master
tar zxpf symfony-symfony-XXXXXXX.tar.gz

curl -O http://github.co...
app/
  .../
     Symfony/
       Components/
       Foundation/
       Framework/
        The Symfony Components – Fabien ...
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  ...
PEAR_Log                >      PEAR/Log.php
            Zend_Log                >      Zend/Log.php
  Swift_Mime_Message  ...
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
pdependreflecti...
SymfonyFoundationKernel > Symfony/Foundation/Kernel.php
     DoctrineDBALDriver > Doctrine/DBAL/Driver.php
pdependreflecti...
PHP 5.3 technical interoperability standards

             « … describes the mandatory requirements
                      ...
use SymfonyFoundationUniversalClassLoader;




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

use SymfonyFoundationUniversalClassLoader;

$loader = new...
$loader->registerNamespaces(array(
  'Symfony' => '/path/to/symfony/src',
  'Doctrine' => '/path/to/doctrine/lib',
  'pdep...
$loader->registerPrefixes(array(
  'Swift_' => '/path/to/swiftmailer/lib/classes',
  'Zend_' => '/path/to/vendor/zend/libr...
require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use SymfonyFoundationUniversalClassLoader;

$loader = new...
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 P...
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 P...
Don’t want to use/learn another language
          Want to share code


            The Symfony Components – Fabien Potenc...
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 Co...
$ ./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
       err...
$ ./life foo "foo bar" --foo foobar -b

Array
(
    [0]   =>   ./life
    [1]   =>   foo
    [2]   =>   foo bar
    [3]   ...
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...
use SymfonyComponentsConsoleApplication;

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




                The S...
$command = new Command('weather');
$command->setCode(
   function ($input, $output)
   {
     // do something
   }
);

$ap...
use SymfonyComponentsConsoleApplication;

$application = new Application();
$application->addCommand(new WeatherCommand())...
use SymfonyComponentsConsoleCommandCommand;
use SymfonyComponentsConsoleInputInputInterface;
use SymfonyComponentsConsoleO...
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
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')
      ->setDescr...
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 InputArgume...
The Symfony Components – Fabien Potencier
protected function execute(InputInterface $input,
OutputInterface $output)
{
  $city = $input->getArgument('place');
  $un...
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');
  $un...
Console

    Interact with the user



The Symfony Components – Fabien Potencier
protected function interact($input, $output)
{
  $city = $this->dialog->ask(
     $output,
     '<comment>Which city?</com...
./life weather --no-interaction




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

formatter
  formatSection()
  formatBlock()

... your own



      ...
class WeatherHelper extends Helper
{
  public function __construct()
  {
    Output::setStyle('weather_hot', array('bg' =>...
$output->writeln(sprintf(
  " %s, low: %s, high: %s",
  $attrs['text'],
  $this->weather->formatTemperature(
    $attrs['l...
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 StringI...
$stream = fopen('php://memory', 'a', false);
$output = new StreamOutput($stream);

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

re...
$application = new Application();

// for testing
$application->setCatchExceptions(false);
$application->setAutoExit(false...
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->applicati...
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 – Fabi...
Routing is a two-way process
   Matching incoming requests (URLs)
           Generating URLs


           The Symfony Comp...
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 =...
$route = new Route(
   '/:year/:month/:day/:slug',
   array('to' => function ($params) { var_export
($params); }),
   arra...
Routing

    Matching URLs



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingMatcherUrlMatcher;

$matcher = new UrlMatcher($routes);

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

$...
array (
  'to' =>
  Closure::__set_state(array(
  )),
  'year' => '2010',
  'month' => '03',
  'day' => '10',
  'slug' => ...
$params = $matcher->match('/yyyy/03/10/confoo');
if (false === $params)
{
  throw new Exception('No route matches.');
}

$...
Routing

    Generating URLs



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingGeneratorUrlGenerator;

$generator = new UrlGenerator($routes);

echo $generator->generate('ho...
$params =    array(
   'year'    => 2010,
   'month'   => 10,
   'day'     => 10,
   'slug'    => 'another-one'
);

echo $...
$params =    array(
   'year'    => 'yyyy',
   'month'   => 10,
   'day'     => 10,
);

echo $generator->generate('blog_po...
use SymfonyComponentsRoutingGeneratorUrlGenerator;

$generator = new UrlGenerator($routes);

echo $generator->generate('ho...
$generator = new   UrlGenerator($routes, array(
  'base_url' =>    '/myapp',
  'host'      =>   'www.example.com',
  'is_s...
The context
        makes the routing
decoupled from the rest of the world

                      base_url
               ...
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
  defau...
use SymfonyComponentsRoutingLoaderYamlFileLoader;

$loader = new YamlFileLoader();

$routes = $loader->load('routes.yml');...
<?xml version="1.0" encoding="UTF-8" ?>

<routes xmlns="http://www.symfony-project.org/schema/routing"
    xmlns:xsi="http...
use SymfonyComponentsRoutingLoaderXmlFileLoader;

$loader = new XmlFileLoader();

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

...
<?xml version="1.0" encoding="UTF-8" ?>

<routes>
  <route id="home" pattern="/">
    <default key="controller">home</defa...
home:
  pattern: /
  defaults: { controller: home, action: index }

import:
  - { resource: blog.yml, prefix: /blog }
  - ...
$yamlLoader = new YamlFileLoader();
$xmlLoader = new XmlFileLoader();

$routes = new RouteCollection();
$route = new Route...
/blog/2010/03/10/confoo
 prefix                                      pattern




         The Symfony Components – Fabien P...
Routing

    Make it simple & fast



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingRouter;

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




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

  return $routes;
};

$context = array(
   'base_url'...
$router = new Router($loader, $options, $context);

if (false === $params = $router->match('/'))
{
  throw new Exception('...
class ProjectUrlMatcher extends SymfonyComponentsRouting
MatcherUrlMatcher
{
  // ...

    public function match($url)
   ...
class ProjectUrlGenerator extends SymfonyComponentsRoutingGeneratorUrlGenerator
{
  // ...

  public function generate($na...
use SymfonyComponentsRoutingFileResource;

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

  $routes-...
Routing

    Make it really fast



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingMatcherDumper
ApacheMatcherDumper;

$dumper = new ApacheMatcherDumper($routes);

echo $dumper-...
RewriteCond %{PATH_INFO} ^/$
RewriteRule .* index.php
[QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo
]




              ...
$options = array(
   'cache_dir'     => '/tmp/routing',
   'debug'         => true,
   'matcher_class' => 'SymfonyComponen...
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(),...
use SymfonyComponentsOutputEscaperEscaper;

$title = 'Foo <br />';

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




...
use SymfonyComponentsOutputEscaperEscaper;

$article = array(
   'title' => 'Foo <br />',
   'author' => array(
     'name...
class Article
{
  protected $title;
  protected $author;

    public $full_title;    public property

    public function ...
class Author
{
  protected $name;

    public function __construct($name) { $this->name = $name; }
    public function get...
use SymfonyComponentsOutputEscaperEscaper;

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

$a...
explicitly ask
                                                              for raw data


echo $article->getHtmlContent(...
Request Handler




The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;

$request = new Request();
$request->getPathInfo();
$request->getPreferredLang...
use SymfonyComponentsRequestHandlerRequest;

$request = new   Request(array(
  'request' =>   $_POST,
  'query'   =>   $_G...
use SymfonyComponentsRequestHandlerResponse;

$response = new Response('Hello World', 200,
  array('Content-Type' => 'text...
Request Handler

    Framework to build Frameworks



The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;
use SymfonyComponentsRequestHandlerResponse;
use SymfonyComponentsRequestHandl...
use SymfonyComponentsEventDispatcherEventDispatcher;
use SymfonyComponentsEventDispatcherEvent;

$dispatcher = new EventDi...
Request Handler

    A small Framework



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

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

    publi...
public function loadController(Event $event)
{
  $request = $event['request'];

    $routes = new RouteCollection();
    f...
$framework = new Framework(array(
  '/' => function ($request)
  {
    $content = 'Hello '.
      $request->getParameter('...
Questions?




The Symfony Components – Fabien Potencier
Sensio S.A.
        92-98, boulevard Victor Hugo
            92 115 Clichy Cedex
                  FRANCE
             Tél...
Upcoming SlideShare
Loading in...5
×

Symfony Components

15,755

Published on

Published in: Technology
2 Comments
32 Likes
Statistics
Notes
No Downloads
Views
Total Views
15,755
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
408
Comments
2
Likes
32
Embeds 0
No embeds

No notes for slide

Transcript of "Symfony Components"

  1. 1. The Symfony Components – Fabien Potencier
  2. 2. 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
  3. 3. Standalone components for PHP 5.3 No dependency between them Used extensively in Symfony 2, the framework The Symfony Components – Fabien Potencier
  4. 4. Low-level libraries needed by most websites The Symfony Components – Fabien Potencier
  5. 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. 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. 7. Download / Installation The Symfony Components – Fabien Potencier
  8. 8. git clone git://github.com/symfony/symfony.git Main repository The Symfony Components – Fabien Potencier
  9. 9. svn checkout http://svn.symfony-project.org/branches/2.0/ Git Mirror Synchronized every 15 minutes The Symfony Components – Fabien Potencier
  10. 10. 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
  11. 11. app/ .../ Symfony/ Components/ Foundation/ Framework/ The Symfony Components – Fabien Potencier
  12. 12. Autoloading Classes The Symfony Components – Fabien Potencier
  13. 13. Before PHP 5.3 PEAR naming convention The Symfony Components – Fabien Potencier
  14. 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. 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. 16. As of PHP 5.3 PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  17. 17. SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php The Symfony Components – Fabien Potencier
  18. 18. SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php Vendor name The Symfony Components – Fabien Potencier
  19. 19. 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
  20. 20. use SymfonyFoundationUniversalClassLoader; The Symfony Components – Fabien Potencier
  21. 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. 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. 23. $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); PEAR style The Symfony Components – Fabien Potencier
  24. 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. 25. Console The Symfony Components – Fabien Potencier
  26. 26. Console The Symfony Components – Fabien Potencier
  27. 27. Automate things code generators deployment The Symfony Components – Fabien Potencier
  28. 28. Long running tasks deployment get « things » from the Internet The Symfony Components – Fabien Potencier
  29. 29. Batches cleanup a database from time to time migrate a DB to a new schema The Symfony Components – Fabien Potencier
  30. 30. These tasks should never be run from a browser The Symfony Components – Fabien Potencier
  31. 31. But PHP is a web language, right? The Symfony Components – Fabien Potencier
  32. 32. So, why not use the right tool for the job? … like Perl or Python? The Symfony Components – Fabien Potencier
  33. 33. Don’t want to use/learn another language Want to share code The Symfony Components – Fabien Potencier
  34. 34. PHP natively supports the CLI environment The Symfony Components – Fabien Potencier
  35. 35. <?php // ... The Symfony Components – Fabien Potencier
  36. 36. #!/usr/bin/env php <?php // ... $ ./foo … The Symfony Components – Fabien Potencier
  37. 37. $ ./foobar Fabien $name = $argv[1]; echo 'Hello '.$name; The Symfony Components – Fabien Potencier
  38. 38. … but the complexity lies in the details The Symfony Components – Fabien Potencier
  39. 39. option / arguments handling exit codes shell output colorization tests error messages … The Symfony Components – Fabien Potencier
  40. 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. 41. don’t reinvent the wheel… use a “framework” The Symfony Components – Fabien Potencier
  42. 42. Console The Symfony Components – Fabien Potencier
  43. 43. Let’s create a CLI tool to get the weather anywhere in the world The Symfony Components – Fabien Potencier
  44. 44. The Symfony Components – Fabien Potencier
  45. 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. 46. use SymfonyComponentsConsoleApplication; $application = new Application(); $application->run(); The Symfony Components – Fabien Potencier
  47. 47. $command = new Command('weather'); $command->setCode( function ($input, $output) { // do something } ); $application->addCommand($command); The Symfony Components – Fabien Potencier
  48. 48. use SymfonyComponentsConsoleApplication; $application = new Application(); $application->addCommand(new WeatherCommand()); $application->run(); The Symfony Components – Fabien Potencier
  49. 49. 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
  50. 50. Console The Output The Symfony Components – Fabien Potencier
  51. 51. $output->writeln($weather->getTitle()); The Symfony Components – Fabien Potencier
  52. 52. $output->writeln( sprintf('<info>%s</info>', $weather->getTitle()) ); $output->writeln("<comment>Conditions</comment>"); The Symfony Components – Fabien Potencier
  53. 53. The Symfony Components – Fabien Potencier
  54. 54. The Symfony Components – Fabien Potencier
  55. 55. Console Getting help The Symfony Components – Fabien Potencier
  56. 56. The Symfony Components – Fabien Potencier
  57. 57. $application = new Application('Life Tool', '0.1'); The Symfony Components – Fabien Potencier
  58. 58. 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
  59. 59. The Symfony Components – Fabien Potencier
  60. 60. The Symfony Components – Fabien Potencier
  61. 61. $ ./life weather $ ./life weath $ ./life w The Symfony Components – Fabien Potencier
  62. 62. Console The Input The Symfony Components – Fabien Potencier
  63. 63. 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
  64. 64. The Symfony Components – Fabien Potencier
  65. 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. 66. Console Error codes / Exit status The Symfony Components – Fabien Potencier
  67. 67. The Symfony Components – Fabien Potencier
  68. 68. The Symfony Components – Fabien Potencier
  69. 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. 70. Console Interact with the user The Symfony Components – Fabien Potencier
  71. 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. 72. ./life weather --no-interaction The Symfony Components – Fabien Potencier
  73. 73. dialog ask() askConfirmation() askAndValidate() formatter formatSection() formatBlock() ... your own The Symfony Components – Fabien Potencier
  74. 74. 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
  75. 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. 76. The Symfony Components – Fabien Potencier
  77. 77. Console Testing The Symfony Components – Fabien Potencier
  78. 78. $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
  79. 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. 80. $application = new Application(); // for testing $application->setCatchExceptions(false); $application->setAutoExit(false); The Symfony Components – Fabien Potencier
  81. 81. echo $application->asXml(); The Symfony Components – Fabien Potencier
  82. 82. $command = new WeatherCommand(); echo $command->asXml(); The Symfony Components – Fabien Potencier
  83. 83. Create a PHAR archive out of your CLI tool for distribution The Symfony Components – Fabien Potencier
  84. 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. 85. git clone http://github.com/fabpot/confoo2010 The Symfony Components – Fabien Potencier
  86. 86. Routing Pretty and Smart URLs The Symfony Components – Fabien Potencier
  87. 87. http://example.com/article.php?id=44 http://example.com/article/confoo-2010 The Symfony Components – Fabien Potencier
  88. 88. Routing is a two-way process Matching incoming requests (URLs) Generating URLs The Symfony Components – Fabien Potencier
  89. 89. The architecture is difficult to get right The Symfony Components – Fabien Potencier
  90. 90. Symfony one is built with performance in mind The Symfony Components – Fabien Potencier
  91. 91. Routing Describing your routes The Symfony Components – Fabien Potencier
  92. 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. 93. $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
  94. 94. Routing Matching URLs The Symfony Components – Fabien Potencier
  95. 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. 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. 97. array ( 'to' => Closure::__set_state(array( )), 'year' => '2010', 'month' => '03', 'day' => '10', 'slug' => 'confoo', '_route' => 'blog_post', ) The Symfony Components – Fabien Potencier
  98. 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. 99. Routing Generating URLs The Symfony Components – Fabien Potencier
  100. 100. use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator = new UrlGenerator($routes); echo $generator->generate('home', array()); The Symfony Components – Fabien Potencier
  101. 101. $params = array( 'year' => 2010, 'month' => 10, 'day' => 10, 'slug' => 'another-one' ); echo $generator->generate('blog_post', $params); The Symfony Components – Fabien Potencier
  102. 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. 103. use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator = new UrlGenerator($routes); echo $generator->generate('home', array('foo' => 'bar')); /?foo=bar The Symfony Components – Fabien Potencier
  104. 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. 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. 106. Routing Describing your routes with XML or YAML The Symfony Components – Fabien Potencier
  107. 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. 108. use SymfonyComponentsRoutingLoaderYamlFileLoader; $loader = new YamlFileLoader(); $routes = $loader->load('routes.yml'); The Symfony Components – Fabien Potencier
  109. 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. 110. use SymfonyComponentsRoutingLoaderXmlFileLoader; $loader = new XmlFileLoader(); $routes = $loader->load('routes.xml'); The Symfony Components – Fabien Potencier
  111. 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. 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. 113. $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
  114. 114. /blog/2010/03/10/confoo prefix pattern The Symfony Components – Fabien Potencier
  115. 115. Routing Make it simple & fast The Symfony Components – Fabien Potencier
  116. 116. use SymfonyComponentsRoutingRouter; $router = new Router($loader, $options, $context); The Symfony Components – Fabien Potencier
  117. 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. 118. $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
  119. 119. 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
  120. 120. 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
  121. 121. use SymfonyComponentsRoutingFileResource; $loader = function () { $routes = new RouteCollection(); // ... $routes->addResource(new FileResource(__FILE__)); return $routes; }; The Symfony Components – Fabien Potencier
  122. 122. Routing Make it really fast The Symfony Components – Fabien Potencier
  123. 123. use SymfonyComponentsRoutingMatcherDumper ApacheMatcherDumper; $dumper = new ApacheMatcherDumper($routes); echo $dumper->dump(); The Symfony Components – Fabien Potencier
  124. 124. RewriteCond %{PATH_INFO} ^/$ RewriteRule .* index.php [QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo ] The Symfony Components – Fabien Potencier
  125. 125. $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, 'matcher_class' => 'SymfonyComponents RoutingMatcherApacheUrlMatcher', ); The Symfony Components – Fabien Potencier
  126. 126. Output Escaper The Symfony Components – Fabien Potencier
  127. 127. Provides XSS protection for your PHP templates The Symfony Components – Fabien Potencier
  128. 128. Wraps template variables Works for strings arrays objects properties methods __call(), __get(), … Iterators, Coutables, … … Works for deep method calls The Symfony Components – Fabien Potencier
  129. 129. use SymfonyComponentsOutputEscaperEscaper; $title = 'Foo <br />'; echo Escaper::escape('htmlspecialchars', $title); The Symfony Components – Fabien Potencier
  130. 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. 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. 132. class Author { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } The Symfony Components – Fabien Potencier
  133. 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. 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. 135. Request Handler The Symfony Components – Fabien Potencier
  136. 136. use SymfonyComponentsRequestHandlerRequest; $request = new Request(); $request->getPathInfo(); $request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest(); The Symfony Components – Fabien Potencier
  137. 137. use SymfonyComponentsRequestHandlerRequest; $request = new Request(array( 'request' => $_POST, 'query' => $_GET, 'path' => array(), 'server' => $_SERVER, )); The Symfony Components – Fabien Potencier
  138. 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. 139. Request Handler Framework to build Frameworks The Symfony Components – Fabien Potencier
  140. 140. use SymfonyComponentsRequestHandlerRequest; use SymfonyComponentsRequestHandlerResponse; use SymfonyComponentsRequestHandlerRequestHandler; $handler = new RequestHandler($dispatcher); $request = new Request(); $response = $handler->handle($request); $response->send(); The Symfony Components – Fabien Potencier
  141. 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. 142. Request Handler A small Framework The Symfony Components – Fabien Potencier
  143. 143. $framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  144. 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. 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. 146. $framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  147. 147. Questions? The Symfony Components – Fabien Potencier
  148. 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
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×