Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony how to get container in my service

I have symfony project and inside this project, I have big own service which is huge and complicated with own dependencies etc... And I wanna create facade 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 (inversion-of-control) here.

like image 376
cn007b Avatar asked Aug 30 '17 16:08

cn007b


People also ask

What is Symfony Service Container?

In Symfony, these useful objects are called services and each service lives inside a very special object called the service container. The container allows you to centralize the way objects are constructed. It makes your life easier, promotes a strong architecture and is super fast!

What is a service container?

A Service Container (or dependency injection container) is simply a PHP object that manages the instantiation of services (i.e. objects). For example, suppose you have a simple PHP class that delivers email messages. Without a service container, you must manually create the object whenever you need it: Copy.

What is dependency injection in Symfony?

The Dependency Injection Container in Symfony2 allows components to be injected with their dependencies, and is often used as a Service Locator, which when combined with the DI-container pattern is considered to be an anti-pattern by many.

What is a service configurator in Symfony?

The service configurator is a feature of the service container that allows you to use a callable to configure a service after its instantiation. A service configurator can be used, for example, when you have a service that requires complex setup based on configuration settings coming from different sources/services.


2 Answers

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.

like image 199
Matko Đipalo Avatar answered Oct 14 '22 15:10

Matko Đipalo


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->...
    }
 }
like image 30
Robert Avatar answered Oct 14 '22 14:10

Robert