Symfony Components

  • 15,450 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • nice
    Are you sure you want to
    Your message goes here
  • cool
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
15,450
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
404
Comments
2
Likes
32

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. The Symfony Components – Fabien Potencier
  • 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. Standalone components for PHP 5.3 No dependency between them Used extensively in Symfony 2, the framework The Symfony Components – Fabien Potencier
  • 4. Low-level libraries needed by most websites The Symfony Components – Fabien Potencier
  • 5. Event Dispatcher Stable Output Escaper Stable Extracted from symfony 1 YAML Stable Routing Beta Console Stable Dependency Injection Container Stable Written from scratch for Symfony 2 Request Handler Stable Templating Stable The Symfony Components – Fabien Potencier
  • 6. YAML Event Dispatcher PHP Quebec 2009 Templating Dependency Injection Container Console Routing ConFoo 2010 Output Escaper Request Handler The Symfony Components – Fabien Potencier
  • 7. Download / Installation The Symfony Components – Fabien Potencier
  • 8. git clone git://github.com/symfony/symfony.git Main repository The Symfony Components – Fabien Potencier
  • 9. svn checkout http://svn.symfony-project.org/branches/2.0/ Git Mirror Synchronized every 15 minutes The Symfony Components – Fabien Potencier
  • 10. curl -O http://github.com/symfony/symfony/tarball/master 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. app/ .../ Symfony/ Components/ Foundation/ Framework/ The Symfony Components – Fabien Potencier
  • 12. Autoloading Classes The Symfony Components – Fabien Potencier
  • 13. Before PHP 5.3 PEAR naming convention The Symfony Components – Fabien Potencier
  • 14. PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Doctrine_Pager_Range > Doctrine/Pager/Range.php Twig_Node_For > Twig/Node/For.php The Symfony Components – Fabien Potencier
  • 15. PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Doctrine_Pager_Range > Doctrine/Pager/Range.php Twig_Node_For > Twig/Node/For.php Vendor name The Symfony Components – Fabien Potencier
  • 16. As of PHP 5.3 PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  • 17. SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php The Symfony Components – Fabien Potencier
  • 18. SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php Vendor name The Symfony Components – Fabien Potencier
  • 19. PHP 5.3 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. use SymfonyFoundationUniversalClassLoader; The Symfony Components – Fabien Potencier
  • 21. require_once '.../Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespace( 'Symfony', __DIR__.'/src/symfony/src' ); $loader->register(); // use any Symfony class The Symfony Components – Fabien Potencier
  • 22. $loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', 'pdepend' => '/path/to/reflection/source', )); PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  • 23. $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); PEAR style The Symfony Components – Fabien Potencier
  • 24. require_once '.../Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', )); $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); $loader->register(); // use any class The Symfony Components – Fabien Potencier
  • 25. Console The Symfony Components – Fabien Potencier
  • 26. Console The Symfony Components – Fabien Potencier
  • 27. Automate things code generators deployment The Symfony Components – Fabien Potencier
  • 28. Long running tasks deployment get « things » from the Internet The Symfony Components – Fabien Potencier
  • 29. Batches cleanup a database from time to time migrate a DB to a new schema The Symfony Components – Fabien Potencier
  • 30. These tasks should never be run from a browser The Symfony Components – Fabien Potencier
  • 31. But PHP is a web language, right? The Symfony Components – Fabien Potencier
  • 32. So, why not use the right tool for the job? … like Perl or Python? The Symfony Components – Fabien Potencier
  • 33. Don’t want to use/learn another language Want to share code The Symfony Components – Fabien Potencier
  • 34. PHP natively supports the CLI environment The Symfony Components – Fabien Potencier
  • 35. <?php // ... The Symfony Components – Fabien Potencier
  • 36. #!/usr/bin/env php <?php // ... $ ./foo … The Symfony Components – Fabien Potencier
  • 37. $ ./foobar Fabien $name = $argv[1]; echo 'Hello '.$name; The Symfony Components – Fabien Potencier
  • 38. … but the complexity lies in the details The Symfony Components – Fabien Potencier
  • 39. option / arguments handling exit codes shell output colorization tests error messages … The Symfony Components – Fabien Potencier
  • 40. $ ./life foo "foo bar" --foo foobar -b Array ( [0] => ./life [1] => foo [2] => foo bar [3] => --foo [4] => foobar [5] => -b ) The Symfony Components – Fabien Potencier
  • 41. don’t reinvent the wheel… use a “framework” The Symfony Components – Fabien Potencier
  • 42. Console The Symfony Components – Fabien Potencier
  • 43. Let’s create a CLI tool to get the weather anywhere in the world The Symfony Components – Fabien Potencier
  • 44. The Symfony Components – Fabien Potencier
  • 45. use LifeYahooWeather; $weather = new YahooWeather('API_KEY', $argv[1]); echo $weather->getTitle()."n"; $attrs = $weather->getCurrentConditions(); echo "Current conditions:n"; echo sprintf(" %s, %sCn", $attrs['text'], $attrs['temp']); $attrs = $weather->getForecast(); echo sprintf("nForecast for %sn", $attrs['date']); echo sprintf(" %s, low: %s, high: %sn", $attrs['text'], $attrs['low'], $attrs['high']); The Symfony Components – Fabien Potencier
  • 46. use SymfonyComponentsConsoleApplication; $application = new Application(); $application->run(); The Symfony Components – Fabien Potencier
  • 47. $command = new Command('weather'); $command->setCode( function ($input, $output) { // do something } ); $application->addCommand($command); The Symfony Components – Fabien Potencier
  • 48. use SymfonyComponentsConsoleApplication; $application = new Application(); $application->addCommand(new WeatherCommand()); $application->run(); The Symfony Components – Fabien Potencier
  • 49. use SymfonyComponentsConsoleCommandCommand; use SymfonyComponentsConsoleInputInputInterface; 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. Console The Output The Symfony Components – Fabien Potencier
  • 51. $output->writeln($weather->getTitle()); The Symfony Components – Fabien Potencier
  • 52. $output->writeln( sprintf('<info>%s</info>', $weather->getTitle()) ); $output->writeln("<comment>Conditions</comment>"); The Symfony Components – Fabien Potencier
  • 53. The Symfony Components – Fabien Potencier
  • 54. The Symfony Components – Fabien Potencier
  • 55. Console Getting help The Symfony Components – Fabien Potencier
  • 56. The Symfony Components – Fabien Potencier
  • 57. $application = new Application('Life Tool', '0.1'); The Symfony Components – Fabien Potencier
  • 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. The Symfony Components – Fabien Potencier
  • 60. The Symfony Components – Fabien Potencier
  • 61. $ ./life weather $ ./life weath $ ./life w The Symfony Components – Fabien Potencier
  • 62. Console The Input The Symfony Components – Fabien Potencier
  • 63. class WeatherCommand 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. The Symfony Components – Fabien Potencier
  • 65. protected function execute(InputInterface $input, OutputInterface $output) { $city = $input->getArgument('place'); $unit = $input->getOption('unit'); $output->writeln("<comment>Conditions</comment>"); } The Symfony Components – Fabien Potencier
  • 66. Console Error codes / Exit status The Symfony Components – Fabien Potencier
  • 67. The Symfony Components – Fabien Potencier
  • 68. The Symfony Components – Fabien Potencier
  • 69. protected function execute(InputInterface $input, OutputInterface $output) { $city = $input->getArgument('place'); $unit = $input->getOption('unit'); $output->writeln("<comment>Conditions</comment>"); return 120; } The Symfony Components – Fabien Potencier
  • 70. Console Interact with the user The Symfony Components – Fabien Potencier
  • 71. protected function interact($input, $output) { $city = $this->dialog->ask( $output, '<comment>Which city?</comment> (Paris)', 'Paris’ ); $input->setArgument('place', $city); } The Symfony Components – Fabien Potencier
  • 72. ./life weather --no-interaction The Symfony Components – Fabien Potencier
  • 73. dialog ask() askConfirmation() askAndValidate() formatter formatSection() formatBlock() ... your own The Symfony Components – Fabien Potencier
  • 74. class WeatherHelper 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. $output->writeln(sprintf( " %s, low: %s, high: %s", $attrs['text'], $this->weather->formatTemperature( $attrs['low'], $input->getOption('unit')), $this->weather->formatTemperature( $attrs['high'], $input->getOption('unit')) )); The Symfony Components – Fabien Potencier
  • 76. The Symfony Components – Fabien Potencier
  • 77. Console Testing The Symfony Components – Fabien Potencier
  • 78. $input = 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. $stream = fopen('php://memory', 'a', false); $output = new StreamOutput($stream); $application->run($input, $output); rewind($output->getStream()); echo stream_get_contents($output->getStream()); The Symfony Components – Fabien Potencier
  • 80. $application = new Application(); // for testing $application->setCatchExceptions(false); $application->setAutoExit(false); The Symfony Components – Fabien Potencier
  • 81. echo $application->asXml(); The Symfony Components – Fabien Potencier
  • 82. $command = new WeatherCommand(); echo $command->asXml(); The Symfony Components – Fabien Potencier
  • 83. Create a PHAR archive out of your CLI tool for distribution The Symfony Components – Fabien Potencier
  • 84. $pharFile = 'life.phar’; if (file_exists($pharFile)) unlink($pharFile); $phar = new Phar($pharFile, 0, $this->application->getName()); $phar->setSignatureAlgorithm(Phar::SHA1); $phar->startBuffering(); // CLI Component files foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../symfony/src/Symfony/Components/ Console'), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { $phar['Symfony/Components/Console'.str_replace(__DIR__.'/../symfony/src/Symfony/Components/Console', '', $file)] = file_get_contents($file); } // Life stuff foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../Life'), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { $phar['Life'.str_replace(__DIR__.'/../Life', '', $file)] = file_get_contents($file); } // Autoloader $phar['Symfony/Foundation/UniversalClassLoader.php'] = file_get_contents(__DIR__.'/../symfony/src/Symfony/Foundation/ UniversalClassLoader.php'); // Stubs $phar['_cli_stub.php'] = $this->getCliStub(); $phar['_web_stub.php'] = $this->getWebStub(); $phar->setDefaultStub('_cli_stub.php', '_web_stub.php'); $phar->stopBuffering(); $phar->compressFiles(Phar::GZ); unset($phar); The Symfony Components – Fabien Potencier
  • 85. git clone http://github.com/fabpot/confoo2010 The Symfony Components – Fabien Potencier
  • 86. Routing Pretty and Smart URLs The Symfony Components – Fabien Potencier
  • 87. http://example.com/article.php?id=44 http://example.com/article/confoo-2010 The Symfony Components – Fabien Potencier
  • 88. Routing is a two-way process Matching incoming requests (URLs) Generating URLs The Symfony Components – Fabien Potencier
  • 89. The architecture is difficult to get right The Symfony Components – Fabien Potencier
  • 90. Symfony one is built with performance in mind The Symfony Components – Fabien Potencier
  • 91. Routing Describing your routes The Symfony Components – Fabien Potencier
  • 92. use SymfonyComponentsRoutingRouteCollection; use SymfonyComponentsRoutingRoute; $routes = new RouteCollection(); $route = new Route( '/', array('to' => function () { echo "Home!"; }) ); $routes->addRoute('home', $route); The Symfony Components – Fabien Potencier
  • 93. $route = 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. Routing Matching URLs The Symfony Components – Fabien Potencier
  • 95. use SymfonyComponentsRoutingMatcherUrlMatcher; $matcher = new UrlMatcher($routes); if (false === $params = $matcher->match('/')) { throw new Exception('No route matches.'); } $params['to'](); The Symfony Components – Fabien Potencier
  • 96. $params = $matcher->match('/2010/03/10/confoo'); if (false === $params) { throw new Exception('No route matches.'); } $params['to']($params); The Symfony Components – Fabien Potencier
  • 97. array ( 'to' => Closure::__set_state(array( )), 'year' => '2010', 'month' => '03', 'day' => '10', 'slug' => 'confoo', '_route' => 'blog_post', ) The Symfony Components – Fabien Potencier
  • 98. $params = $matcher->match('/yyyy/03/10/confoo'); if (false === $params) { throw new Exception('No route matches.'); } $params['to']($params); Uncaught exception 'Exception' with message 'No route matches.' The Symfony Components – Fabien Potencier
  • 99. Routing Generating URLs The Symfony Components – Fabien Potencier
  • 100. use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator = new UrlGenerator($routes); echo $generator->generate('home', array()); The Symfony Components – Fabien Potencier
  • 101. $params = array( 'year' => 2010, 'month' => 10, 'day' => 10, 'slug' => 'another-one' ); echo $generator->generate('blog_post', $params); The Symfony Components – Fabien Potencier
  • 102. $params = array( 'year' => 'yyyy', 'month' => 10, 'day' => 10, ); echo $generator->generate('blog_post', $params); Uncaught exception 'InvalidArgumentException' with message 'The "blog_post" route has some missing mandatory parameters (:slug).' The Symfony Components – Fabien Potencier
  • 103. use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator = new UrlGenerator($routes); echo $generator->generate('home', array('foo' => 'bar')); /?foo=bar The Symfony Components – Fabien Potencier
  • 104. $generator = new UrlGenerator($routes, array( 'base_url' => '/myapp', 'host' => 'www.example.com', 'is_secure' => false, )); echo $generator->generate('home', array(), true); http://www.example.com/myapp/ The Symfony Components – Fabien Potencier
  • 105. The context makes the routing decoupled from the rest of the world base_url host is_secure method The Symfony Components – Fabien Potencier
  • 106. Routing Describing your routes with XML or YAML The Symfony Components – Fabien Potencier
  • 107. home: pattern: / defaults: { controller: home, action: index } blog_post: pattern: /:year/:month/:day/:slug defaults: controller: blog action: show requirements: year: d{4} The Symfony Components – Fabien Potencier
  • 108. use SymfonyComponentsRoutingLoaderYamlFileLoader; $loader = new YamlFileLoader(); $routes = $loader->load('routes.yml'); The Symfony Components – Fabien Potencier
  • 109. <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://www.symfony-project.org/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.symfony-project.org/schema/routing http://www.symfony-project.org/schema/routing/routing-1.0.xsd"> <route id="blog_post" pattern="/:year/:month/:day/:slug"> <default key="controller">blog</default> <default key="action">show</default> <requirement key="year">d{4}</requirement> </route> <route id="home" pattern="/"> <default key="controller">home</default> <default key="action">index</default> </route> </routes> The Symfony Components – Fabien Potencier
  • 110. use SymfonyComponentsRoutingLoaderXmlFileLoader; $loader = new XmlFileLoader(); $routes = $loader->load('routes.xml'); The Symfony Components – Fabien Potencier
  • 111. <?xml version="1.0" encoding="UTF-8" ?> <routes> <route id="home" pattern="/"> <default key="controller">home</default> <default key="action">index</default> </route> <import resource="blog.yml" prefix="/blog" /> <import resource="forum.xml" prefix="/forum" /> </routes> The Symfony Components – Fabien Potencier
  • 112. home: pattern: / defaults: { controller: home, action: index } import: - { resource: blog.yml, prefix: /blog } - { resource: forum.xml, prefix: /forum } The Symfony Components – Fabien Potencier
  • 113. $yamlLoader = 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. /blog/2010/03/10/confoo prefix pattern The Symfony Components – Fabien Potencier
  • 115. Routing Make it simple & fast The Symfony Components – Fabien Potencier
  • 116. use SymfonyComponentsRoutingRouter; $router = new Router($loader, $options, $context); The Symfony Components – Fabien Potencier
  • 117. $loader = function () { $routes = new RouteCollection(); // ... return $routes; }; $context = array( 'base_url' => '/myapp', 'host' => 'www.example.com', 'is_secure' => false, ); $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, ); The Symfony Components – Fabien Potencier
  • 118. $router = 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. 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. 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. use SymfonyComponentsRoutingFileResource; $loader = function () { $routes = new RouteCollection(); // ... $routes->addResource(new FileResource(__FILE__)); return $routes; }; The Symfony Components – Fabien Potencier
  • 122. Routing Make it really fast The Symfony Components – Fabien Potencier
  • 123. use SymfonyComponentsRoutingMatcherDumper ApacheMatcherDumper; $dumper = new ApacheMatcherDumper($routes); echo $dumper->dump(); The Symfony Components – Fabien Potencier
  • 124. RewriteCond %{PATH_INFO} ^/$ RewriteRule .* index.php [QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo ] The Symfony Components – Fabien Potencier
  • 125. $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, 'matcher_class' => 'SymfonyComponents RoutingMatcherApacheUrlMatcher', ); The Symfony Components – Fabien Potencier
  • 126. Output Escaper The Symfony Components – Fabien Potencier
  • 127. Provides XSS protection for your PHP templates The Symfony Components – Fabien Potencier
  • 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. use SymfonyComponentsOutputEscaperEscaper; $title = 'Foo <br />'; echo Escaper::escape('htmlspecialchars', $title); The Symfony Components – Fabien Potencier
  • 130. use SymfonyComponentsOutputEscaperEscaper; $article = array( 'title' => 'Foo <br />', 'author' => array( 'name' => 'Fabien <br/>', ) ); $article = Escaper::escape('htmlspecialchars', $article); echo $article['title']."n"; echo $article['author']['name']."n"; The Symfony Components – Fabien Potencier
  • 131. class Article { protected $title; protected $author; public $full_title; public property public function __construct($title, Author $author) { $this->title = $title; $this->full_title = $title; $this->author = $author; } public method public function getTitle() { return $this->title; } public function getAuthor() { return $this->author; } public method returning public function __get($key) { return $this->$key; } another object public function __call($method, $arguments) { magic __get() return $this->{'get'.$method}(); magic __call() } } The Symfony Components – Fabien Potencier
  • 132. class Author { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } The Symfony Components – Fabien Potencier
  • 133. use SymfonyComponentsOutputEscaperEscaper; $article = new Article( 'foo <br />', new Author('Fabien <br />') ); $article = Escaper::escape('htmlspecialchars', $article); echo $article->getTitle()."n"; echo $article->getAuthor()->getName()."n"; echo $article->full_title."n"; echo $article->title."n"; echo $article->title()."n"; The Symfony Components – Fabien Potencier
  • 134. explicitly ask for raw data echo $article->getHtmlContent('raw'); echo $article->getTitle('js'); change the default escaping strategy The Symfony Components – Fabien Potencier
  • 135. Request Handler The Symfony Components – Fabien Potencier
  • 136. use SymfonyComponentsRequestHandlerRequest; $request = new Request(); $request->getPathInfo(); $request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest(); The Symfony Components – Fabien Potencier
  • 137. use SymfonyComponentsRequestHandlerRequest; $request = new Request(array( 'request' => $_POST, 'query' => $_GET, 'path' => array(), 'server' => $_SERVER, )); The Symfony Components – Fabien Potencier
  • 138. use SymfonyComponentsRequestHandlerResponse; $response = new Response('Hello World', 200, array('Content-Type' => 'text/plain')); $response->send(); $response->setHeader('Content-Type', 'text/plain'); $response->setCookie('foo', 'bar'); $response->setContent('Hello World'); $response->setStatusCode(200); The Symfony Components – Fabien Potencier
  • 139. Request Handler Framework to build Frameworks The Symfony Components – Fabien Potencier
  • 140. use SymfonyComponentsRequestHandlerRequest; use SymfonyComponentsRequestHandlerResponse; use SymfonyComponentsRequestHandlerRequestHandler; $handler = new RequestHandler($dispatcher); $request = new Request(); $response = $handler->handle($request); $response->send(); The Symfony Components – Fabien Potencier
  • 141. use SymfonyComponentsEventDispatcherEventDispatcher; use SymfonyComponentsEventDispatcherEvent; $dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function ($request) { return new Response('Hello!'); }, array($event['request']) )); return true; }); The Symfony Components – Fabien Potencier
  • 142. Request Handler A small Framework The Symfony Components – Fabien Potencier
  • 143. $framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  • 144. class Framework { protected $map; public function __construct($map) { $this->map = $map; } public function run() { $dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', array($this, 'loadController')); $handler = new RequestHandler($dispatcher); $response = $handler->handle(new Request()); $response->send(); } } The Symfony Components – Fabien Potencier
  • 145. public function loadController(Event $event) { $request = $event['request']; $routes = new RouteCollection(); foreach ($this->map as $pattern => $to) { $route = new Route($pattern, array('to' => $to)); $routes->addRoute(str_replace('/', '_', $pattern), $route); } $matcher = new UrlMatcher($routes, array( 'base_url' => $request->getBaseUrl(), 'method' => $request->getMethod(), 'host' => $request->getHost(), 'is_secure' => $request->isSecure(), )); $parameters = $matcher->match($request->getPathInfo()); if (false === $parameters) { return false; } $request->setPathParameters($parameters); $event->setReturnValue(array($parameters['to'], array($request))); return true; } The Symfony Components – Fabien Potencier
  • 146. $framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  • 147. Questions? The Symfony Components – Fabien Potencier
  • 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