2016-02-27 6 views
-1

Перед Доктрины 2.4 путь по умолчанию, чтобы поймать события жизненного цикла (например, prePersist) является глобальной event listener, что уволит всех подразделений. Запуск такого слушателя, как сервис Symfony, облегчил внедрение других сервисов (например, объектов request или request_stack).Как создать объект прослушивателя лениво и ввести в него зависимостей

Теперь лучшим решением является так как это происходит с гораздо меньшими накладными расходами!

Итак, давайте начнем эту вещь в заголовок наши лица ...:

* @ORM\EntityListeners({ "AppBundle\Entity\Listener\LanguageListener" }) 

А вот класс:

namespace AppBundle\Entity\Listener; 

use Doctrine\ORM\Event\LifecycleEventArgs; 

class LanguageListener 
{ 
    public function prePersist($obj_entity, LifecycleEventArgs $obj_eventArgs) 
    {  
     $request = ???; 

     // set entity to users preferred language (for example 'de') 
     $obj_entity->setLanguage($request->getLocale()); 
    } 
} 

Как вы можете видеть, я не имею ни малейшего понятия, как доступ к услугам Symfonys (в данном случае объект request).

Но подождите! Существует способ:

global $kernel; 
if ('AppCache' == get_class($kernel)) 
{ 
    $kernel = $kernel->getKernel(); 
} 
$request = $kernel->getContainer()->get('request'); 

И он тоже работает.

Но во всех моих исследованиях я нашел много связанных вопросов, строго предупреждающих о том, что это! Только разница: все эти вопросы имели в виду лиц, а не к Entity слушателей ...

... ведет меня по этим двум вопросам:

  1. ли вышеупомянутое решение способ идти?
  2. А если нет: как это сделать?

[Edit:] Еще раз (см первое предложение) позвольте мне пояснить, что этот вопрос также о том, как не использовать услугу. Услуги приходят за определенную стоимость, см. Expensive Service Construction. И особенно в этом случае я редко нуждаюсь в функциональности - вот почему я хочу пойти с Entity Listeners, которые делают не работать как сервис.

Извините, я не подчеркивал этот боковой аспект. Не знаю, почему это квалифицировалось для снижения курса, хотя ...

[Edit2:] Чтобы сделать все более ясным, я добавил еще один пример кода (первый), который показывает, как отображается предмет.

+0

Вы уже видели [Рецептор восприятия сущностей] (http://docs.doctrine-project.org/en/latest/reference/events.html#entity-listeners-resolver)? – Matteo

+1

Я думаю, что это решение в сочетании с методом symfony [Entity Listeners] (http://symfony.com/doc/current/bundles/DoctrineBundle/entity-listeners.html) – Matteo

+0

Возможно, я действительно не понял концепция резольвера. Читайте об этом ранее сегодня, хотя, хорошо читайте: [Ресивер приемника сущностей] (http://egeloen.fr/2013/12/01/symfony2-doctrine2-entity-listener-as-serice/) Но все равно это все еще не решит мою проблему. – Eddie

ответ

5

От doctrine/doctrine-bundle >= 1.5.0 слушателей сущностей могут быть созданы как сервисы, и если они помечены doctrine.orm.entity_listener, они будут автоматически зарегистрированы в the desired entity manager. Вы можете вводить требуемые зависимости в службу, например. стек запроса.

Создать слушатель:

namespace AppBundle\Doctrine\Listener; 

use Symfony\Component\HttpFoundation\RequestStack; 

class LanguageListener 
{ 
    /** 
    * @var RequestStack 
    */ 
    private $requestStack; 

    public function __construct(RequestStack $requestStack) 
    { 
     $this->requestStack = $requestStack; 
    } 

    public function prePersist($entity) 
    { 
     if (null !== $request = $this->requestStack->getCurrentRequest()) { 
      // put the logic here 
     } 
    } 
} 

зарегистрировать его в качестве услуги:

app.doctrine.language_listener: 
    class: AppBundle\Doctrine\Listener\LanguageListener 
    public: false 
    arguments: ["@request_stack"] 
    tags: 
     - { name: "doctrine.orm.entity_listener" } 

Аннотирования лиц:

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use FOS\UserBundle\Entity\User as BaseUser; 

/** 
* @ORM\Entity() 
* @ORM\EntityListeners("AppBundle\Doctrine\Listener\LanguageListener") 
* @ORM\Table("user_") 
*/ 
class User extends BaseUser 
{ 
    // ... 
} 

Примечания что объект слушатель зарегистрирован таким образом, не лениво загружены, поэтому они и их зависимости wi Будет создан при создании менеджера объектов.

UPDATE:

Так что, если ваш вопрос о том, как использовать его лениво. Первое решение, которое приходит мне на ум, объявить его как lazy service, но в этом случае оно действительно работает не так, как ожидалось, потому что в аннотации мы используем класс concrate, который будет создан при помощи распознавателя при необходимости, но в этом случае мы должны написать имя прокси-класса в аннотации, вместо этого использовать объект-прокси, что невозможно. Существует решение хотя (которое в настоящий момент не задокументировано), не аннотируют объект с @EntityListeners, но используют параметры тега для регистрации слушателя. Что-то вроде этого:

app.doctrine.language_listener: 
    class: AppBundle\Doctrine\Listener\LanguageListener 
    arguments: ["@request_stack"] 
    lazy: true 
    tags: 
     - { name: "doctrine.orm.entity_listener", entity: AppBundle\Entity\User, event: preUpdate } 
     - { name: "doctrine.orm.entity_listener", entity: AppBundle\Entity\User, event: postUpdate } 

Таким образом, вы можете использовать ленивые услуги, но он работает только с doctrine/orm >= 2.5.0.

Другим решением будет create an own entity listener resolver, который знает о контейнере (это на самом деле не очень хорошо) и использует его для получения слушателя, когда это необходимо. Существует blog post о способе сделать это.

+0

Спасибо за ваш краткий ответ! Но это не ответ на мою проблему: Мне хорошо известно, что я мог бы использовать сервис и вводить все (также как это делается). Но это то, чего я пытаюсь избежать. См. Новое редактирование ** и ** мое первое предложение в исходном вопросе. – Eddie

+0

Тогда я действительно не понимаю, что вы хотите достичь здесь. Это прослушиватель объектов, прослушивающий события субъекта пользователя. Вот как это должно быть сделано. Если вы не создадите экземпляр вручную, вы должны сделать то же самое, что и контейнер. Вы должны зарегистрировать его в менеджере объектов ASAP, чтобы поймать нужные события. Вы можете попробовать и определить его как [ленивый сервис] (http://symfony.com/doc/current/components/dependency_injection/lazy_services.html), поэтому вместо этого будет создан прокси (но для этого требуется «symfony/proxy-manager» -бридж ') или создать завод. – 1ed

+0

Ну, я вижу, что мое решение выше: оно загружается и вызывается только при необходимости. И поскольку это путь доктрины, это не может быть абсолютно неправильным, верно? Единственная проблема заключается в том, как правильно обращаться к службе 'request'. – Eddie

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

  • Нет связанных вопросов^_^