c4pone
c4pone

Reputation: 797

Create a Base-Controller Class which implements the ContainerAwareInterface

I followed the tutorial of Fabien Potiencier, about how to create your own Framework on top of the Symfony Components. Now i need a way. And I want to inject the Dependency Container to all my Controllers, without defining every single Controller as a Service.

In the orginal Symfony2 Framework all Controllers extends the Controller Class located in Symfony\Bundle\FrameworkBundle\Controller\Controller.php:

namespace Symfony\Bundle\FrameworkBundle\Controller;

class Controller extends ContainerAware
{
   // ...
}

The Controller Class extends the ControllerAware Class, so you can do something like this in your Controller:

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class MyController extends Controller
{
   public function someAction()
   {
      $this->container->get('dependencie_xyz);
   }
}

So my question is: How can I accomplish the same in my Framework?

Upvotes: 3

Views: 5305

Answers (4)

Dedan Irungu
Dedan Irungu

Reputation: 61

If you are not implementing any interface on controller you can add the this way and it will work. This is a small modification to c4pone implementation.

/**
* Description of ContainerAwareControllerResolver
*
* @author sbc
*/
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;

class ContainerAwareControllerResolver extends ControllerResolver {

private $container;

public function __construct(LoggerInterface $logger = null, ContainerInterface $container = null) {

    parent::__construct($logger);

    $this->container = $container;
}

protected function instantiateController($class) {

    $new_class = new $class();

    $new_class->setContainer($this->container);

    return $new_class;
}

Upvotes: 0

1nstinct
1nstinct

Reputation: 1775

It is too simply. The next code will help you

namespace Symfony\Bundle\FrameworkBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Symfony\Component\DependencyInjection\ContainerAware as ContainerAware;

class TestService extends ContainerAware
{
   public function __construct(Container $container) {
      // in your example from official doc 'dependencie_xyz' is a name of service
      $this->setContainer($container); // call parent setContainer() method, for identifying container variable, from now you can access to ServiceContainer using $this->container variable
      $test_param = $this->container->getParameter('test_param'); // get test_param from config.yml
   }

}

in service.yml

write smthing like this

services:
    test_service:
        class: Symfony\Bundle\FrameworkBundle\TestService
        arguments: ['@service_container']

and post service container as argument

Upvotes: 0

c4pone
c4pone

Reputation: 797

It took me a while, but i finally figured out how the Symfony2 Framework does it. In the SymfonyFrameworkBundle is a custom ControllerResolver, which call the setContainer Method on the resolved controller. The controller has to be a instance of the ContainerAwareInterface.

Simplified version:

class ContainerAwareControllerResolver extends ControllerResolver
{
    private $container;

    public __construct(ContainerInterface $container)
    {
        $this->container = $container;
            parent::__construct();
    }

    public function getController(Request $request)
    {
        $controller = parent::getController($request);
        if($controller instanceof ContainerAware ){
            $controller->setContainer($this->container);
        }
    }
}

Source:

https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php

Upvotes: 3

Wouter J
Wouter J

Reputation: 41934

The Controller Class extends the ControllerAware Class, so you can do something like this in your Controller:

Well, this is not true. If we take a look at the signature of the ContainerAware class, we see that this added a setContainer method so we can set the container. Symfony2 has created the Controller::get method to make some live easier.

We can see how they do it in the source code:

/**
 * Gets a service by id.
 *
 * @param string $id The service id
 *
 * @return object The service
 */
public function get($id)
{
    return $this->container->get($id);
}

You can put this in your own Controller class and let all your controllers extend that controller class.

Upvotes: -1

Related Questions