in Профессиональное

Symfony2: аналог preExecute() для контроллера

Я думаю многих смущает отсутствие preExecute в стандартном контроллере Symfony2. Ниже я приведу возможное решение данного вопроса при помощи внедрения зависимости через Service Container (Оригинал подсмотрен у Szymon Szewczyk).

UPDATE 20 января 2012: статья обновлена в соответствии с современными реалиями SF 2.0.9 (фактически изменения коснулись именования тага и события)

Итак, начнем с определения службы:

YAML:

# Vendor\MyBundle\Resources\config.yml
services:
    # ...
    preexecute.listener:
        class: Vendor\MyBundle\Listener\PreExecuteListener
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

XML:

# Vendor\MyBundle\Resources\config.xml
        <service id="kernel.listener.pre_execute" class="Vendor\MyBundle\Listener\PreExecuteListener">
            <tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" priority="0"/>
        </service>

Создадим также определение нашей службы в положенном ей месте:

// Vendor\MyBundle\Listener\PreExecuteListener.php
 
namespace Vendor\MyBundle\Listener;
 
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
 
class PreExecuteListener
{
  public function onKernelController(FilterControllerEvent $event)
  {
    if (HttpKernelInterface::MASTER_REQUEST === $event-&gt;getRequestType()){
      $controllers = $event-&gt;getController();
      // контроллер должен существовать
      if (isset($controllers[0])){
        $controller = $controllers[0];
        // метод должен существовать
        if(method_exists($controller, 'preExecute')){
          $controller-&gt;preExecute();
        }
      }
    }
  }
}

Вот и все! ) Теперь в нужном контроллере объявляем метод preExecute() и наслаждаемся нашими танцами с бубном )

Write a Comment

Comment

*

20 Comments

  1. А почему только для мастера вызываем?
    Что обычно принято складывать в preExecute?

    • Насчет принято – не скажу, ибо не знаю, а вот лично за себя могу сказать что иногда удобно инициализировать ряд переменных, которые используются во многих действиях, к примеру (получить логгер, или репозиторий).

    • Попробуйте, я несколько недель назад (до этой статьи) пробовал, но у меня не вышло, так как в момент вызова конструктора контейнер не инициализирован (по сути получается что это чуть больше чем стандартный PHP объект в этот момент). Однако если содержимое контейнера не нужно или его таки можно заполучить, то это сработает.

      Если получится – отпишите комментарий )

      • Не думаю, что возможно. $myController->setContainer() вызывается после конструктора. Стало быть в конструкторе тот же EntityManager (репозиторий ведь через него получаем?) мы не увидим.

        Как вариант можно так:

        setContainer(ContainerInterface $container)
        {
            $this-&gt;repo =  $container-&gt;get('em')-&gt;getRepo('Foo');
         
            return parent::setContainer($container);
        }
        • оу, щи. Заэскейпилось. Предпросмотр не помешал бы. Что там с моей учеткой, кстати?)

          а вообще я пока не уверен, что буду использовать еще какие-то поля внутри контроллеров. Просто буду напрямую из контейнера все дергать, да и все. Ну может быть сделаю хелпер-методы в стиле getEntityManager($name = ‘read’).

          • Спасибо. Но оно все равно требует капчу.

            Про wp – не знаю, никогда блогов не вел. Только комменты пишу.

          • Странно, я тебя в юзерах не вижу, ты точно зарегался? )

          • О, добавил тебя к блогу, отпиши помогло или нет )

          • да, спасибо. Теперь без капчи

  2. А еще можно сделать попроще и поменьше кода, объявив контроллеры как службы:

    • Код увы не запостился. Я пока не понял смысла объявлять контроллер сервисом. Может приведете пример еще раз? Или на мыло скиньте, я в комент вставлю.

  3. сейчас отправлю почтой, а то тут что-то неладное, можно все комменты мои удалить последующие

    • Надо <pre> писать. Можно добавить атрибут lang=”php” например. И желательно эскейпеный текст вставлять, добавляя атрибут escaped=”true” (у меня стоит плагин WP-Syntax)

  4. <service id="demo.controller" class="%demo.controller.class%" scope="request">
        <call method="setContainer">
            <argument type="service" id="service_container" />
        </call>
        <call method="preExecute"></call>
    </service>
  5. Можно закрыть нужные методы контроллера и проводить инициализацию через __call.