Environment service decoration

Discussion forum for Extension Writers regarding Extension Development.
Post Reply
User avatar
GanstaZ
Jr. Extension Validator
Posts: 636
Joined: Wed Oct 11, 2017 10:29 pm
Location: Zverse

Environment service decoration

Post by GanstaZ » Sun Apr 01, 2018 2:33 pm

Question i have may sound noobish, but i want to understand how it works. When i take a look at core file, phpbb injects environment and loads $extension_manager that loads all available extensions. I need to load 1 service i created in tag parser, so i tried to decorate phpbb environment.

Code: Select all

acme.demo.decorated.environment:
  class: '\acme\demo\decorated\environment'
  decorates: template.twig.environment
  public: false
  arguments:
    - '@acme.demo.decorated.config.inner'
    - '@vendor.name.demo'
Then I extend environment class and set constructor with injected services:

Code: Select all

class environment extends \phpbb\template\twig\environment

    public function __construct(\phpbb\template\twig\environment $environ, \my\injected\service $service)
    {
         ...
    }
After when i load a page i get an exception about loader not set. As i understand it, the main class exists & is used as a reference, but i can't set my constructor the same way as is done already in phpbb environment. How can i make it to work? I know there is a service replacement, but decoration is preferred method.
"When answer lies in the question,.. question becomes redundant!"

User avatar
kasimi
Extension Customisations
Extension Customisations
Posts: 3360
Joined: Sat Sep 10, 2011 7:12 pm
Location: Germany
Contact:

Re: Environment service decoration

Post by kasimi » Sun Apr 01, 2018 2:58 pm

I've had similar issues with service decoration. Since your environment extends \phpbb\template\twig\environment, you need to call the parent constructor and pass all its arguments, which means your decoration service needs them injected in addition to the .inner service. Also I'm not sure if the setters are called by Symfony. This makes the code anything but future proof and defeats the purpose in my opinion. I guess service decoration doesn't go well with inheritance, and instead it is intended to be used with composition exclusively, which greatly narrows the use-cases.

User avatar
GanstaZ
Jr. Extension Validator
Posts: 636
Joined: Wed Oct 11, 2017 10:29 pm
Location: Zverse

Re: Environment service decoration

Post by GanstaZ » Sun Apr 01, 2018 3:19 pm

I see. So one problem is parent constructor, another may be that setter. I will test it out later & see how it goes. Of course there is a way, but i don't think it is needed in core, because i don't have a clue who may need to use some custom services in places like tags. As i see it, you can't inject a service directly into tagparser, but only with environment. If environment had a custom service loader like it is done for twig extensions, then it would be a lot easier. Hook service with a tag in .yml, class will extend an interface get_something that would return an array, environment would load it with a method($vendor or whatever). But yeah.. is something like this needed for masses or just for one person.. I don't know?!
Thanks for the help & i will update my post later, with success or failure)
"When answer lies in the question,.. question becomes redundant!"

User avatar
GanstaZ
Jr. Extension Validator
Posts: 636
Joined: Wed Oct 11, 2017 10:29 pm
Location: Zverse

Re: Environment service decoration

Post by GanstaZ » Sun Apr 01, 2018 9:00 pm

I did some research and found a way to do what i want without extending/decorating environment. Is it a good practice i don't know, maybe someone who knows better can answer it, but below is the solution i found:
Here is node class:

Code: Select all

class your_node_class extends \Twig_Node
{
	/** @var \Twig_Environment */
	protected $environment;
	public function __construct(\Twig_Node_Expression $expr, \phpbb\template\twig\environment $environment, $lineno, $tag = null)
	{
		$this->environment = $environment;
		parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
	}
	
	/**
	* Compiles the node to PHP.
	*
	* @param \Twig_Compiler A Twig_Compiler instance
	*/
	public function compile(\Twig_Compiler $compiler)
	{
		$compiler->addDebugInfo($this);
		$service = $this->environment->getExtension('path\to\your\twig\your_extension');
		
		// $service->get_service_we_need($this->getNode('expr')->getAttribute('name'))
                $service->get_service_we_need()->method_we_want_to_use();
And here is extension class:

Code: Select all

class your_extension extends \Twig_Extension
{
	/** @var \path\to\service */
	protected $service;
	/**
	* Constructor
	*
	* @param \path\to\service $service
	* @return \phpbb\template\twig\extension
	*/
	public function __construct(\path\to\service $service)
	{
		$this->service = $service;
	}
	
	
	/**
	* Get our service object
        *       get_service_we_need($something)
	*
	* @return string
	*/
	public function get_service_we_need()
	{
	        // return $this->service->method($something);
		return $this->service;
	}
"When answer lies in the question,.. question becomes redundant!"

Post Reply

Return to “Extension Writers Discussion”

Who is online

Users browsing this forum: No registered users and 7 guests