Вы находитесь на странице: 1из 148

The Symfony Components – Fabien Potencier

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

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

No dependency between them

Used extensively in Symfony 2, the framework

The Symfony Components – Fabien Potencier


Low-level libraries
needed by most websites

The Symfony Components – Fabien Potencier


Event Dispatcher Stable

Output Escaper Stable


Extracted from symfony 1
YAML Stable

Routing Beta

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

Templating Stable

The Symfony Components – Fabien Potencier


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

The Symfony Components – Fabien Potencier


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

Main repository

The Symfony Components – Fabien Potencier


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

Git Mirror
Synchronized
every 15 minutes

The Symfony Components – Fabien Potencier


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

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

Nightly build

The Symfony Components – Fabien Potencier


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

The Symfony Components – Fabien Potencier


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

The Symfony Components – Fabien Potencier


PEAR_Log > PEAR/Log.php
Zend_Log > Zend/Log.php
Swift_Mime_Message > Swift/Mime/Message.php
Doctrine_Pager_Range > Doctrine/Pager/Range.php
Twig_Node_For > Twig/Node/For.php

Vendor name

The Symfony Components – Fabien Potencier


As of PHP 5.3
PHP 5.3 technical
interoperability standards
The Symfony Components – Fabien Potencier
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 property

public function __construct($title, Author $author)


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

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


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

The Symfony Components – Fabien Potencier


use 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


explicitly ask
for raw data

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

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

The Symfony Components – Fabien Potencier


Request Handler

The Symfony Components – Fabien Potencier


use 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/

The Symfony Components – Fabien Potencier

Вам также может понравиться