PHP Symfony request stack not found on bundle extension load -


i'm trying create reusable logging bundle can have custom formatter log messages. formatter set in main app's config file that:

custom_logger:     formatter: appbundle\services\messageformatter 

then in loggerbundle/dependencyinjection/customloggerextension.php after receive configuration i'm trying logger service , set formatter

class customloggerextension extends configurableextension {      public function loadinternal(array $mergedconfig, containerbuilder $container)     {         $loader = new yamlfileloader($container, new filelocator(__dir__ . '/../resources/config'));         $loader->load('services.yml');         $class = $mergedconfig['formatter'];         $obj = new $class;         $container->get('custom.logger')->setformatter($obj); 

but problem logger uses request stack

services:     custom.logger:         class: loggerbundle\services\logger         arguments: ['@request_stack'] 

and when try service in loadinternal function seems request stack not initialized yet , receive error: you have requested non-existent service "request_stack"

what correct way of doing this?

edit (2016-04-21 21:54:11)

that's weird. if remove request stack , set formatter in loadinternal, it's not in service when i'm getting controller in main app. must doing wrong :)

ok, think figured out.

when load() or in case loadinternal() method called, symfony passes there new container merged main one. if request service , created there, it's not saved anywhere in temporary container , destroyed (only service definitions passed main one).

since services loaded(created) on demand, it's not right instantiate on bundle load. want instead configure definitions

here how got working:

use symfony\component\httpkernel\dependencyinjection\configurableextension; use symfony\component\dependencyinjection\compiler\compilerpassinterface; use symfony\component\dependencyinjection\containerbuilder; use symfony\component\dependencyinjection\loader\yamlfileloader; use symfony\component\dependencyinjection\reference; use symfony\component\dependencyinjection\definition; use symfony\component\config\filelocator; use loggerbundle\formatter\messageformatterinterface;  class loggerbundleextension extends configurableextension implements compilerpassinterface {     protected $customformatter;      public function loadinternal(array $mergedconfig, containerbuilder $container)     {         $loader = new yamlfileloader($container, new filelocator(__dir__ . '/../resources/config'));         $loader->load('services.yml');          if (array_key_exists('formatter', $mergedconfig)) {             $this->customformatter = $mergedconfig['formatter'];         }     }      public function process(containerbuilder $containerbuilder)     {         if ($this->customformatter) {             $class = $this->customformatter;              //if formatter service id             $serviceused = $containerbuilder->has($this->customformatter);             if ($serviceused) {                 $class = $containerbuilder->getdefinition($this->customformatter)->getclass();             }             if (!class_exists($class) || !is_a($class, messageformatterinterface::class, true)) {                 throw new \errorexception('invalid logger formatter');             }             if ($serviceused) {                 $containerbuilder                     ->getdefinition('custom.logger')                     ->addmethodcall('setformatter', array(new reference($this->customformatter)));             } else {                 $containerbuilder                     ->getdefinition('custom.logger')                     ->addmethodcall('setformatter', array(new definition($this->customformatter)));             }         }     } } 

in loadinternal() check if formatter set in main app's config , save it. main thing happening in process() function (you have implement symfony\component\dependencyinjection\compiler\compilerpassinterface run).

from docs.

as process() called after extensions loaded, allows edit service definitions of other extensions retrieving information service definitions.

so, doing is:

  • checking if formatter option value class name or service id(if that's case, retrieve class name service definition)
  • validate class name (checking if it's valid class , making sure implements required interface)
  • adding definition logger service tells container call setformatter provided arguments when logger service created(when first retrieved container)

basically $containerbuilder->getdefinition('custom.logger')->addmethodcall('setformatter', array(new reference('my_formatter')));

is same declaring in config:

services:     custom.logger:         class: loggerbundle\services\logger         arguments: ['@request_stack']         calls:             - [setformatter, ['@my_formatter']] 

Comments

Popular posts from this blog

Django REST Framework perform_create: You cannot call `.save()` after accessing `serializer.data` -

Why does Go error when trying to marshal this JSON? -