Встроенные контроллеры Twig вызывают многократное срабатывание событий kernel.request.

В моем проекте Symfony я столкнулся со странной проблемой с kernel.request слушателями событий срабатывает несколько раз, когда встроенные контроллеры Twig используются.

В моем пользовательском прослушивателе событий у меня есть прослушиватель событий, который отправляет ответ о перенаправлении, если существует определенное условие (в данном случае пароль с истекшим сроком действия). Чтобы предотвратить цикл перенаправления, я проверил, были ли мы уже на странице:

if ($event->getRequest()->get('_route') != 'user_change_password') {
    $response = new RedirectResponse($this->router->generate('user_change_password'));
    $event->setResponse($response);
}

Но это не остановило циклы перенаправления. Пока я не добавил ведение журнала, я понятия не имел, что встроенный контроллер вызовет событие kernel.request (это очевидно задним числом, поскольку эти встроенные контроллеры работают, отправляя «подзапрос»). У меня есть один встроенный контроллер в базовом шаблоне ветки, который проверяет наличие предупреждающих сообщений и отображает их.

Учитывая вышеизложенное, как я могу

  1. иметь возможность вставлять динамический контент в базовый шаблон (который расширяют все другие шаблоны), И
  2. прослушиватели событий kernel.request не срабатывают несколько раз.

Несмотря на то, что Symfony предлагает вставлять этот динамический контент в базовые шаблоны с помощью встроенных контроллеров, считается ли это плохой практикой?

Не лучше ли создать расширение Twig для решения этой проблемы? Из того, что я видел, расширения Twig обычно используются только для простых вещей, таких как пример price в кулинарной книге, хотя я не понимаю, почему это не работает для более сложных вещей, связанных с базой данных. Я просто не уверен, как это сделать.

Примеры приветствуются.


Возможно, связано?: Контроллер Symfony выполняется несколько раз


person user5670895    schedule 19.05.2016    source источник
comment
kernel.request запускается для каждого запроса, включая подзапросы, такие как {{ render(controller('...')) }}   -  person Anyone    schedule 20.05.2016
comment
Правильно, это то, что я сказал. Я пытался найти решение проблемы, описанной выше, которую любезно предоставил xabbuh.   -  person user5670895    schedule 20.05.2016


Ответы (1)


Вы можете выполнить перенаправление только в том случае, если прослушиватель событий выполняется для главного запроса:

use Symfony\Component\HttpKernel\HttpKernelInterface;

// ...

if ($event->isMasterRequest() && $event->getRequest()->get('_route') != 'user_change_password') {
    $response = new RedirectResponse($this->router->generate('user_change_password'));
    $event->setResponse($response);
}

Если вы все еще привязаны к Symfony 2.3, вы можете использовать метод getRequestType() для сравнения его возвращаемого значения с константой MASTER_REQUEST из HttpKernelInterface (это то, что isMasterRequest() делает внутри):

use Symfony\Component\HttpKernel\HttpKernelInterface;

// ...

if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType() && $event->getRequest()->get('_route') != 'user_change_password') {
    $response = new RedirectResponse($this->router->generate('user_change_password'));
    $event->setResponse($response);
}
person xabbuh    schedule 19.05.2016
comment
Бинго! Вот такое решение мне нравится: быстро и просто. Спасибо! Однако есть одно но: этот метод, по-видимому, был переименован в $event->getRequestType() в Symfony3. Кроме того, полное пространство имен (для оператора use) — Symfony\Component\HttpKernel\HttpKernelInterface. - person user5670895; 19.05.2016
comment
Я ковырялся в исходниках, и нашел способ попроще. Существует метод события isMasterRequest(), который выполняет точное сравнение requestType в ответе. Не уверен, когда это было добавлено в Symfony, но это предпочтительное решение. - person user5670895; 23.05.2016
comment
Ты прав. Этот метод был представлен в Symfony 2.4. Я снова обновил свой ответ для тех, кто споткнется об этом в будущем. - person xabbuh; 24.05.2016