0

I have the following controller:

namespace Acme\CompanyBundle\Controller;
use Symfony\Component\DependencyInjection\Container;

/**
 * Company controller.
 *
 */
class CompanyController extends Controller
{
    protected $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function getData()
    {
        $userObj = $this->container->get('security.context')->getToken()->getUser();
    }
}

In my services.yml file, I have injected Container class:

parameters:
    acme.controller.company.class:  Acme\ContainerBundle\Controller\CompanyController

services:
    acme.controller.company:
        class:      %acme.controller.company.class%
        arguments:  [@service_container]

When loading this controller, I get following error:

Catchable Fatal Error: Argument 1 passed to Acme\CompanyBundle\Controller\CompanyController::__construct() must be an instance of Symfony\Component\DependencyInjection\Container, none given, called in C:\wamp\www\symfony\app\cache\dev\classes.php on line 2785 and defined in C:\wamp\www\symfony\src\Acme\CompanyBundle\Controller\CompanyController.php line ...

As you could see, this is a simple injection of Container object into a controller but throws nice errors. What is the problem here?

Similar issue is posted in another SO thread here.

Community
  • 1
  • 1
webblover
  • 1,196
  • 2
  • 12
  • 30
  • The reason is that your route is still using MyBundle:CompanyController:action. You need to call the controller as a service _controller: acme.controller.company:action http://symfony.com/doc/current/cookbook/controller/service.html – Cerad Oct 08 '14 at 18:35
  • yeah great. I could understand that. But, could you rewrite that settings as per my configuration so that I understand clearly? – webblover Oct 08 '14 at 18:38

3 Answers3

2

You don't need to inject the container in controllers as long as they extend the base Controller class, which yours do.

Just do:

namespace Acme\CompanyBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * Company controller.
 *
 */
class CompanyController extends Controller
{
    public function getData()
    {
        $userObj = $this->get('security.context')->getToken()->getUser();
    }
}
FyodorX
  • 1,490
  • 2
  • 19
  • 23
  • I have used this similar injection in a handler file (AuthHandler, SecurityHandler etc.). But it works there without throwing any errors. I am highly confused & frustrated with the way symfony's dependency injection behaves. – webblover Oct 08 '14 at 18:15
  • Sorry, I didn't see it was a `Controller`. I've updated my answer. – FyodorX Oct 08 '14 at 18:15
  • I tried that and got this error: **Error: Call to a member function getUser() on a non-object in C:\wamp\www\symfony\src\Acme\CompanyBundle\Controller\CompanyController.php line ...** – webblover Oct 08 '14 at 18:20
  • Try doing `$this->get('security.context')->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');` instead. I know it's not what you want, but does it produce an error? – FyodorX Oct 08 '14 at 18:30
  • Thanks, that's a good suggestion. I tried that but it does not produce any error. – webblover Oct 08 '14 at 18:34
  • Then it has something to do with your user management. Post another question with the details and I'll try to help. – FyodorX Oct 08 '14 at 18:37
  • BTW, use `$this->container->get('security.authorization_checker')` instead (new in 2.6) – Ronan Aug 30 '15 at 20:32
1

By default, routes look something like this:

cerad_player_wanabe_list:
    pattern:  /player-request/list
    defaults: 
        _controller: CeradPlayerWanabeBundle:Player/PlayerList:list

The Symfony\Component\HttpKernel\HttpKernel::handle($request) method pulls the _controller attribute from the request object. If the attribute has two colons in it then it translates the attribute into a class name and creates an instance using the new operator. If the instance implements the ContainerAwareInterface then the container is injected into the controller instance. The controller service you defined is not used. Hence the error about no argument being passed to the constructor.

On the other hand, if _controller has only one colon then the controller is pulled as a service from the container. There is no checking for the ContainerAwareInterface. It's up to you to inject the dependencies via your service definition.

This is all documented in: http://symfony.com/doc/current/cookbook/controller/service.html

So for this particular question, your route should be something like:

cerad_player_wanabe_list:
    pattern:  /player-request/list
    defaults: 
        _controller: acme.controller.company:action

This does raise the question of why you are trying to define the controller as a service. The default approach already does exactly what you want so you are not gaining anything.

The rationale for defining services as containers is that you can control exactly what dependencies the controller uses. Makes the controller easier to understand and test.

Injecting the complete container pretty much destroys the value of defining the controller as a service.

Cerad
  • 48,157
  • 8
  • 90
  • 92
1

Never and never inject the container inside something (services, controller or whatever) Instead try to inject the securityContext or access it through the helper method of symfony controller as suggested above.

The token it's not an object just because probably the route of the controller it's not under a firewall

erlangb
  • 521
  • 6
  • 13
  • But **$this->container** is not available in my controller. Then how could I access any other service or "secutity.context" without this? – webblover Oct 11 '14 at 14:02
  • It's available on any sf controller. By the way you can inject the security.context or whatever as a service. Have a look on SF documentation. Tips: if you need to inject a lot of services the solution it's not inject all the container but change a probably poor or bad design. – erlangb Oct 13 '14 at 14:43