docs icon indicating copy to clipboard operation
docs copied to clipboard

Symfony Container not available for Legacy Environment

Open TechhDan opened this issue 5 years ago • 8 comments

The PrestaShop Module Services documentation mentions that we are able to obtain the Symfony Container from our modules. This isn't working for me when extending PaymentModule on 1.7.5.2.

public function getContent()
{
    // Error: Attempted to call an undefined method named "getContainer" of class "AdminModulesController".
    $formFactory = $this->context->controller->getContainer()->get('form.factory');
}

I did find something similar in the Psaddonsconnect which does work for me. Should we use this instead?

public function getContent()
{
    global $kernel;
    $formFactory = $kernel->getContainer()->get('form.factory');
}

TechhDan avatar Jul 08 '19 04:07 TechhDan

In fact there are 3 containers :

  • Front container contains legacy services for front office
  • Back container contains legacy services for back office
  • Symfony container contains Symfony services but only available on back office for now because front office migration is not started.

Currently, if you want some Symfony services on front office, you have to declare them in config/front/services.yml inside your modules. Same as if you use them as standalone.

Matt75 avatar Jul 08 '19 06:07 Matt75

Oh ok that makes sense. I was trying to use the Symfony Services that are already loaded from the Modules main class and i guess how to get the Symfony Sevices was what I was confused but i think I get it. Thanks!

class MyModule extends Module
{
	public function getContent()
    {
    	// Accessing legacy back-office service container - works but service not found
        $legacy_service = $this->context->controller->get('form.factory');

        // Accessing Symfony service container - works and service is found
        global $kernel;
        $symfony_service = $kernel->getContainer()->get('form.factory');

        // The documentation under Services mentions this method - does not work. Error - undefined method 'getContainer'
        // this is where the documentation threw me off
        $unidentified_service = $this->context->controller->getContainer()->get('custom.service');
    }
}

TechhDan avatar Jul 08 '19 07:07 TechhDan

<?php

if (!defined('_PS_VERSION_')) {
    exit;
}

if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    // Only for PrestaShop < 1.7.6.0
    require_once __DIR__ . '/vendor/autoload.php';
}

// Use statement should be after your autoloader inclusion
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;

class MyModule extends Module
{
    public function getContent()
    {
        $symfonyContainer = SymfonyContainer::getInstance();
        // You must declare your service in module/mymodule/config/services.yml
        $myService = $this->getSymfonyContainer()->get('mymodule.myservice');
    }
}

Matt75 avatar Jul 08 '19 10:07 Matt75

Thank you!

TechhDan avatar Jul 09 '19 09:07 TechhDan

Hi,

how about this ?

class MyModule extends Module
{
    public function getContent()
    {
       // the service still needs to be declared in the right file
       $this->get('mymodule.myservice');
    }
}

$symfonyContainer = SymfonyContainer::getInstance();

We should never use that directly, this was a terrible idea to create such global state. Note that it will boot the "entire" Symfony application where it's called, so if it's called in a "front office" hook the performance impact will be really huge !

mickaelandrieu avatar Jul 09 '19 15:07 mickaelandrieu

Right now the only two options that work for me on 1.7.5.2 are the SymfonyContainer singleton and calling global on the kernel. The $this->get method looks for services but only works for me on modern controllers. From the module class I'm only able to get legacy services.

Since my problem is only with Admin Legacy Controller i guess would it be okay to use SymfonyContainer for this only?

<?php

class MyModule extends Module
{
	public function getContent()
	{
                // works fine - legacy service
                $service = $this->get('employee');

		// You have requested a non-existent service 
		$service = $this->get('mymodule.service'); // defined in my services.yml
		
		// You have requested a non-existent service 
		$form = $this->get('form.factory'); // Symfony service, not defined in my modules services.yml

		// works fine
		$form = SymfonyContainer::getInstance()->get('form.factory');
		// works fine
		global $kernel;
                $symfony_service = $kernel->getContainer()->get('form.factory');
	}
}

class ModernAdminController extends \PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController
{
    public function demoAction()
    {
    	// Works fine
    	$service = $this->get('mymodule.service'); // defined in my services.yml

    	// Works fine
        $form = $this->get('form.factory'); // Symfony service, not defined in my modules services.yml
    }
}

TechhDan avatar Jul 10 '19 01:07 TechhDan

Yes, of course !

mickaelandrieu avatar Jul 10 '19 21:07 mickaelandrieu

and if you override some classes file, you can not get service anyway. like: override/classes/ImageManager.php

langziyang avatar Jun 30 '22 03:06 langziyang