Arsham
Arsham

Reputation: 1452

Inject service in symfony2 Controller

How can I inject a service (the service that I created) into my Controller? A setter injection would do.

<?php
namespace MyNamespace;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class MyController extends Controller
{
    public function setMyService(MyService $myService)
    {
        $this->myService = $myService;
    }

    public function indexAction()
    {
        //Here I cannot access $this->myService;
        //Because the setter is not called magically!
    }
}

And my route settings :

// Resources/routing.yml
myController_index:
    pattern:  /test
    defaults: { _controller: "FooBarBundle:MyController:index" }

I'm setting the service in another bundle :

// Resources/services.yml 
parameters:
   my.service.class: Path\To\My\Service

services:
    my_service:
        class: %my.service.class%

When the route is resolved, the service is not injected ( I know it shouldn't ). I suppose somewhere in a yml file, I have to set:

    calls:
        - [setMyService, [@my_service]]

I am not using this Controller as a service, it's a regular Controller that serves a Request.

Edit: At this point in time, I am getting the service with $this->container->get('my_service'); But I need to inject it.

Upvotes: 7

Views: 17621

Answers (4)

Kevin Kopf
Kevin Kopf

Reputation: 14195

Since it's 2017 ending now and there is no tag for Symfony 3 or upcoming Symfony 4 (and I think there should not be), this problem is solvable in a native much better way.

If you are still struggling and somehow ended up on this page and not in Symfony docs, then you should know, that you do not need to declare controller as service, as it is already registered as one.

What you need to do, is check you services.yml:

# app/config/services.yml
services:
    # default configuration for services in *this* file
    _defaults:
        # ...
        public: false

Change public: false to public:true if you want all services to be public.

Or explicitly add a service and declare it public:

# app/config/services.yml
services:
    # ... same code as before

    # explicitly configure the service
    AppBundle\Service\MessageGenerator:
        public: true

And then in your controller you can get the service:

use AppBundle\Service\MessageGenerator;

// accessing services like this only works if you extend Controller
class ProductController extends Controller
{
    public function newAction()
    {
        // only works if your service is public
        $messageGenerator = $this->get(MessageGenerator::class);
    }
}

Read more:

Upvotes: 3

COil
COil

Reputation: 7586

When using the JMSDiExtraBundle you DON'T have to define your controller as a service (unlike @elnur said) and the code would be:

<?php

namespace MyNamespace;

use JMS\DiExtraBundle\Annotation as DI;
use Path\To\My\Service;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class MyController extends Controller
{
    /**
     * @var $myService Service
     *
     * @DI\Inject("my_service")
     */
    protected $myService;

    public function indexAction()
    {
        // $this->myService->method();
    }
}

I find this approach very nice because you avoid writing a __construct() method.

Upvotes: 6

bjuice
bjuice

Reputation: 291

If you don't want to define your controller as a service, you can add a listener to the kernel.controller event to configure it just before it is executed. This way, you can inject the services you need inside your controller using setters.

http://symfony.com/doc/current/components/http_kernel/introduction.html#component-http-kernel-kernel-controller

Upvotes: 0

Elnur Abdurrakhimov
Elnur Abdurrakhimov

Reputation: 44831

If you want to inject services into your controllers, you have to define controllers as services.

You could also take a look at JMSDiExtraBundle's special handling of controllers — if that solves your problem. But since I define my controllers as services, I haven't tried that.

Upvotes: 7

Related Questions