Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Symfony: The Fast Track
  4. Russian
  5. Обработка событий

Обработка событий

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

Добавление шапки сайта

Всё, что необходимо отображать на всех страницах, например, шапка сайта, должно быть частью основного макета:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -14,6 +14,15 @@
         {% endblock %}
     </head>
     <body>
+        <header>
+            <h1><a href="{{ path('homepage') }}">Guestbook</a></h1>
+            <ul>
+            {% for conference in conferences %}
+                <li><a href="{{ path('conference', { id: conference.id }) }}">{{ conference }}</a></li>
+            {% endfor %}
+            </ul>
+            <hr />
+        </header>
         {% block body %}{% endblock %}
     </body>
 </html>

Добавление этого кода в макет означает, что все шаблоны, расширяющие его, должны определить переменную conferences, которую необходимо создать и передать из соответствующих контроллеров.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -29,12 +29,13 @@ class ConferenceController extends AbstractController
     }

     #[Route('/conference/{id}', name: 'conference')]
-    public function show(Request $request, Conference $conference, CommentRepository $commentRepository): Response
+    public function show(Request $request, Conference $conference, CommentRepository $commentRepository, ConferenceRepository $conferenceRepository): Response
     {
         $offset = max(0, $request->query->getInt('offset', 0));
         $paginator = $commentRepository->getCommentPaginator($conference, $offset);

         return new Response($this->twig->render('conference/show.html.twig', [
+            'conferences' => $conferenceRepository->findAll(),
             'conference' => $conference,
             'comments' => $paginator,
             'previous' => $offset - CommentRepository::PAGINATOR_PER_PAGE,

Представьте себе, что нам необходимо обновить десятки контроллеров. И с каждым новым контроллером мы будем вынуждены делать то же самое. Это не очень практично. Должен быть способ лучше.

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

Исследуем события Symfony

В Symfony есть встроенный компонент диспетчера событий (Event Dispatcher). Диспетчер отправляет определённые события в конкретные моменты времени, а обработчики обрабатывают эти события. Обработчики событий позволяют взаимодействовать с внутренностями фреймворка, то есть выполнять некоторый код, в ответ на события, генерируемые в фреймворке.

Например, есть события, которые позволяют взаимодействовать с жизненным циклом HTTP-запросов. При обработке запроса диспетчер генерирует события в следующих случаях: когда создан объект запроса, когда должен быть выполнен контроллер, когда готов HTTP-ответ, либо когда выброшено исключение. Обработчик может реагировать на одно или несколько разных событий, и выполнять некоторую логику в зависимости от контекста события.

События — это то, что помогает фреймворку быть более гибким и многофункциональным. Многие компоненты Symfony, такие как Security, Messenger, Workflow или Mailer, активно используют их.

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

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

Вместо использования конфигурационного файла, описывающего, на какие события должен реагировать обработчик, создайте подписчика. Подписчик — это обработчик со статическим методом getSubscribedEvents(), который возвращает свою конфигурацию. Это позволяет автоматически регистрировать подписчиков в диспетчере Symfony.

Реализация подписчика

Теперь, когда вы всё знаете, используйте бандл maker, чтобы сгенерировать подписчика:

1
$ symfony console make:subscriber TwigEventSubscriber

Команда спросит вас о том, какое событие вы хотите обрабатывать. Выберите событие Symfony\Component\HttpKernel\Event\ControllerEvent, отправляемое непосредственно перед вызовом контроллера. Самое время для определения глобальной переменной conferences, чтобы Twig имел к ней доступ во время отрисовки шаблона контроллером. Обновите вашего подписчика следующим образом:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
--- a/src/EventSubscriber/TwigEventSubscriber.php
+++ b/src/EventSubscriber/TwigEventSubscriber.php
@@ -2,14 +2,25 @@

 namespace App\EventSubscriber;

+use App\Repository\ConferenceRepository;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpKernel\Event\ControllerEvent;
+use Twig\Environment;

 class TwigEventSubscriber implements EventSubscriberInterface
 {
+    private $twig;
+    private $conferenceRepository;
+
+    public function __construct(Environment $twig, ConferenceRepository $conferenceRepository)
+    {
+        $this->twig = $twig;
+        $this->conferenceRepository = $conferenceRepository;
+    }
+
     public function onControllerEvent(ControllerEvent $event)
     {
-        // ...
+        $this->twig->addGlobal('conferences', $this->conferenceRepository->findAll());
     }

     public static function getSubscribedEvents()

Теперь вы можете добавить сколько угодно контроллеров: переменная conferences всегда будет доступна в Twig.

Note

Более производительную альтернативу мы рассмотрим позднее.

Сортировка конференций по годам и городам

Представление списка конференций по годам позволит упростить просмотр. Для получения и сортировки всех конференций мы могли бы создать отдельный метод, однако вместо этого переопределим стандартную реализацию метода findAll(), чтобы данная сортировка применялась всегда по умолчанию:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--- a/src/Repository/ConferenceRepository.php
+++ b/src/Repository/ConferenceRepository.php
@@ -19,6 +19,11 @@ class ConferenceRepository extends ServiceEntityRepository
         parent::__construct($registry, Conference::class);
     }

+    public function findAll(): array
+    {
+        return $this->findBy([], ['year' => 'ASC', 'city' => 'ASC']);
+    }
+
     // /**
     //  * @return Conference[] Returns an array of Conference objects
     //  */

В конце этого шага сайт должен выглядеть следующим образом:

/

Двигаемся дальше

  • Рабочий процесс запроса-ответа в приложениях Symfony;
  • Встроенные HTTP-события в Symfony;
  • Встроенные события Symfony Console.
Previous page Работа с ветками
Next page Жизненный цикл объектов Doctrine
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version

    Symfony 5.4 is backed by

    Peruse our complete Symfony & PHP solutions catalog for your web development needs.

    Peruse our complete Symfony & PHP solutions catalog for your web development needs.

    Make sure your project is risk free

    Make sure your project is risk free

    Version:
    Locale:
    ebook

    This book is backed by:

    see all backers

    Symfony footer

    Avatar of sparrowek, a Symfony contributor

    Thanks sparrowek for being a Symfony contributor

    1 commit • 2 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony