Skip to content

Прослуховування подій

У поточному макеті відсутня шапка з навігаційним меню, що дозволяє повернутися на головну сторінку або перейти з однієї конференції на іншу.

Додавання шапки веб-сайту

Все, що має бути відображено на всіх веб-сторінках, наприклад шапка сайту, має бути частиною основного базового макета:

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. Диспетчер оголошує про певні події у визначений час, які можуть слухати слухачі. Слухачі — це гачки (англ. hooks), що дозволяють взаємодіяти з внутрішніми механізмами фреймворку.

Наприклад, є деякі події що дозволяють взаємодіяти з життєвим циклом 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
     //  */

В кінці цього кроку веб-сайт повинен виглядати наступним чином:

/
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version