Search code examples
phpsymfonyentitycontainerssymfony-2.6

How to get Container object from LifecycleEventArgs of postLoad in Entity?


I'm trying to inject the Container object (which is available in controllers) into an Entity using postLoad lifecycleCallbacks. The argument to the postLoad method is LifecycleEventArgs. I could see the container property (which I want to retrieve) in EventManager of LifecycleEventArgs according to the dump output, but it seems to be a private property and there is no getContainer() method in EventManager. The below is my code.

service.yml

services:
    ibw.jobeet.entity.job.container_aware:
        class: Ibw\JobeetBundle\Entity\Job
        tags:
            - { name: doctrine.event_listener, event: postLoad }

Ibw\JobeetBundle\Entity\Job.php

<?php
namespace Ibw\JobeetBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerInterface;

use Ibw\JobeetBundle\Utils\Jobeet;

/**
 * Job
 */
class Job
{
    //....
    /**
     * @var Container
     */
    protected $container;

    public function postLoad(LifecycleEventArgs $eventArgs)
    {
        $entity = $eventArgs->getEntity();
        $entityManager = $eventArgs->getEntityManager();
        $eventManager = $entityManager->getEventManager();
        echo '<pre>';
        \Doctrine\Common\Util\Debug::dump($eventManager, 3);

        // want to get $eventManager->container here

        exit;
    }
    //....
}

Is there any other way to retrieve it?


Solution

  • You can use setter-injection which result in a call to a predefined method (setContainer() in this case) with the container as an argument upon creation of the listener service:

    services:
        ibw.jobeet.entity.job.container_aware:
            class: Your\Bundle\Doctrine\Event\Listener\JobListener
            calls:
                - [setContainer, ["@service_container"]]
            tags:
                - { name: doctrine.event_listener, event: postLoad }
    

    Now the container is injected into the constructor of your listener class:

    namespace Your\Bundle\Doctrine\Event\Listener;
    
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Doctrine\ORM\Event\LifecycleEventArgs;
    
    class JobListener
    {
         /** @var ContainerInterface */
         protected $container;
    
         /** 
          * @param ContainerInterface @container
          */
         public function setContainer(ContainerInterface $container)
         {
              $this->container = $container;
         }
    
         public function postLoad(LifecycleEventArgs $eventArgs)
         {
             $entity = $eventArgs->getEntity();
             // do something with your entity here i.e.
             $entity->setFoo($this->container->getParameter('foo'));
    

    This is just an example. Please consider injecting only the services you really need - instead of injecting the container itself. You will be rewarded with better testability and performance.