symfony components

148

Upload: fabien-potencier

Post on 06-May-2015

15.702 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Symfony Components

The Symfony Components – Fabien Potencier

Page 2: Symfony Components

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/

Page 3: Symfony Components

The Symfony Components – Fabien Potencier

Standalone components for PHP 5.3

No dependency between them

Used extensively in Symfony 2, the framework

Page 4: Symfony Components

The Symfony Components – Fabien Potencier

Low-level libraries needed by most websites

Page 5: Symfony Components

The Symfony Components – Fabien Potencier

Event Dispatcher Output Escaper YAML Routing Console Dependency Injection Container Request Handler Templating

Extracted from symfony 1

Written from scratch for Symfony 2

Stable

Stable

Stable

Beta

Stable

Stable

Stable

Stable

Page 6: Symfony Components

The Symfony Components – Fabien Potencier

YAML Event Dispatcher Templating Dependency Injection Container Console Routing Output Escaper Request Handler

PHP Quebec 2009

ConFoo 2010

Page 7: Symfony Components

The Symfony Components – Fabien Potencier

Download / Installation

Page 8: Symfony Components

The Symfony Components – Fabien Potencier

git clone git://github.com/symfony/symfony.git

Main repository

Page 9: Symfony Components

The Symfony Components – Fabien Potencier

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

Git Mirror Synchronized

every 15 minutes

Page 10: Symfony Components

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

Page 11: Symfony Components

The Symfony Components – Fabien Potencier

app/

.../

Symfony/

Components/

Foundation/

Framework/

Page 12: Symfony Components

The Symfony Components – Fabien Potencier

Autoloading Classes

Page 13: Symfony Components

The Symfony Components – Fabien Potencier

Before PHP 5.3 PEAR naming convention

Page 14: Symfony Components

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

Page 15: Symfony Components

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

Page 16: Symfony Components

The Symfony Components – Fabien Potencier

As of PHP 5.3 PHP 5.3 technical

interoperability standards

Page 17: Symfony Components

The Symfony Components – Fabien Potencier

Symfony\Foundation\Kernel > Symfony/Foundation/Kernel.php

Doctrine\DBAL\Driver > Doctrine/DBAL/Driver.php pdepend\reflection\ReflectionSession > pdepend/reflection/ReflectionSession.php

Page 18: Symfony Components

The Symfony Components – Fabien Potencier

Symfony\Foundation\Kernel > Symfony/Foundation/Kernel.php

Doctrine\DBAL\Driver > Doctrine/DBAL/Driver.php pdepend\reflection\ReflectionSession > pdepend/reflection/ReflectionSession.php

Vendor name

Page 19: Symfony Components

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

Page 20: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Foundation\UniversalClassLoader;

Page 21: Symfony Components

The Symfony Components – Fabien Potencier

require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use Symfony\Foundation\UniversalClassLoader;

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

// use any Symfony class

Page 22: Symfony Components

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

Page 23: Symfony Components

The Symfony Components – Fabien Potencier

$loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', ));

PEAR style

Page 24: Symfony Components

The Symfony Components – Fabien Potencier

require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use Symfony\Foundation\UniversalClassLoader;

$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

Page 25: Symfony Components

The Symfony Components – Fabien Potencier

Console

Page 26: Symfony Components

The Symfony Components – Fabien Potencier

Console

Page 27: Symfony Components

The Symfony Components – Fabien Potencier

Automate things code generators

deployment

Page 28: Symfony Components

The Symfony Components – Fabien Potencier

Long running tasks deployment

get « things » from the Internet

Page 29: Symfony Components

The Symfony Components – Fabien Potencier

Batches cleanup a database from time to time

migrate a DB to a new schema

Page 30: Symfony Components

The Symfony Components – Fabien Potencier

These tasks should never be run from a browser

Page 31: Symfony Components

The Symfony Components – Fabien Potencier

But PHP is a web language, right?

Page 32: Symfony Components

The Symfony Components – Fabien Potencier

So, why not use the right tool for the job?

… like Perl or Python?

Page 33: Symfony Components

The Symfony Components – Fabien Potencier

Don’t want to use/learn another language Want to share code

Page 34: Symfony Components

The Symfony Components – Fabien Potencier

PHP natively supports the CLI environment

Page 35: Symfony Components

The Symfony Components – Fabien Potencier

<?php

// ...

Page 36: Symfony Components

The Symfony Components – Fabien Potencier

#!/usr/bin/env php <?php

// ...

$ ./foo …

Page 37: Symfony Components

The Symfony Components – Fabien Potencier

$ ./foobar Fabien

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

Page 38: Symfony Components

The Symfony Components – Fabien Potencier

… but the complexity lies in the details

Page 39: Symfony Components

The Symfony Components – Fabien Potencier

option / arguments handling exit codes

shell output colorization

tests error messages

Page 40: Symfony Components

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 )

Page 41: Symfony Components

The Symfony Components – Fabien Potencier

don’t reinvent the wheel… use a “framework”

Page 42: Symfony Components

The Symfony Components – Fabien Potencier

Console

Page 43: Symfony Components

The Symfony Components – Fabien Potencier

Let’s create a CLI tool to get the weather

anywhere in the world

Page 44: Symfony Components

The Symfony Components – Fabien Potencier

Page 45: Symfony Components

The Symfony Components – Fabien Potencier

use Life\YahooWeather;

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

$attrs = $weather->getCurrentConditions();

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

$attrs = $weather->getForecast();

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

Page 46: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Console\Application;

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

Page 47: Symfony Components

The Symfony Components – Fabien Potencier

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

$application->addCommand($command);

Page 48: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Console\Application;

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

Page 49: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Console\Command\Command; use Symfony\Components\Console\Input\InputInterface; use Symfony\Components\Console\Output\OutputInterface;

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

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

Page 50: Symfony Components

The Symfony Components – Fabien Potencier

Console

The Output

Page 51: Symfony Components

The Symfony Components – Fabien Potencier

$output->writeln($weather->getTitle());

Page 52: Symfony Components

The Symfony Components – Fabien Potencier

$output->writeln( sprintf('<info>%s</info>', $weather->getTitle()) );

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

Page 53: Symfony Components

The Symfony Components – Fabien Potencier

Page 54: Symfony Components

The Symfony Components – Fabien Potencier

Page 55: Symfony Components

The Symfony Components – Fabien Potencier

Console

Getting help

Page 56: Symfony Components

The Symfony Components – Fabien Potencier

Page 57: Symfony Components

The Symfony Components – Fabien Potencier

$application = new Application('Life Tool', '0.1');

Page 58: Symfony Components

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 ); }

Page 59: Symfony Components

The Symfony Components – Fabien Potencier

Page 60: Symfony Components

The Symfony Components – Fabien Potencier

Page 61: Symfony Components

The Symfony Components – Fabien Potencier

$ ./life weather $ ./life weath $ ./life w

Page 62: Symfony Components

The Symfony Components – Fabien Potencier

Console

The Input

Page 63: Symfony Components

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);

Page 64: Symfony Components

The Symfony Components – Fabien Potencier

Page 65: Symfony Components

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>"); }

Page 66: Symfony Components

The Symfony Components – Fabien Potencier

Console

Error codes / Exit status

Page 67: Symfony Components

The Symfony Components – Fabien Potencier

Page 68: Symfony Components

The Symfony Components – Fabien Potencier

Page 69: Symfony Components

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; }

Page 70: Symfony Components

The Symfony Components – Fabien Potencier

Console

Interact with the user

Page 71: Symfony Components

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); }

Page 72: Symfony Components

The Symfony Components – Fabien Potencier

./life weather --no-interaction

Page 73: Symfony Components

The Symfony Components – Fabien Potencier

dialog ask() askConfirmation() askAndValidate()

formatter formatSection() formatBlock()

... your own

Page 74: Symfony Components

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'; } }

Page 75: Symfony Components

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')) ));

Page 76: Symfony Components

The Symfony Components – Fabien Potencier

Page 77: Symfony Components

The Symfony Components – Fabien Potencier

Console

Testing

Page 78: Symfony Components

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);

Page 79: Symfony Components

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());

Page 80: Symfony Components

The Symfony Components – Fabien Potencier

$application = new Application();

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

Page 81: Symfony Components

The Symfony Components – Fabien Potencier

echo $application->asXml();

Page 82: Symfony Components

The Symfony Components – Fabien Potencier

$command = new WeatherCommand(); echo $command->asXml();

Page 83: Symfony Components

The Symfony Components – Fabien Potencier

Create a PHAR archive out of your CLI tool

for distribution

Page 84: Symfony Components

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);

Page 85: Symfony Components

The Symfony Components – Fabien Potencier

git clone http://github.com/fabpot/confoo2010

Page 86: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Pretty and Smart URLs

Page 87: Symfony Components

The Symfony Components – Fabien Potencier

http://example.com/article.php?id=44

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

Page 88: Symfony Components

The Symfony Components – Fabien Potencier

Routing is a two-way process Matching incoming requests (URLs)

Generating URLs

Page 89: Symfony Components

The Symfony Components – Fabien Potencier

The architecture is difficult to get right

Page 90: Symfony Components

The Symfony Components – Fabien Potencier

Symfony one is built with performance in mind

Page 91: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Describing your routes

Page 92: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\RouteCollection; use Symfony\Components\Routing\Route;

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

Page 93: Symfony Components

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);

Page 94: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Matching URLs

Page 95: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Matcher\UrlMatcher;

$matcher = new UrlMatcher($routes);

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

$params['to']();

Page 96: Symfony Components

The Symfony Components – Fabien Potencier

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

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

Page 97: Symfony Components

The Symfony Components – Fabien Potencier

array ( 'to' => Closure::__set_state(array( )), 'year' => '2010', 'month' => '03', 'day' => '10', 'slug' => 'confoo', '_route' => 'blog_post', )

Page 98: Symfony Components

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.'

Page 99: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Generating URLs

Page 100: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Generator\UrlGenerator;

$generator = new UrlGenerator($routes);

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

Page 101: Symfony Components

The Symfony Components – Fabien Potencier

$params = array( 'year' => 2010, 'month' => 10, 'day' => 10, 'slug' => 'another-one' );

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

Page 102: Symfony Components

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).'

Page 103: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Generator\UrlGenerator;

$generator = new UrlGenerator($routes);

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

/?foo=bar

Page 104: Symfony Components

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/

Page 105: Symfony Components

The Symfony Components – Fabien Potencier

The context makes the routing

decoupled from the rest of the world

base_url host

is_secure

method

Page 106: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Describing your routes with XML or YAML

Page 107: Symfony Components

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}

Page 108: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Loader\YamlFileLoader;

$loader = new YamlFileLoader();

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

Page 109: Symfony Components

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>

Page 110: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Loader\XmlFileLoader;

$loader = new XmlFileLoader();

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

Page 111: Symfony Components

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>

Page 112: Symfony Components

The Symfony Components – Fabien Potencier

home: pattern: / defaults: { controller: home, action: index }

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

Page 113: Symfony Components

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');

Page 114: Symfony Components

The Symfony Components – Fabien Potencier

/blog/2010/03/10/confoo

prefix pattern

Page 115: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Make it simple & fast

Page 116: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Router;

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

Page 117: Symfony Components

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, );

Page 118: Symfony Components

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());

Page 119: Symfony Components

The Symfony Components – Fabien Potencier

class ProjectUrlMatcher extends Symfony\Components\Routing\Matcher\UrlMatcher { // ...

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; } }

Page 120: Symfony Components

The Symfony Components – Fabien Potencier

class ProjectUrlGenerator extends Symfony\Components\Routing\Generator\UrlGenerator { // ...

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, ),)); } }

Page 121: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\FileResource;

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

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

return $routes; };

Page 122: Symfony Components

The Symfony Components – Fabien Potencier

Routing

Make it really fast

Page 123: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\Routing\Matcher\Dumper\ApacheMatcherDumper;

$dumper = new ApacheMatcherDumper($routes);

echo $dumper->dump();

Page 124: Symfony Components

The Symfony Components – Fabien Potencier

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

Page 125: Symfony Components

The Symfony Components – Fabien Potencier

$options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, 'matcher_class' => 'Symfony\Components\Routing\Matcher\ApacheUrlMatcher', );

Page 126: Symfony Components

The Symfony Components – Fabien Potencier

Output Escaper

Page 127: Symfony Components

The Symfony Components – Fabien Potencier

Provides XSS protection for your PHP templates

Page 128: Symfony Components

The Symfony Components – Fabien Potencier

Wraps template variables Works for

strings arrays objects

properties methods __call(), __get(), … Iterators, Coutables, … …

Works for deep method calls

Page 129: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\OutputEscaper\Escaper;

$title = 'Foo <br />';

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

Page 130: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\OutputEscaper\Escaper;

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

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

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

Page 131: Symfony Components

The Symfony Components – Fabien Potencier

class Article { protected $title; protected $author;

public $full_title;

public function __construct($title, Author $author) { $this->title = $title; $this->full_title = $title; $this->author = $author; }

public function getTitle() { return $this->title; } public function getAuthor() { return $this->author; } public function __get($key) { return $this->$key; } public function __call($method, $arguments) { return $this->{'get'.$method}(); } }

public property

public method

public method returning another object

magic __get() magic __call()

Page 132: Symfony Components

The Symfony Components – Fabien Potencier

class Author { protected $name;

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

Page 133: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\OutputEscaper\Escaper;

$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";

Page 134: Symfony Components

The Symfony Components – Fabien Potencier

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

echo $article->getTitle('js');

explicitly ask for raw data

change the default escaping strategy

Page 135: Symfony Components

The Symfony Components – Fabien Potencier

Request Handler

Page 136: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\RequestHandler\Request;

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

Page 137: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\RequestHandler\Request;

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

Page 138: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\RequestHandler\Response;

$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);

Page 139: Symfony Components

The Symfony Components – Fabien Potencier

Request Handler

Framework to build Frameworks

Page 140: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\RequestHandler\Request; use Symfony\Components\RequestHandler\Response; use Symfony\Components\RequestHandler\RequestHandler;

$handler = new RequestHandler($dispatcher);

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

Page 141: Symfony Components

The Symfony Components – Fabien Potencier

use Symfony\Components\EventDispatcher\EventDispatcher; use Symfony\Components\EventDispatcher\Event;

$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; });

Page 142: Symfony Components

The Symfony Components – Fabien Potencier

Request Handler

A small Framework

Page 143: Symfony Components

The Symfony Components – Fabien Potencier

$framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name');

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

Page 144: Symfony Components

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(); } }

Page 145: Symfony Components

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; }

Page 146: Symfony Components

The Symfony Components – Fabien Potencier

$framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name');

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

Page 147: Symfony Components

The Symfony Components – Fabien Potencier

Questions?

Page 148: Symfony Components

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/