Upload
fabien-potencier
View
15.683
Download
1
Embed Size (px)
Citation preview
The Symfony Components – Fabien Potencier
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 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
The Symfony Components – Fabien Potencier
YAML Event Dispatcher Templating Dependency Injection Container Console Routing Output Escaper Request Handler
PHP Quebec 2009
ConFoo 2010
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
Symfony\Foundation\Kernel > Symfony/Foundation/Kernel.php
Doctrine\DBAL\Driver > Doctrine/DBAL/Driver.php pdepend\reflection\ReflectionSession > pdepend/reflection/ReflectionSession.php
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
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 Symfony\Foundation\UniversalClassLoader;
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
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 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
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 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']);
The Symfony Components – Fabien Potencier
use Symfony\Components\Console\Application;
$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 Symfony\Components\Console\Application;
$application = new Application(); $application->addCommand(new WeatherCommand()); $application->run();
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 } }
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 Symfony\Components\Routing\RouteCollection; use Symfony\Components\Routing\Route;
$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 Symfony\Components\Routing\Matcher\UrlMatcher;
$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 Symfony\Components\Routing\Generator\UrlGenerator;
$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 Symfony\Components\Routing\Generator\UrlGenerator;
$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 Symfony\Components\Routing\Loader\YamlFileLoader;
$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 Symfony\Components\Routing\Loader\XmlFileLoader;
$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 Symfony\Components\Routing\Router;
$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 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; } }
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, ),)); } }
The Symfony Components – Fabien Potencier
use Symfony\Components\Routing\FileResource;
$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 Symfony\Components\Routing\Matcher\Dumper\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' => 'Symfony\Components\Routing\Matcher\ApacheUrlMatcher', );
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 Symfony\Components\OutputEscaper\Escaper;
$title = 'Foo <br />';
echo Escaper::escape('htmlspecialchars', $title);
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";
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()
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 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";
The Symfony Components – Fabien Potencier
echo $article->getHtmlContent('raw');
echo $article->getTitle('js');
explicitly ask for raw data
change the default escaping strategy
The Symfony Components – Fabien Potencier
Request Handler
The Symfony Components – Fabien Potencier
use Symfony\Components\RequestHandler\Request;
$request = new Request(); $request->getPathInfo(); $request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest();
The Symfony Components – Fabien Potencier
use Symfony\Components\RequestHandler\Request;
$request = new Request(array( 'request' => $_POST, 'query' => $_GET, 'path' => array(), 'server' => $_SERVER, ));
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);
The Symfony Components – Fabien Potencier
Request Handler
Framework to build Frameworks
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();
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; });
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/