Beyond symfony 1.2

     Fabien Potencier
Work on symfony 2
    started 2 years ago
with a brand new code base
symfony 2 goals

   Learn from our mistakes

Take user feedback into account
But then, I realized that
     Starting from scratch is a lot of work!

We loose all the debugging we have already done

 ...
But I learned a lot with this new code

        I used it to test new ideas…
…that were later incorporated into symfony 1
...
symfony 2
•  symfony 2 will be an evolution of symfony 1, not a
   revolution
•  A lot of changes in symfony 1.1 and 1.2 a...
symfony 2
•  Based on the same symfony platform




•  New libraries / sub-frameworks
  –  Dependency injection container
...
Dependency Injection
The world of programming
  is evolving fast… very fast

But the ultimate goal of these
      changes is the same
Build better tools
    to avoid reinventing
         the wheel
Build on existing code / work / librairies
Specialize for y...
Better tools are possible because
we base our work on existing work

  We learn from other projects

    We can adopt thei...
symfony
•  PHP
  –  Mojavi : Controller
  –  Propel : ORM
  –  Doctrine : ORM
•  Ruby
  –  Rails : Helpers, routing
•  Jav...
Read code to learn
This is why Open-Source wins
Open-Source drives

     Creativity
    Innovation
Create a website
•  Assembly code
•  C code
•  Operating system
•  MySQL, Apache
•  PHP
•  …
•  Your code
Create a website
•  You really need a framework nowadays
•  But you want it to be flexible and customizable
•  The framewo...
Reusability

Customization / Extension
     Configuration

Documentation / Support
Dependency Injection
A symfony example
In symfony, you manipulate a User object
  –  To manage the user culture
  –  To authenticate the user
  –  To manage her ...
The User information need to be persisted
        between HTTP requests

 We use the PHP session for the Storage
<?php

class User
{
  protected $storage;

    function __construct()
    {
      $this->storage = new SessionStorage();
 ...
I want to change the session cookie name
<?php

class User
{
  protected $storage;                      Add a global
                                          Conf...
<?php
                                        Configure via
class User                                 User?
{
  protected...
<?php
                                        Configure with
class User                                 an array
{
  prote...
I want to change the session storage engine

                Filesystem
                  MySQL
                  SQLite
 ...
<?php

class User                              Use a global
{                                      context object?
  prote...
The User now depends on the Context
Instead of harcoding
  the Storage dependency
      in the User class

Inject the storage dependency
       in the User ob...
<?php

class User
{
  protected $storage;

    function __construct(StorageInterface $storage)
    {
      $this->storage ...
Use built-in Storage strategies
     Configuration becomes natural
    Wrap third-party classes (Adapter)
    Mock the Sto...
That’s Dependency Injection

      Nothing more
« Dependency Injection is
    where components are given
     their dependencies through
    their constructors, methods,
...
Configurable
 Extensible
 Decoupled
 Reusable
symfony platform
<?php

$dispatcher = new sfEventDispatcher();

$request = new sfWebRequest($dispatcher);
$response = new sfWebResponse($di...
<?php

class Application
{
  function __construct()
  {
    $this->dispatcher = new sfEventDispatcher();
    $this->reques...
Back to square 1
We need a Container
    Describe objects
  and their relationships

     Configure them

     Instantiate them
Dependency Injection
    in symfony 2

 sfServiceContainer
<?php

$container = new sfServiceContainer(array(
  'dispatcher' => new sfServiceDefinition('sfEventDispatcher'),
));

$di...
<?php

$dispatcherDef = new sfServiceDefinition('sfEventDispatcher');

$requestDef = new sfServiceDefinition('sfWebRequest...
$request = $container->getService('request');




           Get the configuration for the request service

 The sfWebRequ...
$request = $container->getService('request');



          is roughly equivalent to

    $dispatcher = new sfEventDispatch...
<?php

$container = new sfServiceContainer(array(
  'dispatcher' => new sfServiceDefinition('sfEventDispatcher’),
  'reque...
<?php

$container = new sfServiceContainer(array(
  'dispatcher' => new sfServiceDefinition('sfEventDispatcher'),
));



<...
<parameter key="core.with_logging">true</parameter>
<parameter key="core.charset">UTF-8</parameter>
<parameter key="respon...
// YML

$loader = new sfServiceLoaderYml(array('/paths/to/config/dir'));

list($definitions, $parameters) = $loader->load(...
// Access parameters

$withLogging = $container['core.with_logging'];



// Access services

$response = $container->respo...
<import resource="core.xml" />

<parameter key="dispatcher.class">sfEventDispatcher</parameter>

<service id="dispatcher" ...
sfServiceContainer replaces several symfony 1.X concepts


  – sfContext

  – sfConfiguration

  – sfConfig

  – factories...
services:
  response:
    class: %response.class%
    global: false



Each time you ask for a response object,
          ...
services:
  user:
    class: %user.class%
    lazy: true



 By default, the services are created on
      startup except ...
Does it scale?


sfServiceContainerApplication
 caches the service definition
Questions?
Sensio S.A.
                     92-98, boulevard Victor Hugo
                         92 115 Clichy Cedex
               ...
Upcoming SlideShare
Loading in...5
×

Beyond symfony 1.2 (Symfony Camp 2008)

59,151

Published on

Published in: Technology, Sports, Career
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
59,151
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
20
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Beyond symfony 1.2 (Symfony Camp 2008)

  1. 1. Beyond symfony 1.2 Fabien Potencier
  2. 2. Work on symfony 2 started 2 years ago with a brand new code base
  3. 3. symfony 2 goals Learn from our mistakes Take user feedback into account
  4. 4. But then, I realized that Starting from scratch is a lot of work! We loose all the debugging we have already done I didn’t want symfony 2 to be the next Perl 6 ;)
  5. 5. But I learned a lot with this new code I used it to test new ideas… …that were later incorporated into symfony 1 Event dispatcher Form framework
  6. 6. symfony 2 •  symfony 2 will be an evolution of symfony 1, not a revolution •  A lot of changes in symfony 1.1 and 1.2 are done to support symfony 2 •  symfony 1.1 decoupling was to support symfony 2 •  There will be a symfony 1.3
  7. 7. symfony 2 •  Based on the same symfony platform •  New libraries / sub-frameworks –  Dependency injection container –  Real template layer –  New controller layer
  8. 8. Dependency Injection
  9. 9. The world of programming is evolving fast… very fast But the ultimate goal of these changes is the same
  10. 10. Build better tools to avoid reinventing the wheel Build on existing code / work / librairies Specialize for your specific needs That’s why Open-Source wins
  11. 11. Better tools are possible because we base our work on existing work We learn from other projects We can adopt their ideas We can make them better This is the process of evolution
  12. 12. symfony •  PHP –  Mojavi : Controller –  Propel : ORM –  Doctrine : ORM •  Ruby –  Rails : Helpers, routing •  Java –  Spring : Dependency injection container •  Python –  Django : request / response paradigm, controller philosophy •  … and much more
  13. 13. Read code to learn
  14. 14. This is why Open-Source wins
  15. 15. Open-Source drives Creativity Innovation
  16. 16. Create a website •  Assembly code •  C code •  Operating system •  MySQL, Apache •  PHP •  … •  Your code
  17. 17. Create a website •  You really need a framework nowadays •  But you want it to be flexible and customizable •  The framework needs to find the sweet spot –  Features / Complexity –  Easyness / Extensibility •  Each version of symfony tries to be closer to this sweet spot •  I hope symfony 2 will be the one •  A framework is all about reusability
  18. 18. Reusability Customization / Extension Configuration Documentation / Support
  19. 19. Dependency Injection
  20. 20. A symfony example
  21. 21. In symfony, you manipulate a User object –  To manage the user culture –  To authenticate the user –  To manage her credentials –  … –  setCulture(), getCulture() –  isAuthenticated() –  addCredential() –  …
  22. 22. The User information need to be persisted between HTTP requests We use the PHP session for the Storage
  23. 23. <?php class User { protected $storage; function __construct() { $this->storage = new SessionStorage(); } } $user = new User();
  24. 24. I want to change the session cookie name
  25. 25. <?php class User { protected $storage; Add a global Configuration? function __construct() { $this->storage = new SessionStorage(); } } sfConfig::set('storage_session_name', 'SESSION_ID'); $user = new User();
  26. 26. <?php Configure via class User User? { protected $storage; function __construct($sessionName) { $this->storage = new SessionStorage($sessionName); } } $user = new User('SESSION_ID');
  27. 27. <?php Configure with class User an array { protected $storage; function __construct($options) { $this->storage = new SessionStorage($options); } } $user = new User( array('session_name' => 'SESSION_ID') );
  28. 28. I want to change the session storage engine Filesystem MySQL SQLite …
  29. 29. <?php class User Use a global { context object? protected $storage; function __construct() { $this->storage = Context::get('session_storage'); } } $user = new User();
  30. 30. The User now depends on the Context
  31. 31. Instead of harcoding the Storage dependency in the User class Inject the storage dependency in the User object
  32. 32. <?php class User { protected $storage; function __construct(StorageInterface $storage) { $this->storage = $storage; } } $storage = new Storage( array('session_name' => 'SESSION_ID') ); $user = new User($storage);
  33. 33. Use built-in Storage strategies Configuration becomes natural Wrap third-party classes (Adapter) Mock the Storage object (for test) Easy without changing the User class
  34. 34. That’s Dependency Injection Nothing more
  35. 35. « Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. » http://www.picocontainer.org/injection.html
  36. 36. Configurable Extensible Decoupled Reusable
  37. 37. symfony platform
  38. 38. <?php $dispatcher = new sfEventDispatcher(); $request = new sfWebRequest($dispatcher); $response = new sfWebResponse($dispatcher); $storage = new sfSessionStorage( array('session_name' => 'symfony') ); $user = new sfUser($dispatcher, $storage); $cache = new sfFileCache( array('dir' => dirname(__FILE__).'/cache') ); $routing = new sfPatternRouting($dispatcher, $cache);
  39. 39. <?php class Application { function __construct() { $this->dispatcher = new sfEventDispatcher(); $this->request = new sfWebRequest($this->dispatcher); $this->response = new sfWebResponse($this->dispatcher); $this->storage = new sfSessionStorage( array('session_name' => 'symfony') ); $this->user = new sfUser($this->disptacher, $this->storage); $this->cache = new sfFileCache( array('dir' => dirname(__FILE__).'/cache') ); $this->routing = new sfPatternRouting($this->disptacher, $this->cache); } } $application = new Application();
  40. 40. Back to square 1
  41. 41. We need a Container Describe objects and their relationships Configure them Instantiate them
  42. 42. Dependency Injection in symfony 2 sfServiceContainer
  43. 43. <?php $container = new sfServiceContainer(array( 'dispatcher' => new sfServiceDefinition('sfEventDispatcher'), )); $dispatcher = $container->getService('dispatcher'); It is a just a Service Locator?
  44. 44. <?php $dispatcherDef = new sfServiceDefinition('sfEventDispatcher'); $requestDef = new sfServiceDefinition('sfWebRequest', array(new sfServiceReference('dispatcher')) ); $container = new sfServiceContainer(array( 'dispatcher' => $dispatcherDef, 'request' => $requestDef, )); $request = $container->getService('request');
  45. 45. $request = $container->getService('request'); Get the configuration for the request service The sfWebRequest constructor must be given a dispatcher service Get the dispatcher object from the container Create a sfWebRequest object by passing the constructor arguments
  46. 46. $request = $container->getService('request'); is roughly equivalent to $dispatcher = new sfEventDispatcher(); $request = new sfWebRequest($dispatcher);
  47. 47. <?php $container = new sfServiceContainer(array( 'dispatcher' => new sfServiceDefinition('sfEventDispatcher’), 'request' => new sfServiceDefinition('sfWebRequest', PHP array(new sfServiceReference('dispatcher')) = ), )); <service id="dispatcher" class="sfEventDispatcher" /> <service id="request" class="sfWebRequest"> <constructor_arg type="service" id="dispatcher" /> XML = </service> dispatcher: class: sfEventDispatcher request: class: sfWebRequest YAML constructor_args: [@dispatcher]
  48. 48. <?php $container = new sfServiceContainer(array( 'dispatcher' => new sfServiceDefinition('sfEventDispatcher'), )); <parameter key="dispatcher.class">sfEventDispatcher</parameter> <service id="dispatcher" class="%dispatcher.class%" /> parameters: dispatcher.class: sfEventDispatcher services: dispatcher: class: %dispatcher.class%
  49. 49. <parameter key="core.with_logging">true</parameter> <parameter key="core.charset">UTF-8</parameter> <parameter key="response.class">sfWebResponse</parameter> <service id="response" class="%response.class%" global="false"> <constructor_arg type="service" id="event_dispatcher" /> <constructor_arg type="collection"> <arg key="logging">%core.with_logging%</arg> <arg key="charset">%core.charset%</arg> </constructor_arg> </service> parameters: core.with_logging: true core.charset: UTF-8 response.class: sfWebResponse services: response: class: %response.class% global: false constructor_args: - @event_dispatcher - [logging: %core.with_logging%, charset: %core.charset%]
  50. 50. // YML $loader = new sfServiceLoaderYml(array('/paths/to/config/dir')); list($definitions, $parameters) = $loader->load('/paths/to/yml'); // XML $loader = new sfServiceLoaderXml(array('/paths/to/config/dir')); list($definitions, $parameters) = $loader->load('/paths/to/xml'); // Create the container $container = new sfServiceContainer($definitions, $parameters);
  51. 51. // Access parameters $withLogging = $container['core.with_logging']; // Access services $response = $container->response;
  52. 52. <import resource="core.xml" /> <parameter key="dispatcher.class">sfEventDispatcher</parameter> <service id="dispatcher" class="%disaptcher.class%" /> <import resource="app_dev.xml" /> imports_1: core.xml parameters: dispatcher.class: sfEventDispatcher services: dispatcher: class: %dispatcher.class% imports_2: app_dev.xml
  53. 53. sfServiceContainer replaces several symfony 1.X concepts – sfContext – sfConfiguration – sfConfig – factories.yml – settings.yml / logging.yml / i18n.yml Into one integrated system
  54. 54. services: response: class: %response.class% global: false Each time you ask for a response object, you get a new one
  55. 55. services: user: class: %user.class% lazy: true By default, the services are created on startup except if lazy is true
  56. 56. Does it scale? sfServiceContainerApplication caches the service definition
  57. 57. Questions?
  58. 58. 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@sensio.com http://www.sensiolabs.com/ http://www.symfony-project.org/
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×