Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

symfony

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.

like image 920
user1134287 Avatar asked Jan 06 '12 12:01

user1134287


4 Answers

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.

like image 82
Elnur Abdurrakhimov Avatar answered Nov 09 '22 06:11

Elnur Abdurrakhimov


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

like image 31
Matthieu Avatar answered Nov 09 '22 06:11

Matthieu


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

global $kernel;
$assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏
like image 8
Guilherme Viebig Avatar answered Nov 09 '22 05:11

Guilherme Viebig


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');
like image 1
T30 Avatar answered Nov 09 '22 05:11

T30