Symfony2 revealed

47,415 views
45,027 views

Published on

Symfony2 revealed

Published in: Technology
0 Comments
54 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
47,415
On SlideShare
0
From Embeds
0
Number of Embeds
16,849
Actions
Shares
0
Downloads
699
Comments
0
Likes
54
Embeds 0
No embeds

No notes for slide

Symfony2 revealed

  1. Fabien Potencier
  2. A bit of history
  3. symfony 1.0 – January 2007 •  Started as a glue between existing Open-Source libraries: – Mojavi (heavily modified), Propel, Prado i18n, … •  Borrowed concepts from other languages and frameworks: – Routing, CLI, functional tests, YAML, Rails helpers… •  Added new concepts to the mix – Web Debug Toolbar, admin generator, configuration cascade, …
  4. symfony 1.2 – November 2008 •  Based on decoupled but cohesive components –  Forms, Routing, Cache, YAML, ORMs, … •  Controller still based on Mojavi –  View, Filter Chain, …
  5. symfony 1.4 – November 2009 •  Added some polish on existing features •  Removed the support for deprecated features •  Current LTS release, maintained until late 2012
  6. Symfony Components YAML Dependency Injection Container Event Dispatcher Templating Routing Console Output Escaper Request Handler …
  7. What is Symfony 2?
  8. Symfony 2 is the next version of the symfony framework… except Symfony now takes a S instead of a s
  9. Talk about Symfony 2 or symfony 1
  10. To make it clear: Symfony 1 does not make any sense
  11. symfony 2 does not make more sense
  12. Symfony 2
  13. Same philosophy, just better
  14. MVC
  15. hmmm, now that I think about it…
  16. …it’s now probably more a Fabien’s style framework than anything else
  17. Highly configurable Highly extensible Same Symfony Components Same great developer tools Full-featured
  18. Ok, but why a major version then?
  19. Symfony 2 has a brand new low-level architecture
  20. PHP 5.3
  21. A Quick Tour
  22. <?php require_once __DIR__.'/../blog/BlogKernel.php'; $kernel = new BlogKernel('prod', false); $kernel->run();
  23. <?php Everything is namespaced namespace ApplicationHelloBundleController; use SymfonyFrameworkWebBundleController; class HelloController extends Controller { public function indexAction($name) Variables come from the routing { return $this->render('HelloBundle:Hello:index', array('name' => $name)); } } Template name Variables to pass to the template
  24. Layout <?php $view->extend('HelloBundle::layout') ?> Hello <?php echo $name ?>!
  25. <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <?php $view->slots->output('_content') ?> </body> </html> Helpers are objects
  26. hello: pattern: /hello/:name defaults: _bundle: HelloBundle _controller: Hello _action: index
  27. hello: pattern: /hello/:name defaults: _bundle: HelloBundle _controller: Hello _action: index namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  28. hello: pattern: /hello/:name defaults: _bundle: HelloBundle _controller: Hello _action: index namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  29. hello: pattern: /hello/:name defaults: _bundle: HelloBundle _controller: Hello _action: index namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  30. hello: pattern: /hello/:name defaults: _bundle: HelloBundle _controller: Hello _action: index namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  31. hello: pattern: /hello/:name defaults: _bundle: HelloBundle _controller: Hello _action: index namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($name) { // ... } }
  32. hello: pattern: /hello/:year/:month/:slug defaults: _bundle: HelloBundle _controller: Hello _action: index namespace ApplicationHelloBundleController; class HelloController extends Controller { public function indexAction($slug, $year) { // ... } }
  33. Extremely Configurable
  34. Dependency Injection Container
  35. Replaces a lot of symfony 1 “things” sfConfig All config handlers sfProjectConfiguration / sfApplicationConfiguration sfContext (No Singleton anymore) The configuration cache system … and some more
  36. in one easy-to-master unified and cohesive package
  37. Thanks to the DIC, Configuration has never been so easy and so flexible
  38. Name your configuration files the way you want
  39. Store them where you want
  40. Use PHP, XML, YAML, or INI
  41. $configuration = new BuilderConfiguration(); $configuration->addResource(new FileResource(__FILE__)); $configuration ->mergeExtension('web.user', array('default_culture' => 'fr', 'session' => array('name' => 'SYMFONY', 'type' => 'Native', 'lifetime' => 3600))) ->mergeExtension('doctrine.dbal', array('dbname' => 'sfweb', 'username' => 'root')) ->mergeExtension('web.templating', array('escaping' => 'htmlspecialchars', 'assets_version' => 'SomeVersionScheme')) ->mergeExtension('swift.mailer', array('transport' => 'gmail', 'username' => 'fabien.potencier', 'password' => 'xxxxxx')) PHP   ;
  42. web.user: default_culture: fr session: { name: SYMFONY, type: Native, lifetime: 3600 } web.templating: escaping: htmlspecialchars assets_version: SomeVersionScheme doctrine.dbal: { dbname: sfweb, username: root, password: null } swift.mailer: transport: gmail username: fabien.potencier password: xxxxxxxx YAML  
  43. <web:user default_culture="fr"> <web:session name="SYMFONY" type="Native" lifetime="3600" /> </web:user> <web:templating escaping="htmlspecialchars" assets_version="SomeVersionScheme" /> <doctrine:dbal dbname="sfweb" username="root" password="" /> <swift:mailer transport="gmail" username="fabien.potencier" password="xxxxxxxx" /> XML  
  44. $configuration->mergeExtension('swift.mailer', array( 'transport' => 'gmail', 'username' => 'fabien.potencier', 'password' => 'xxxxxx', )); PHP  
  45. swift.mailer: transport: gmail username: fabien.potencier password: xxxxxxxx YAML  
  46. <swift:mailer transport="gmail" username="fabien.potencier" password="xxxxxxxx" /> XML  
  47. <?xml version="1.0" ?> <container xmlns="http://www.symfony-project.org/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance » xmlns:doctrine="http://www.symfony-project.org/schema/dic/doctrine" xmlns:zend="http://www.symfony-project.org/schema/dic/zend" xmlns:swift="http://www.symfony-project.org/schema/dic/swiftmailer" > XML  
  48. <?xml version="1.0" ?> <container xmlns="http://www.symfony-project.org/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance » xmlns:doctrine="http://www.symfony-project.org/schema/dic/doctrine" xmlns:zend="http://www.symfony-project.org/schema/dic/zend" xmlns:swift="http://www.symfony-project.org/schema/dic/swiftmailer" xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd http://www.symfony-project.org/schema/dic/doctrine http://www.symfony-project.org/schema/dic/doctrine/doctrine-1.0.xsd http://www.symfony-project.org/schema/dic/zend http:// www.symfony-project.org/schema/dic/zend/zend-1.0.xsd http://www.symfony-project.org/schema/dic/swiftmailer http://www.symfony-project.org/schema/dic/swiftmailer/swiftmailer-1.0.xsd »> XML  
  49. Inherit them as much as you want
  50. Mix and match configuration files written in any format useful when using third-party plugins
  51. <imports> <import resource="parent.xml" /> <import resource="config.yml" /> Mix and match formats <import resource="parameters.ini" /> </imports> <zend:logger priority="debug" path="%kernel.logs_dir%/%kernel.environment%.log" /> <web:debug exception="%kernel.debug%" toolbar="%kernel.debug%" ide="textmate" />
  52. You choose the format you want Pros Cons XML validation verbose (not that much) IDE completion & help YAML concise needs the YAML component simple to read no validation easy to change no IDE auto-completion PHP flexible no validation more expressive
  53. Store sensitive settings outside of your project
  54. <doctrine:dbal dbname="sfweb" username="root" password="SuperSecretPasswordThatAnyoneCanSee" />
  55. in a .htaccess or httpd.conf file SetEnv SYMFONY__DOCTRINE__DBAL__PASSWORD "foobar" %doctrine.dbal.password%
  56. Semantic Configuration
  57. <swift:mailer transport="gmail" username="fabien.potencier" password="xxxxxxxx" /> XML  
  58. <swift:mailer transport="smtp" encryption="ssl" auth_mode="login" host="smtp.gmail.com" username="fabien.potencier" password="xxxxxxxx" /> XML  
  59. <parameters> <parameter key="swiftmailer.class">Swift_Mailer</parameter> <parameter key="swiftmailer.transport.smtp.class">Swift_Transport_EsmtpTransport</parameter> <parameter key="swiftmailer.transport.smtp.host">smtp.gmail.com</parameter> <parameter key="swiftmailer.transport.smtp.port">25</parameter> <parameter key="swiftmailer.transport.smtp.encryption">ssl</parameter> <parameter key="swiftmailer.transport.smtp.username">fabien.potencier</parameter> <parameter key="swiftmailer.transport.smtp.password">xxxxxx</parameter> <parameter key="swiftmailer.transport.smtp.auth_mode">login</parameter> <parameter key="swiftmailer.init_file">swift_init.php</parameter> </parameters> <services> <service id="swiftmailer.mailer" class="%swiftmailer.class%"> <argument type="service" id="swiftmailer.transport" /> <file>%swiftmailer.init_file%</file> </service> <service id="swiftmailer.transport.smtp" class="%swiftmailer.transport.smtp.class%"> <argument type="service" id="swiftmailer.transport.buffer" /> <argument type="collection"> <argument type="service" id="swiftmailer.transport.authhandler" /> </argument> <argument type="service" id="swiftmailer.transport.eventdispatcher" /> <call method="setHost"><argument>%swiftmailer.transport.smtp.host%</argument></call> <call method="setPort"><argument>%swiftmailer.transport.smtp.port%</argument></call> <call method="setEncryption"><argument>%swiftmailer.transport.smtp.encryption%</argument></call> <call method="setUsername"><argument>%swiftmailer.transport.smtp.username%</argument></call> <call method="setPassword"><argument>%swiftmailer.transport.smtp.password%</argument></call> <call method="setAuthMode"><argument>%swiftmailer.transport.smtp.auth_mode%</argument></call> </service> <service id="swiftmailer.transport.buffer" class="Swift_Transport_StreamBuffer"> <argument type="service" id="swiftmailer.transport.replacementfactory" /> </service> <service id="swiftmailer.transport.authhandler" class="Swift_Transport_Esmtp_AuthHandler"> <argument type="collection"> <argument type="service"><service class="Swift_Transport_Esmtp_Auth_CramMd5Authenticator" /></argument> <argument type="service"><service class="Swift_Transport_Esmtp_Auth_LoginAuthenticator" /></argument> <argument type="service"><service class="Swift_Transport_Esmtp_Auth_PlainAuthenticator" /></argument> </argument> XML   </service> <service id="swiftmailer.transport.eventdispatcher" class="Swift_Events_SimpleEventDispatcher" /> <service id="swiftmailer.transport.replacementfactory" class="Swift_StreamFilters_StringReplacementFilterFactory" /> <service id="swiftmailer.transport" alias="swiftmailer.transport.smtp" /> </services>
  60. Creating DIC extensions is insanely simple
  61. Very Fast thanks to a Smart Caching mechanism it always knows when to flush the cache
  62. /** * Gets the 'swiftmailer.mailer' service. * * This service is shared. * This method always returns the same instance of the service. * * @return Swift_Mailer A Swift_Mailer instance. PHPDoc for auto-completion */ protected function getSwiftmailer_MailerService() { if (isset($this->shared['swiftmailer.mailer'])) return $this->shared['swiftmailer.mailer']; As fast as it could be $instance = new Swift_Mailer($this->getSwiftmailer_Transport_SmtpService()); return $this->shared['swiftmailer.mailer'] = $instance; }
  63. The DIC can manage ANY PHP object (POPO)
  64. Plugins…
  65. or Bundles
  66. Plugins are first-class citizens They are called Bundles
  67. Everything is a bundle Core features Third-party code Application code
  68. app/ src/ web/
  69. app/ AppKernel.php cache/ config/ console logs/
  70. src/ autoload.php Application/ Bundle/ vendor/ doctrine/ swiftmailer/ symfony/ zend/
  71. web/ index.php index_dev.php
  72. .../ SomeBundle/ Bundle.php Controller/ Model/ Resources/ config/ views/
  73. public function registerBundleDirs() { return array( 'Application' => __DIR__.'/../src/Application', 'Bundle' => __DIR__.'/../src/Bundle', 'SymfonyFramework' => __DIR__.'/../src/vendor/ symfony/src/Symfony/Framework', ); }
  74. $this->render('SomeBundle:Hello:index', $params)
  75. hello: pattern: /hello/:name defaults: { _bundle: SomeBundle, ... }
  76. SomeBundle can be any of ApplicationSomeBundle BundleSomeBundle SymfonyFrameworkSomeBundle
  77. Less concepts… but more powerful ones
  78. symfony 1 View Layer templates layouts slots components partials component slots
  79. Symfony 2 View Layer templates slots
  80. A layout is just another template with _content as a special slot A partial is just a template you embed in another one A component is just another action embedded in a template
  81. <?php $view->output('BlogBundle:Post:list', array('posts' => $posts)) ?>
  82. <?php $view->actions->output('BlogBundle:Post:list', array ('limit' => 2)) ?>
  83. <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <?php $view->slots->output('_content') ?> </body> </html>
  84. Big and Small Improvements
  85. multiple level of layouts
  86. partials can be decorated!
  87. Better Logs
  88. INFO: Matched route "blog_home" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'index', '_route' => 'blog_home',)) INFO: Using controller "BundleBlogBundleController PostController::indexAction" INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ ORDER BY s0_.published_at DESC LIMIT 10 (array ())
  89. INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) INFO: Using controller "BundleBlogBundleController PostController::showAction » INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught SymfonyComponentsRequestHandlerException NotFoundHttpException exception) INFO: Using controller "SymfonyFrameworkWebBundleController ExceptionController::exceptionAction"
  90. <zend:logger priority="debug" />
  91. DEBUG: Notifying (until) event "core.request" to listener "(SymfonyFrameworkWebBundleListenerRequestParser, resolve)" INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) DEBUG: Notifying (until) event "core.load_controller" to listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" INFO: Using controller "BundleBlogBundleControllerPostController::showAction" DEBUG: Listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" processed the event "core.load_controller" INFO: Trying to get post "3456" from database INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) DEBUG: Notifying (until) event "core.exception" to listener "(SymfonyFrameworkWebBundleListenerExceptionHandler, handle)" ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught SymfonyComponents RequestHandlerExceptionNotFoundHttpException exception) DEBUG: Notifying (until) event "core.request" to listener "(SymfonyFrameworkWebBundleListenerRequestParser, resolve)" DEBUG: Notifying (until) event "core.load_controller" to listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" INFO: Using controller "SymfonyFrameworkWebBundleControllerExceptionController::exceptionAction" DEBUG: Listener "(SymfonyFrameworkWebBundleListenerControllerLoader, resolve)" processed the event "core.load_controller" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleListenerResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugDataCollector DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugWebDebugToolbar, handle)" DEBUG: Listener "(SymfonyFrameworkWebBundleListenerExceptionHandler, handle)" processed the event "core.exception" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleListenerResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugDataCollector DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(SymfonyFrameworkWebBundleDebugWebDebugToolbar, handle)"
  92. Even Better Exception Error Pages
  93. An Event Better Web Debug Toolbar
  94. Everything you need is at the bottom of the screen
  95. Web Designer “friendly”
  96. app/ views/ BlogBundle/ Post/ index.php AdminGeneratorBundle/ DefaultTheme/ list.php edit.php ...
  97. “Mount” Routing Configuration
  98. blog: resource: BlogBundle/Resources/config/routing.yml forum: resource: ForumBundle/Resources/config/routing.yml prefix: /forum
  99. Symfony 2 is a lazy framework
  100. Smart Autoloading
  101. require_once __DIR__.'/vendor/symfony/src/Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/vendor/symfony/src', 'Application' => __DIR__, 'Bundle' => __DIR__, 'Doctrine' => __DIR__.'/vendor/doctrine/lib', )); $loader->registerPrefixes(array( 'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes', 'Zend_' => __DIR__.'/vendor/zend/library', )); $loader->register(); // for Zend Framework & SwiftMailer set_include_path(__DIR__.'/vendor/zend/library'.PATH_SEPARATOR.__DIR__.'/vendor/ swiftmailer/lib'.PATH_SEPARATOR.get_include_path());
  102. lazy-loading of services
  103. lazy-loading of listeners
  104. lazy-loading of helpers
  105. <?php echo $view->router->generate('blog_post', array('id' => $post->getId())) ?>
  106. Symfony 2 is a “cachy” framework
  107. blog/ cache/ prod/ blogProjectContainer.php blogUrlGenerator.php blogUrlMatcher.php classes.php
  108. class blogUrlMatcher extends SymfonyComponentsRoutingMatcherUrlMatcher { public function __construct(array $context = array(), array $defaults = array()) { $this->context = $context; $this->defaults = $defaults; } public function match($url) { $url = $this->normalizeUrl($url); if (0 === strpos($url, '/webblog') && preg_match('#^/webblog/(? P<id>[^/.]+?)$#x', $url, $matches)) return array_merge($this->mergeDefaults($matches, array ( '_bundle' => 'WebBundle', '_controller' => 'Redirect', '_action' => 'redirect', 'route' => 'blog_post',)), array('_route' => 'old_blog_post_redirect'));
  109. You can use Apache for Routing matching
  110. A Very Fast Dev. Env.
  111. blog/ cache/ dev/ blogProjectContainer.meta blogProjectContainer.php blogUrlGenerator.meta blogUrlGenerator.php blogUrlMatcher.meta blogUrlMatcher.php classes.meta classes.php prod/ blogProjectContainer.php blogUrlGenerator.php blogUrlMatcher.php classes.php
  112. Symfony 2
  113. Easy to learn Easy to use Extensible at will
  114. Easy to learn Easy to use
  115. Extensible at will
  116. But Symfony 2 should be slow, right?
  117. Fast as hell
  118. Benchmark on a simple application
  119. 2x faster than Solar 1.0.0
  120. 2.5x faster than symfony 1.4.2
  121. 3x faster than Zend Framework 1.10
  122. 4x faster than Lithium
  123. 6x faster than CakePHP 1.2.6
  124. 60x faster than Flow3
  125. …and Symfony 2.0 uses half the memory needed by both symfony 1 and ZF
  126. We have barely scratched the surface of all the goodness of Symfony 2.0
  127. Controller except for the nice default pages Autoloading Cache via ZF - DI extension coming soon CLI commands still missing Configuration Database via Doctrine DBAL Debug except Timer and extended WDT Escaper Event Dispatcher Form / Validation / Widget can use the 1.4 version as is Admin Generator Helpers I18n / L10n can use the 1.4 version as is Logger via ZF Mailer except commands Bundles except installing Doctrine Plugin just the DBAL part Propel Plugin Request / Response Routing no REST support, no Object support Storage / User Test View
  128. Final Release Target Date Late 2010
  129. If you want the bleeding edge of news, follow me on Twitter @fabpot on Github github.com/fabpot
  130. http://symfony-reloaded.org/
  131. Questions? My slides will be available on http://slideshare.com/fabpot
  132. 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/

×