简体   繁体   中英

Symfony how to get container in my service

I have project and inside this project, I have big own service which is huge and complicated with own dependencies etc... And I wanna create for this service with purpose to use my service in controllers like:

$myService = $this->container->get('service_from_my_domain');

My question - is how inside my facade I can get access to container to service's dependencies. I know only 1 way - is to inject dependency into service in yaml config.
But is there another way to do it? Like:

$dependency = Container::getInstance()->get('my_dependency_service');

I've found this answer but using global variable feels like back in time...

PS: I don't want to inject dependency through yaml config (not constructor injection nor setter injection) because I don't need IoC ( ) here.

can you do like this

services:
     kernel.listener.acme_listener:
          class: Acme\AcmeBundle\EventListener\AcmeListener
          arguments:
                - @service_container
          tags:
                - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

your Listener

use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class AcmeListener
 {
    /**
     * @var Container
     */
     private $container;

    /**
     * Constructor
     *
     * @param Container $container
     */
   public function __construct(Container $container)
    {
        $this->container = $container;
    }

   public function onKernelController(FilterControllerEvent $event)
    {
        $this->container->...
    }
 }

If you really want to have a fun and do code escapades, you could do something like this...

Create a Facade class, that must be initialized when the app starts. So, in app.php , just after the line $kernel = new AppKernel('prod', false); do the Facade initialization:

$kernel->boot();
$container = $kernel->getContainer();
\MyBundle\Facade::init($container);

And, here is a code for the Facade class:

<?php

namespace MyBundle;


use Symfony\Component\DependencyInjection\ContainerInterface;

class Facade
{
    /**
     * self|null
     */
    private static $instance = null;

    /**
     * ContainerInterface
     */
    private static $myContainer;

    /**
     * @param ContainerInterface $container
     */
    private function __construct(ContainerInterface $container)
    {
        self::$myContainer = $container;
    }

    /**
     * @param string $serviceId
     *
     * @return object
     * @throws \Exception
     */
    public static function create($serviceId)
    {
        if (null === self::$instance) {
            throw new \Exception("Facade is not instantiated");
        }

        return self::$myContainer->get($serviceId);
    }

    /**
     * @param ContainerInterface $container
     *
     * @return null|Facade
     */
    public static function init(ContainerInterface $container)
    {
        if (null === self::$instance) {
            self::$instance = new self($container);
        }

        return self::$instance;
    }
}

And, wherever you need some service, you create it this way:

$service = \\MyBundle\\Facade::create('my_dependency_service');


But, if you ask me - I would create a Facade service, that would have a container injected in the constructor. And you would have some method for service creation ( Facade::create($serviceId) ), that would ask the container for given service ID.

I've built a console app using Symfony 5.

Injecting a service in Symfony 5 is as simples as __construct(ServiceClass $service_name) ( type-hinting ) and everything is a service. But in one case I could not dependency inject at the constructor because the dependency service is conditioned to the parameters given at the command line.

So this is how I injected the needed service on the fly.

<?php

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use App\Kernel;

class MyCommand extends Command {
    protected static $defaultName = 'app:my-command';
    private $container;

    public function __construct(Kernel $kernel) {
        $this->container = $kernel->getContainer();
        //...
        parent::__construct();
    }

    protected function configure() {
        // ...
    }

    protected function execute(InputInterface $input, OutputInterface $output) {
        //...
        // read the parameters given in the cmd and decide what class is
        // gona be injected.
        // $service_name = "App\\My\\Namespace\\ServiceClassName"
        $service = $this->container->get($service_name);
        $service->doSomething();

        return Command::SUCCESS;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM