Symfony Tunisia 2015 - Cycle de vie du container d’Injection de Dépendance

Symfony Tunisia 2015 - Cycle de vie du container d’Injection de Dépendance

Nous revoyons le cycle de vie du contanier d'injection dépendance dans le détail.

34ade09dd3d11004ca8ee4174fd3d6a2?s=128

Sarah KHALIL

April 17, 2015
Tweet

Transcript

  1. Fonctionnement interne du container d'injection de dépendance de Symfony Sarah

    Khalil 17 avril 2015 Symfony Tunisie 2015 Cycle de vie du container d’Injection de Dépendance
  2. Sarah Khalil Responsable @saro0h SensioLabs Qui suis-je ?

  3. Je ne parlerai pas de configuration, ni de bonnes pratiques,

    ni de la manipulation de services avec Symfony. Un tout petit peu
  4. Parcourir la construction du container. Identifier les points d’extension. Du

    code, beaucoup de code.
  5. None
  6. None
  7. Qu’est-ce que l’injection de dépendance ?

  8. Principes de Programmation Orientée Objet SOLID

  9. SOLID : Single responsability principle Une classe ne doit avoir

    qu’une seule responsabilité.
  10. SOLID : Open/Closed principle Une classe doit être ouverte à

    l’extension, fermée à la modification.
  11. SOLID : Liskov substitution principle Remplacer une dépendance sans rien

    affecter. Lors de la spécialisation, conserver les même prototypes de méthodes.
  12. Plusieurs interfaces spécifiques plutôt qu'une seule interface générale. SOLID :

    Interface segregation principle
  13. Ne pas instancier les dépendances. Abstraction (Interface/Abstract) Implémentation SOLID :

    Dependency Injection principle Changer facilement d’implémentation Dépendance = Objet
  14. Dependency Injection Component

  15. Quelques chiffres • 13 189 / 253 901LOC • 145

    fichiers • 121 classes
  16. Un peu de vocabulaire • Service = Instance de classe,

    un objet. • Container d’injection dépendance Objet PHP en charge de l’instanciation des services.
  17. Types d’injection • Constructeur • Setter • Propriété Le plus

    utilisé
  18. Types d’injection : Constructeur (1/3) class  NewsletterManager   {  

           private  $mailer;          public  function  __construct(MailerInterface  $mailer)          {                  $this-­‐>mailer  =  $mailer;          }   }   <container>          <services>                  <service  id="my_mailer"  class="Mailer"></service>                  <service  id="newsletter_manager"  class="NewsletterManager">                          <argument  type="service"  id="my_mailer"/>                  </service>          </services>   </container> Dépendance Déclaration de services Dépendance obligatoire
  19. Types d’injection : Setter (2/3) class  NewsletterManager   {  

           private  $mailer;          public  function  setMailer(MailerInterface  $mailer)          {                  $this-­‐>mailer  =  $mailer;          }   }   <?xml  version="1.0"  encoding="UTF-­‐8"  ?>   <container>          <services>                  <service  id="my_mailer"  class="Mailer"></service>                  <service  id="newsletter_manager"  class="NewsletterManager">                          <call  method="setMailer">                                  <argument  type="service"  id="my_mailer"  />                          </call>                  </service>          </services>   </container> Déclaration de services Dépendance Dépendance optionnelle
  20. Types d’injection : Propriété (3/3) class  NewsletterManager   {  

           public  $mailer;   }   <?xml  version="1.0"  encoding="UTF-­‐8"  ?>   <container>          <services>                  <service  id="my_mailer"  class="Mailer"></service>                  <service  id="newsletter_manager"  class="NewsletterManager">                          <property  name="mailer"  type="service"  id="my_mailer"  />                  </service>          </services>   </container> Déclaration de services Dépendance Non conseillé
  21. Types d’injection Types + - Constructeur • Typage • Certain

    d’avoir la dépendance • Toujours passer la dépendance • Sauf si $dep=null Setter • Dépendance optionnelle • Typage • Vérifier que la dépendance est bien là. Propriété - • Aucun moyen de s’assurer que la dépendance est bien injectée. • Typage impossible.
  22. None
  23. Ce que nous avons l’habitude faire <?xml  version="1.0"  encoding="UTF-­‐8"  ?>

      <container>          <services>                  <service  id="my_mailer"  class="AppBundle\Mail\Mailer"></service>          </services>   </container> use  Symfony\Bundle\FrameworkBundle\Controller\Controller;   class  DefaultController  extends  Controller   {          public  function  mailAction()          {                  $this-­‐>get('my_mailer')-­‐>sendEmail();          }   } étape 1: déclaration de service étape 2 : faire appel au service
  24. Comment ça marche ?

  25. Suivez la carte, je vous emmène ! Front Controller Kernel

    ContainerBuilder Container Vous êtes ici
  26. 3 Grandes étapes 1. Construction du container builder 2. Compilation

    du container builder 3. Récupérer le container
  27. C’est parti ! Front Controller Kernel ContainerBuilder Container Vous êtes

    ici
  28. None
  29. Front Controller web/app.php ou web/app_dev.php use  Symfony\Component\ClassLoader\ApcClassLoader;   use  Symfony\Component\HttpFoundation\Request;

      $loader  =  require_once  __DIR__.'/../app/bootstrap.php.cache';   require_once  __DIR__.'/../app/AppKernel.php';   $kernel  =  new  AppKernel('prod',  false);   $kernel-­‐>loadClassCache();   $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   $kernel-­‐>terminate($request,  $response); Build Container
  30. Vers le kernel Front Controller Kernel ContainerBuilder Container Vous êtes

    ici AppKernel
  31. app/AppKernel • Etend Symfony\Component\HttpKernel\Kernel •registerBundles() •registerContainerConfiguration(LoaderInterface $loader)

  32. Front controller web/app.php ou web/app_dev.php use  Symfony\Component\ClassLoader\ApcClassLoader;   use  Symfony\Component\HttpFoundation\Request;

      $loader  =  require_once  __DIR__.'/../app/bootstrap.php.cache';   require_once  __DIR__.'/../app/AppKernel.php';   $kernel  =  new  AppKernel('prod',  false);   $kernel-­‐>loadClassCache();   $request  =  Request::createFromGlobals();   $response  =  $kernel-­‐>handle($request);   $response-­‐>send();   $kernel-­‐>terminate($request,  $response);
  33. Kernel Symfony\Component\HttpKernel\Kernel Build Container public  function  handle(Request  $request  […])  

    {          if  (false  ===  $this-­‐>booted)  {                   $this-­‐>boot();          }          return  […]   }
  34. Kernel Symfony\Component\HttpKernel\Kernel public  function  boot()   {      if

     (true  ===  $this-­‐>booted)  {              return;      }      […]       $this-­‐>initializeBundles();      $this-­‐>initializeContainer();      foreach  ($this-­‐>getBundles()  as  $bundle)  {              $bundle-­‐>setContainer($this-­‐>container);              $bundle-­‐>boot();      }      $this-­‐>booted  =  true;   } Appelle registerBundles() d’AppKernel pour récupérer tous les bundles à initialiser
  35. Construction du Container Builder 1ère étape

  36. Kernel Symfony\Component\HttpKernel\Kernel Build Container public  function  boot()   {  

       if  (true  ===  $this-­‐>booted)  {              return;      }      […]      $this-­‐>initializeBundles();       $this-­‐>initializeContainer();      foreach  ($this-­‐>getBundles()  as  $bundle)  {              $bundle-­‐>setContainer($this-­‐>container);              $bundle-­‐>boot();      }      $this-­‐>booted  =  true;   }
  37. Kernel Symfony\Component\HttpKernel\Kernel Build Container protected  function  initializeContainer()   {  

            $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  38. Kernel getContainerClass() Build Container Construit le nom de la classe

    de container app(Prod|Dev)(Debug)ProjectContainer
  39. app(Prod|Dev)(Debug)ProjectContainer Build Container class  appDevDebugProjectContainer  extends  Container   {  

           //…          public  function  __construct()          {                  $this-­‐>methodMap  =  array(                          'user_manager'  =>  'getUserManagerService',                          //…            }          //…          protected  function  getUserManagerService()          {                  return  $this-­‐>services['user_manager']  =                            new  \AppBundle\Service\UserManager();          }   }
  40. Kernel Symfony\Component\HttpKernel\Kernel Build Container protected  function  initializeContainer()   {  

           $class  =  $this-­‐>getContainerClass();    $cache  =  new  ConfigCache(          $this-­‐>getCacheDir().’/'.$class.’.php',          $this-­‐>debug    );          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  41. Un petit détour Symfony\Component\Config\ConfigCache Build Container Son métier : gestion

    des fichiers mis en cache isFresh() write() getMetaFile() On y reviendra
  42. Kernel Symfony\Component\HttpKernel\Kernel Build Container protected  function  initializeContainer()   {  

           $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  ( !$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  43. isFresh() Symfony\Component\Config\ConfigCache Build Container Le cache est frais si :

    • app(Prod|Dev)(Debug)ProjectContainer.php existe • l’application n’est pas en mode debug • si le fichier app(Prod|Dev) (Debug)ProjectContainer.php.meta existe • Ressources n’ont pas changées depuis la dernier boot du kernel et ou et app(Prod|Dev)(Debug)ProjectContainer.php.meta contient la liste des resources ajoutées au containerBuilder, serialisée
  44. None
  45. Moitié du voyage Front Controller Kernel ContainerBuilder Container Vous êtes

    ici
  46. Kernel Symfony\Component\HttpKernel\Kernel Build Container protected  function  initializeContainer()   {  

           $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                   $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  47. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  48. Kernel::buildContainer()

  49. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  50. buildContainer() 1/6 Symfony\Component\HttpKernel\Kernel Build Container Vérifie que le dossier de

    cache est accessible en écriture. 1
  51. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  52. buildContainer() /6 Symfony\Component\HttpKernel\Kernel Build Container Instancie le ContainerBuilder. 2

  53. Instancier le ContainerBuilder Symfony\Component\HttpKernel\Kernel Build Container Si ocramius/proxy-manager • Permet

    le lazy loading des services. • Un ProxyInstanciator se charge de n’instancier un service que si c’est vraiment nécessaire. lazy=true
  54. Lazy loading Service A Service B Sans lazy loading :

    ce service est instancé même s’il n’est pas utilisé. Avec le lazy loading : ce service n’est instancé que s’il y a utilisation concrète.
  55. ! Overhead non négligeable blackfire.io

  56. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  57. buildContainer() 3/6 Symfony\Component\HttpKernel\Kernel Build Container Kernel::prepareContainer() Pour chaque bundle •

    Chargement des classes d’extensions [1] ! • Appel de la méthode build() [2] ! • Passe de compilation chargée d’appeler la méthode load() de toutes les extensions 3
  58. namespace  AppBundle\DependencyInjection;   use  […]   class  AppExtension  extends  Extension

      {      public  function  load(array  $configs,  ContainerBuilder   $container)      {          $configuration  =  new  Configuration();          $config  =  $this-­‐>processConfiguration($configuration,   $configs);          $loader  =  new  Loader\XmlFileLoader($container,  new   FileLocator(__DIR__.'/../Resources/config'));          $loader-­‐>load('services.xml');      }   }   Classe d’extension Rappel
  59. prepareContainer() Symfony\Component\HttpKernel\Kernel Build Container Point d’extension ! [1] Bundle::getContainerExtension() [NamespaceDuBundle]\DependencyInjection\[NomDuBundle]Extension

  60. prepareContainer() Symfony\Component\HttpKernel\Kernel Build Container Point d’extension ! [2] Bundle::build(ContainerBuilder) Enregistrer

    les passes de compilation, d’autres extensions… tout ce que l’on souhaite ajouter au containerBuilder.
  61. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  62. Symfony\Component\HttpKernel\Kernel Build Container Kernel::registerContainerConfiguration(LoaderInterface $loader) Tout ce qui est dans

    config_*.yml est mergé dans le container. [3] buildContainer() 3/6 4
  63. registerContainerConfiguration() Symfony\Component\HttpKernel\Kernel Build Container Point d’extension ! [3] Kernel::registerContainerConfiguration() Enregistrer

    de la configuration dynamiquement, en fonction de l’environnement par exemple.
  64. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  65. Symfony\Component\HttpKernel\Kernel Build Container • Ajout d’une passe de compilation responsable

    de l’écriture du classes.map. • Ne contient que les classes d’extension. • Usage uniquement interne. buildContainer() 3/6 5
  66. protected  function  buildContainer()   {          //

     check  if  the  cache  directory  is  writable          $container  =  $this-­‐>getContainerBuilder();          $container-­‐>addObjectResource($this);          $this-­‐>prepareContainer($container);          $containerLoader  =  $this-­‐>getContainerLoader($container);          $cont  =  $this-­‐>registerContainerConfiguration($containerLoader);          if  (null  !==  $cont)  {                  $container-­‐>merge($cont);          }          $container-­‐>addCompilerPass(new  AddClassesToCachePass($this));          $container-­‐>addResource(new  EnvParametersResource(‘SYMFONY__’);          return  $container;   } Kernel Symfony\Component\HttpKernel\Kernel Build Container 2 1 3 4 5 6
  67. Symfony\Component\HttpKernel\Kernel Build Container Variables d’environnements dans $_SERVER et commençant par

    SYMFONY__ buildContainer() 3/6 6
  68. On y arrive ! Front Controller Kernel ContainerBuilder Container Vous

    êtes ici
  69. Compilation du Container Builder 2ième étape

  70. ContainerBuilder Symfony\Component\DependencyInjection Compile protected  function  initializeContainer()   {    

         $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                   $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  71. ContainerBuilder Symfony\Component\DependencyInjection Compile • Récupération du compiler • Symfony\Component\DependencyInjection\Compiler •

    process($containerBuilder) de toutes les passes de compilations [4] • Résout les paramètres « %xxxxxx% » • Ajout des paramètres dans le FrozenParameterBag Lecture seule
  72. ContainerBuilder Symfony\Component\DependencyInjection Compile Le container est à l’état « frozen

    »
  73. Passe de compilation Compiler pass Compile Modifier la définition de

    services dans le ContainerBuilder http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html Point d’extension ! [4] CompilerPassInterface::process() http://afsy.fr/avent/2013/05-conteneur-de-services-creer-ses-propres-tags
  74. Récupérer le container 3ième étape

  75. On y arrive ! Front Controller Kernel ContainerBuilder Container Vous

    êtes ici
  76. ContainerBuilder Symfony\Component\DependencyInjection récupérer le container protected  function  initializeContainer()   {

             $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                   $this-­‐>dumpContainer(                  $cache,                  $container,                  $class,                  $this-­‐>getContainerBaseClass()          );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  77. • Symfony\Component\DependencyInjection\Dumper\PhpDumper • Si => le proxyDumper est utilisé. •

    Le code est créé pour remplir le fichier app(Prod|Dev)(Debug)ProjectContainer. • Le fichier est écrit. récupérer le container Kernel Symfony\Component\HttpKernel
  78. app(Prod|Dev)(Debug)ProjectContainer.php class  appDevDebugProjectContainer  extends  Container   {      

       //…          public  function  __construct()          {                  $this-­‐>methodMap  =  array(                          'user_manager'  =>  'getUserManagerService',                          //…            }          //…          protected  function  getUserManagerService()          {                  return  $this-­‐>services['user_manager']  =                            new  \AppBundle\Service\UserManager();          }   } récupérer le container
  79. Hurray Container

  80. On y est ! Front Controller Kernel ContainerBuilder Container Vous

    êtes ici
  81. ContainerBuilder Symfony\Component\DependencyInjection Compile protected  function  initializeContainer()   {    

         $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }           require_once  $cache;      $this-­‐>container  =  new  $class();          $this-­‐>container-­‐>set('kernel',  $this);                    […]   }
  82. ContainerBuilder Symfony\Component\DependencyInjection protected  function  initializeContainer()   {      

       $class  =  $this-­‐>getContainerClass();          $cache  =  new  ConfigCache($this-­‐>getCacheDir().'/'.$class.'.php',  $this-­‐>debug);          $fresh  =  true;          if  (!$cache-­‐>isFresh())  {                  $container  =  $this-­‐>buildContainer();                  $container-­‐>compile();                  $this-­‐>dumpContainer(                          $cache,                          $container,                          $class,                          $this-­‐>getContainerBaseClass()                  );                  $fresh  =  false;          }          require_once  $cache;          $this-­‐>container  =  new  $class();         $this-­‐>container-­‐>set('kernel',  $this);                    […]   } Service synthetic
  83. Comment cela se finit ?

  84. Kernel Symfony\Component\HttpKernel\Kernel Build Container public  function  boot()   {  

       if  (true  ===  $this-­‐>booted)  {              return;      }      […]      $this-­‐>initializeBundles();      $this-­‐>initializeContainer();      foreach  ($this-­‐>getBundles()  as  $bundle)  {              $bundle-­‐>setContainer($this-­‐>container);              $bundle-­‐>boot();      }      $this-­‐>booted  =  true;   }
  85. Récapitulons

  86. 3 Grandes étapes 1. Construction du container builder 2. Compilation

    du container builder 3. Récupérer le container
  87. Points d’extension disponibles Quand ? Réécriture Kernel:buildContainer() Étape 1 Bundle::getContainerExtension()

    Kernel:buildContainer() Étape 1 Bundle::build() Kernel:buildContainer() Étape 1 AppKernel::registerContainerConfiguration() ContainerBuilder::compile() Étape 2 CompilerPassInterface::process()
  88. None
  89. @saro0h