user1134287
user1134287

Reputation: 161

Symfony2-How to use access a service from outside of a controller

In my Symfony2 controller, this works fine:

$uploadManager = $this->get('upload.upload_manager');

but when I move it to a custom Listener:

use Doctrine\ORM\Event\LifecycleEventArgs;
use Acme\UploadBundle\Upload\UploadManager;

class PersonChange
{
    public function postRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entityManager = $args->getEntityManager();

        $uploadManager = $this->get('ep_upload.upload_manager');
        echo "the upload dir is " . $uploadManager->getUploadDir();
    }
}

I get an error:

Fatal error: Call to undefined method Acme\MainBundle\Listener\PersonChange::get() in /home/frank/...

I know I must need a use statement but don't know what to use.

Upvotes: 15

Views: 21388

Answers (4)

Elnur Abdurrakhimov
Elnur Abdurrakhimov

Reputation: 44831

Update: Defining controllers as services is no longer officially recommended in Symfony.

The get() method in the Controller class is just a helper method to get services from the container, and it was meant to get new Symfony2 developers up to speed faster. Once people get comfortable with the framework and dependency injection, it's recommended to define controllers as services and inject each required service explicitly.

Since your PersonChange class is not a controller and doesn't extend the Controller class, you don't have that get() helper method. Instead, you need to define your class as a service and inject needed services explicitly. Read the Service Container chapter for details.

Upvotes: 16

T30
T30

Reputation: 12222

If you need to access a Service, define it in the class constructor:

class PersonChange{
    protected $uploadManager;
    public function __construct(UploadManager $uploadManager){
        $this->uploadManager = $uploadManager;
    }
    // Now you can use $this->uploadManager.
}

Now you can pass the Service as argument when calling the class (example 1) or define the clas itself as a Service (recommended, example 2)

Example 1:

use Acme\PersonChange;
class appController{
    function buzzAction(){
        $uploadManager = $this->get('upload.upload_manager');
        $personChange = new PersonChange($uploadManager);

Example 2 (better):

Define PersonChange as a Service itself, and define the other Service as an argument in services.yml file:

 # app/config/services.yml
services:
    upload.upload_manager:
        class:     AppBundle\uploadManager

    PersonChange:
        class:     AppBundle\PersonChange
        arguments: ['@upload.upload_manager']

In this way, you don't have to bother with the upload_manager service in the Controller, since it's implicitely passed as an argument for the constructor, so your Controller can be:

class appController{
    function buzzAction(){
        $personChange = $this->get('PersonChange');

Upvotes: 1

Guilherme Viebig
Guilherme Viebig

Reputation: 6932

An approach that always works, despite not being the best practice in OO

global $kernel;
$assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏

Upvotes: 8

Mathieu
Mathieu

Reputation: 1082

As I ran into the exact same problem maybe I can help

What Elnur said is perfectly fine and I'll just try to pop up a real life example.

In my case I wanted to access

$lucenemanager = $this->get('ivory.lucene.manager')

Even by extending the controller I couldn't get it to work while the controller does access the container (I still did not understand why)

In config.yml my listener (searchindexer.listener) is declared as follow :

   services:
    searchindexer.listener:
        class: ripr\WfBundle\Listener\SearchIndexer
        arguments:
              luceneSearch: "@ivory_lucene_search"
        tags:
            - { name: doctrine.event_listener, event: postPersist }

A service (ivory.lucene.search) is passed as argument in my service/listener.

Then in my class

protected $lucenemanager;

        public function __construct($luceneSearch)
        {
            $this->lucenemanager = $luceneSearch;
        }

Then you can use the get method against $this

Upvotes: 12

Related Questions