2016-07-29 2 views
0

У меня есть служба, которую я использую в разных местах моего проекта. В моих контроллерах он работает отлично.Как получить услугу для работы в прослушивателе событий жизненного цикла

Мне нужен он в прослушивателе событий жизненного цикла prePersist, но вызов службы там не хочет работать. Когда я пытаюсь, я получаю следующую ошибку;

Пытались вызвать метод "получить" на классе "Xx \ ххх \ XxxxBundle \ Lib \ Ыыыы \ OrderUserListener".

Я думаю, что я понимаю, что мне нужно внедрить мою службу в прослушиватель событий, но я не понимаю, как это сделать.

Вот как выглядят службы OrderUserListener и OrderLogger в файле service.yml соответственно;

bss.pmod.current_user_id: 
    class: Xx\Xxx\XxxxBundle\Lib\Yyyy\OrderUserListener 
    calls: 
    - [ setServiceContainer, [@service_container] ] 
    tags: 
     - { name: doctrine.event_listener, event: prePersist } 

bss.pmod.order_logger: 
    class: Xx\Xxx\XxxxBundle\Lib\Yyyy\OrderLogger 
    arguments: [ "@doctrine.orm.entity_manager", "@security.token_storage" ] 

И это моя функция OrderLogger, которую я хочу внедрить в свою службу;

class OrderLogger { 

    private $em; 
    private $tokenStorage; 

    /** 
    * Constructor. 
    * 
    * @param EntityManager $em 
    * @param TokenStorage $securityTokenStorage 
    */ 
    public function __construct(EntityManager $em, TokenStorage $securityTokenStorage) 
    { 
     $this->em = $em; 
     $this->tokenStorage = $securityTokenStorage; 
    } 

    /** 
    * Log an order action. 
    * 
    * @param string $text 
    */ 
    public function log($order, $action) 
    { 
     $logRecord = new PmodLog(); 
     if (is_object($this->tokenStorage->getToken())) { 
      $user = $this->tokenStorage->getToken()->getUser(); 
      if (is_object($user)) { 
       $logRecord->setUser($user); 
      } 
     } 
     $logRecord->setOrder($order); 
     $logRecord->setAction($action); 
     $logRecord->setTime(new \DateTime()); 

     $this->em->persist($logRecord); 
     $this->em->flush(); 
    } 

} 

Мой слушатель событий выглядит следующим образом;

class OrderUserListener 
{ 

    /** 
    * Service container 
    * @var type 
    */ 
    private $serviceContainer; 

    /** 
    * Performs tasks before destruction 
    * @ORM\PrePersist 
    */ 
    public function prePersist(LifecycleEventArgs $args) 
    { 
     $order = $args->getEntity(); 

     if ($order instanceof PmodOrder) { 
      $user = $this->serviceContainer->get('security.token_storage')->getToken()->getUser(); 

      if ($user) { 
       $order->setCreatedBy($user); 
       $order->setCreatedAt(new \DateTime(date('Y-m-d H:i:s'))); 
       $order->setDepartment($user->getDepartment()); 
       $order->setStatus(PmodOrder::STATUS_AWAITING_APPROVAL); 

       //$this->get('bss.pmod.order_logger')->log($order, 'Order Created');  // This is then clearly wrong. 
      } 
     } 
    } 

    /** 
    * Sets the sales order exporter object 
    * @param type $serviceContainer 
    */ 
    public function setServiceContainer($serviceContainer) 
    { 
     $this->serviceContainer = $serviceContainer; 
    } 
} 

Если кто-нибудь может объяснить мне, показывая, как сделать это с моим образцом, я действительно буду ценить это много.

+0

Можете ли вы предоставить определение 'OrderUserListener'? Как вы это делали для 'OrderLogger' –

+0

Вы имеете в виду определение службы в моем файле service.yml для' OrderUserListener'? – Mentos93

+0

Да, кажется, вам нужно добавить свой 'bss.pmod.order_logger' в качестве аргумента. –

ответ

1

Во-первых, похоже, вы смешиваете ContainerAwareInterface (теперь осуждается в пользу ContainerAwareTrait) с Controller базового класса Symfony в. ContainerAwareInterface предназначен для различения классов, которым требуется инсталлированный контейнер обслуживания, а контроллеры автоматически вводят его. Поскольку, похоже, эта линия работает:

$user = $this->serviceContainer->get('security.token_storage')->getToken()->getUser(); 

, похоже, что контейнер впрыскивается должным образом.

Метод get(), который вы пытаетесь вызвать со службы, на самом деле напоминает мне о Controller's get() method. Но ваш класс не является потомком Controller, и отнюдь не является на самом деле контроллером, насколько я могу судить.

Что вы должны сделать вместо вызова get() здесь называют контейнер:

$logger = $this->serviceContainer->get('bss.pmod.order_logger')->log($order, 'Order Created'); 

Однако услуги ContainerAware, как правило, считается плохой практикой. Вместо этого вы можете вводить услуги непосредственно через конструктор:

# Service definition 
bss.pmod.current_user_id: 
    class: Xx\Xxx\XxxxBundle\Lib\Yyyy\OrderUserListener 
    arguments: 
     - "@security.token_storage" 
     - "@bss.pmod.order_logger" 
    tags: 
     - { name: doctrine.event_listener, event: prePersist } 

class OrderUserListener 
{ 
    private $tokenStorage; 

    private $logger; 

    public function __construct($tokenStorage, $logger) 
    { 
     $this->tokenStorage = $tokenStorage; 
     $this->logger = $logger; 
    } 

    // ... 

    public function prePersist(LifecycleEventArgs $args) 
    { 
     // ... 

     // Here you can call the injected services: 
     $user = $this->tokenStorage->getToken()->getUser(); 

     $this->logger->log($order, 'Created'); 
    } 
} 
+0

Это на правильном пути, но приведет к ошибке циклической зависимости. Служба управления сущностью доктрины фактически зависит от ее слушателей сущностей. В вашем примере прослушиватель объектов в свою очередь зависит от регистратора, который сам зависит от менеджера сущности. Boom! Инъекция контейнера - один из способов обойти это. Лучше всего извлечь диспетчер сущностей из $ args и передать его журналу. – Cerad

+0

Спасибо за ответ kix, я попробую. Но что вы имеете в виду @Cerad? Можете ли вы, может быть, разработать больше, чтобы помочь мне заставить его работать на правильном пути? Или это строка '$ logger = $ this-> serviceContainer-> get ('bss.pmod.order_logger') -> журнал ($ order, 'Order Created');' упомянуто kix достаточно? Потому что тогда это то же самое, что и нижний проголосовавший ответ ниже, и это приводит к другой ошибке. Я предполагаю, что тогда я просто поработаю над этой ошибкой и задаю новый вопрос ... – Mentos93

+0

Я бы ожидал, что нисходящий ответ, по крайней мере, приведет вас к опубликованному сообщению об ошибке. В любое время, когда вы пытаетесь обновить базу данных ($ em-> flush()) у слушателя, у вас могут быть проблемы. Но посмотрите, что произойдет. – Cerad

-1

Изменение $this->get('bss.pmod.order_logger')->log($order, 'Order Created'); к $this->serviceContainer->get('bss.pmod.order_logger')->log($order, 'Order Created');

+0

Если вы положите -1, то объясните причину –

+0

Я не тот, кто голосует, но я помню, что я действительно пробовал это именно так. Я получил еще одну ошибку.Я не могу проверить это прямо сейчас, но я вернусь к вам в понедельник утром. – Mentos93

Смежные вопросы