Динамическое построение меню в модульном Laravel-приложении с использованием событий

Модульная архитектура — один из лучших способов поддерживать чистоту и расширяемость кода в больших Laravel-приложениях. Однако с ростом числа модулей часто возникает задача динамического построения пользовательского интерфейса, особенно навигационного меню, которое должно собирать пункты из разных частей системы. В этой статье я покажу элегантный подход к решению этой проблемы с помощью кастомных событий и View composer.

Проблема

В монолитном приложении меню можно просто прописать в шаблоне Blade. Но в модульной системе каждый модуль должен иметь возможность добавить свои пункты в меню, не нарушая работу других модулей. Жёсткая привязка к шаблонам приводит к хрупкости и усложнению поддержки.

Решение: событийный подход

Идея проста: мы создаём специальное событие BuildingMenu, которое собирает пункты меню от всех заинтересованных модулей. Затем через View composer передаём собранное меню в шаблон.

Шаг 1: Класс события BuildingMenu

<?php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class BuildingMenu
{
    use Dispatchable, SerializesModels;

    private array $items = [];

    public function addItem(array $item): void
    {
        $this->items[] = $item;
    }

    public function getItems(): array
    {
        return $this->items;
    }
}

Класс выполняет две функции:

  • Является событием (через трейты Dispatchable, SerializesModels).
  • Служит контейнером для пунктов меню (методы addItem и getItems).

Обратите внимание: массив $items инициализирован как пустой, чтобы избежать ошибок при отсутствии пунктов.

Шаг 2: View composer для передачи меню в шаблон

<?php

use App\Events\BuildingMenu;
use Illuminate\Support\Facades\View;

View::composer('welcome', function ($view) {
    $buildingMenu = new BuildingMenu();
    event($buildingMenu);

    $view->with('buildingMenu', $buildingMenu);
});

View composer связывается с шаблоном welcome (или любым другим). При каждом рендеринге этого шаблона:

  • Создаётся экземпляр BuildingMenu.
  • Запускается событие event($buildingMenu), которое уведомляет всех слушателей.
  • Объект меню передаётся в шаблон как переменная $buildingMenu.

Шаг 3: Слушатель события, добавляющий пункты

<?php

use App\Events\BuildingMenu;
use Illuminate\Support\Facades\Event;

Event::listen(BuildingMenu::class, function (BuildingMenu $event) {
    $event->addItem([
        'text' => 'Счета',
        'url'  => 'invoices.index',
        'icon' => 'fas fa-file-invoice-dollar',
        'can'  => 'view_invoices', // Проверка прав через Gate
    ]);
});

Это пример слушателя, который может быть размещён в сервис-провайдере модуля. Он добавляет пункт «Счета» с иконкой, маршрутом и проверкой прав (ключ can позволяет скрыть пункт у пользователей без соответствующего разрешения).

Как это работает в модульной системе

Каждый модуль регистрирует своего слушателя в своём сервис-провайдере:

<?php

namespace Modules\Invoices\Providers;

use Illuminate\Support\ServiceProvider;
use App\Events\BuildingMenu;
use Illuminate\Support\Facades\Gate;

class InvoicesServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Event::listen(BuildingMenu::class, function (BuildingMenu $event) {
            if (Gate::allows('view_invoices')) {
                $event->addItem([
                    'text' => 'Счета',
                    'url'  => 'invoices.index',
                    'icon' => 'fas fa-file-invoice-dollar',
                ]);
            }
        });
    }
}

Таким образом, модуль ничего не знает о других модулях, но вносит свой вклад в общее меню. При добавлении нового модуля нужно лишь зарегистрировать его провайдер в config/app.php — меню автоматически пополнится.

Расширение функциональности

Класс BuildingMenu можно улучшить, добавив:

  • Группировку пунктов (например, выпадающие подменю).
  • Сортировку по приоритету.
  • Кэширование собранного меню (чтобы не строить его при каждом запросе).

Пример с группировкой:

<?php

$event->addItem([
    'text'    => 'Финансы',
    'icon'    => 'fas fa-wallet',
    'submenu' => [
        ['text' => 'Счета', 'url' => 'invoices.index'],
        ['text' => 'Платежи', 'url' => 'payments.index'],
    ],
]);

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

Достоинства подхода
  • Модульность: каждый модуль управляет своими пунктами независимо.
  • Тестируемость: легко писать тесты для слушателей событий.
  • Гибкость: пункты могут зависеть от прав пользователя, конфигурации, состояния приложения.
  • Чистота шаблонов: в Blade остаётся только простой цикл по пунктам, без логики.
Недостатки
  • Небольшое увеличение сложности (нужно создать событие и View composer).
  • Требуется внимательно следить за производительностью, если пунктов очень много (можно добавить кэширование).

Заключение

Использование событий для построения меню превращает навигацию из статического элемента в динамическую, расширяемую систему. Такой подход особенно полезен в больших приложениях с командной разработкой, где несколько программистов работают над разными модулями одновременно. Он снижает связанность (coupling) и повышает связность (cohesion) кода, следуя принципам SOLID.

Внедрение описанного механизма займёт всего несколько часов, но сэкономит много времени в будущем при добавлении новых модулей и изменении структуры меню. Laravel с его мощной системой событий и сервис-контейнером идеально подходит для реализации подобных архитектурных паттернов.

PHP и его фреймворки

Фреймворк(дословный перевод – рабочая рамка) – это набор функционала, который используется с проекта в проект. В современном мире знания языка недостаточно для звания “программист”, еще нужно уметь хотя б в один популярный фреймворк. В этой статье я кратко опишу самые популярные для php фреймворки.

Symfony

Symfony – это высокопроизводительный PHP-фреймворк, который используется для создания веб-приложений любой сложности. Он имеет широкий набор инструментов и компонентов, которые позволяют разработчикам создавать приложения с высокой степенью гибкости и расширяемости. Symfony также имеет большое сообщество разработчиков, которое активно поддерживает и развивает этот фреймворк.

Достоинства:
  • Конфигурация и настройка фреймворка легко производится с помощью встроенного инструмента – Symfony Console.
  • Имеет готовый набор библиотек для работы с БД, тестирования и других операций.
  • Шаблонизатор Twig позволяет создавать качественный HTML-код с меньшими усилиями.
  • Внутренняя команда Symfony использует реактивный подход к программированию, что позволяет улучшить производительность приложения.
Недостатки:
  • Для начала работы с Symfony требуется изучение дополнительных инструментов и концепций.
  • Фреймворк имеет большой размер, что может замедлять работу приложения в случае недостаточных ресурсов сервера.

Laravel

Laravel – это очень популярный PHP-фреймворк, который используется для создания веб-приложений. Он имеет элегантный и простой синтаксис, который позволяет разработчикам быстро создавать приложения. Laravel также имеет широкий набор инструментов и компонентов, которые облегчают работу разработчикам и позволяют им создавать приложения с меньшим количеством кода.

Достоинства:
  • Фреймворк имеет интуитивно понятный синтаксис, что делает его простым для использования.
  • Инструмент artisan позволяет быстро генерировать различные компоненты и структуры приложения.
  • Огромное сообщество разработчиков Laravel, которые поддерживают и развивают этот фреймворк.
  • Шаблонизатор Blade удобен для создания HTML-кода.

Статьи:

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

CodeIgniter

CodeIgniter – это легкий PHP-фреймворк, который используется для создания быстрых и масштабируемых веб-приложений. Он имеет минимальную конфигурацию и не требует специальных навыков для начала работы. CodeIgniter также имеет множество полезных функций и компонентов, которые помогают разработчикам создавать качественные приложения.

Достоинства:
  • Легкий и быстрый фреймворк, который позволяет создавать веб-приложения любой сложности.
  • Множество полезных функций и компонентов, включая систему маршрутизации и библиотеку для работы с базами данных.
  • Интуитивно понятный синтаксис, который делает его простым для использования.
  • Поддержка различных модулей, которые расширяют функциональность фреймворка.
Недостатки:
  • Отсутствие стандартной ORM библиотеки может усложнить работу с базами данных.
  • Не имеет встроенной поддержки для многопоточности и асинхронности, что может быть неудобно для создания приложений с большой нагрузкой.

Yii2

Yii2 является одним из наиболее популярных PHP-фреймворков. Он предоставляет мощные инструменты для создания веб-приложений любого уровня сложности, включая масштабные проекты. Yii2 имеет множество функций, таких как автоматическая генерация кода, миграции базы данных, кэширование, поддержку шаблонов и многое другое.

Достоинства:
  • Простота и интуитивно понятный синтаксис.
  • Мощные инструменты для создания сложных приложений.
  • Высокая производительность и оптимизированная работа с базами данных.
  • Активное сообщество пользователей и разработчиков.
  • Поддержка RESTful API.
Недостатки:
  • Относительно небольшое сообщество по сравнению с Symfony и Laravel.
  • Некоторые функции могут быть сложными для понимания для начинающих разработчиков.

Сравнение с Yii1: Yii2 был выпущен в 2014 году и представляет собой обновленную версию Yii1. Он имеет множество новых функций, более быструю производительность и оптимизированную работу с базами данных. Однако, многие основные принципы остались прежними, такие как использование MVC-архитектуры и гибкость в настройке.

Заключение

“На вкус и цвет…” – каждый сам в праве выбирать фреймворк для проекта и работы. Но я, как хлебнувший нескольких, скажу что Laravel наиболее удобный – может это действительно так, а может я не распробовал прочие… Скажу, что Laravel был третьим по порядку в моей дегустации.