Skip to Content
Разработка модулейAPI маршрутизатора

API маршрутизатора

API маршрутизатора Flute CMS построен на базе Symfony Routing с дополнительными возможностями. Поддерживается как атрибутная маршрутизация, так и программное создание маршрутов.

Получение роутера

<?php use Flute\Core\Router\Router; // Через DI контейнер $router = app(Router::class); // Через хелпер $router = router();

Создание маршрутов

Базовые HTTP методы

<?php // GET запрос router()->get('/users', [UserController::class, 'index']); // POST запрос router()->post('/users', [UserController::class, 'store']); // PUT запрос router()->put('/users/{id}', [UserController::class, 'update']); // DELETE запрос router()->delete('/users/{id}', [UserController::class, 'destroy']);

Дополнительные методы

<?php // Множественные HTTP методы router()->match(['GET', 'POST'], '/contact', [ContactController::class, 'handle']); // Любой HTTP метод router()->any('/webhook', [WebhookController::class, 'handle']); // Статические страницы (возвращает view) router()->view('/about', 'pages.about', ['title' => 'О нас']); // Редирект router()->redirect('/old-url', '/new-url', 301);

Именованные маршруты

<?php router()->get('/news', [NewsController::class, 'index']) ->name('news.index'); router()->get('/news/{id}', [NewsController::class, 'show']) ->name('news.show'); // Использование имени для генерации URL $url = route('news.show', ['id' => 123]); // Результат: /news/123

Middleware

<?php // Один middleware router()->post('/news', [NewsController::class, 'store']) ->middleware('auth') ->name('news.store'); // Несколько middleware router()->put('/news/{id}', [NewsController::class, 'update']) ->middleware(['auth', 'csrf', 'can:edit_news']) ->name('news.update');

Группы маршрутов

<?php // Группа с общим префиксом и middleware router()->group(['prefix' => '/admin', 'middleware' => ['auth', 'admin']], function () { router()->get('/news', [AdminNewsController::class, 'index']); router()->post('/news', [AdminNewsController::class, 'store']); router()->get('/news/{id}', [AdminNewsController::class, 'edit']); }); // Вложенные группы router()->group(['prefix' => '/api'], function () { router()->group(['prefix' => '/v1', 'middleware' => 'throttle:100,1'], function () { router()->get('/users', [ApiUserController::class, 'index']); router()->get('/users/{id}', [ApiUserController::class, 'show']); }); });

Атрибутная маршрутизация

Автоматическая загрузка

Маршруты из атрибутов загружаются автоматически при вызове bootstrapModule() или loadRouterAttributes() в провайдере:

<?php // В провайдере public function boot(\DI\Container $container): void { $this->bootstrapModule(); // Включает loadRouterAttributes() }

Ручная регистрация

<?php // Регистрация из директории $router->registerAttributeRoutes( [app_path('Modules/News/Controllers')], 'Flute\\Modules\\News\\Controllers' ); // Регистрация из конкретного класса $router->registerAttributeRoutesFromClass(NewsController::class);

Встроенные middleware

Алиасы

АлиасКлассОписание
authIsAuthenticatedMiddlewareПроверка аутентификации
guestIsGuestMiddlewareТолько для гостей
canCanMiddlewareПроверка разрешений
csrfCsrfMiddlewareCSRF защита
htmxHtmxMiddlewareHTMX запросы
throttleRateLimiterMiddlewareОграничение частоты
tokenTokenMiddlewareAPI токены
ban.checkBanCheckMiddlewareПроверка блокировки
maintenanceMaintenanceMiddlewareРежим обслуживания

Группы

<?php // Встроенные группы middleware 'web' => ['csrf', 'throttle'], 'api' => ['throttle', 'ban.check'], 'default' => ['ban.check', 'throttle', 'maintenance'],

Группа default добавляется ко всем маршрутам автоматически.

Middleware с параметрами

<?php // Проверка разрешения router()->get('/admin/users', [AdminController::class, 'users']) ->middleware('can:admin.users'); // Ограничение частоты: 100 запросов в минуту router()->get('/api/data', [ApiController::class, 'data']) ->middleware('throttle:100,1');

Регистрация своих middleware

Регистрация алиаса

<?php // Регистрация своего middleware router()->aliasMiddleware('blog.owner', BlogOwnerMiddleware::class); // Использование router()->put('/blog/{id}', [BlogController::class, 'update']) ->middleware('blog.owner');

Регистрация группы

<?php router()->middlewareGroup('blog', [ 'auth', 'blog.owner', 'throttle:10,1' ]); // Использование группы router()->group(['middleware' => 'blog'], function () { router()->put('/blog/{id}', [BlogController::class, 'update']); router()->delete('/blog/{id}', [BlogController::class, 'destroy']); });

Создание middleware

<?php namespace Flute\Modules\Blog\Middlewares; use Closure; use Flute\Core\Router\Contracts\MiddlewareInterface; use Flute\Core\Support\FluteRequest; use Symfony\Component\HttpFoundation\Response; class BlogOwnerMiddleware implements MiddlewareInterface { /** * Обработка запроса * * @param FluteRequest $request Текущий запрос * @param Closure $next Следующий обработчик * @param mixed ...$args Дополнительные аргументы */ public function handle(FluteRequest $request, Closure $next, ...$args): Response { // Получаем ID статьи из параметров маршрута $blogId = $request->getAttribute('id'); if (!$blogId) { return response()->error(400, 'ID статьи не указан'); } // Проверяем существование и владельца $blog = \Flute\Modules\Blog\Database\Entities\Article::findByPK($blogId); if (!$blog) { return response()->error(404, 'Статья не найдена'); } if ($blog->author_id !== user()->id && !user()->can('admin.blog')) { return response()->error(403, 'Доступ запрещён'); } // Передаём управление дальше return $next($request); } }

Генерация URL

Основные методы

<?php // Через хелпер (рекомендуется) $url = route('news.show', ['id' => 123]); // Через роутер $url = router()->url('news.show', ['id' => 123]);

Примеры

<?php // Простой маршрут без параметров $homeUrl = route('home'); // Результат: / // С параметром в пути $newsUrl = route('news.show', ['id' => 123]); // Результат: /news/123 // С несколькими параметрами $articleUrl = route('blog.article', ['category' => 'php', 'slug' => 'my-article']); // Результат: /blog/php/my-article // С query параметрами $searchUrl = route('search') . '?' . http_build_query(['q' => 'flute', 'page' => 2]); // Результат: /search?q=flute&page=2

Проверка существования

<?php // Проверка существования маршрута по пути if (router()->hasRoute('/news', ['GET'])) { echo "Маршрут существует"; } // Проверка по имени if (router()->getRoutes()->get('news.show')) { $url = route('news.show', ['id' => 123]); }

Вспомогательные методы

<?php // Получение текущего маршрута $currentRoute = router()->getCurrentRoute(); // Получение всех маршрутов $allRoutes = router()->getRoutes();

События маршрутизации

Router отправляет события в процессе работы:

<?php use Flute\Core\Router\Events\RoutingStartedEvent; use Flute\Core\Router\Events\OnRouteFoundEvent; use Flute\Core\Router\Events\RoutingFinishedEvent; // При инициализации роутера events()->addListener(RoutingStartedEvent::NAME, function($event) { // Роутер начал обработку }); // При нахождении маршрута events()->addListener(OnRouteFoundEvent::NAME, function($event) { $route = $event->getRoute(); $request = $event->getRequest(); // Можно модифицировать запрос или добавить логику }); // После обработки запроса events()->addListener(RoutingFinishedEvent::NAME, function($event) { // Роутер завершил обработку });

Кеширование

Router автоматически кеширует скомпилированные маршруты:

storage/app/cache/routes_compiled_front.php - фронтенд маршруты storage/app/cache/routes_compiled_admin.php - админ маршруты

В debug режиме кеш автоматически инвалидируется. В production кеш сохраняется до изменения файлов маршрутов.

Лучшие практики

Именуйте маршруты

Всегда используйте понятные имена с точечной нотацией:

->name('news.show') // Хорошо ->name('show_news') // Плохо

Группируйте по модулям

Начинайте имена с названия модуля для избежания конфликтов.

Используйте middleware

Всегда добавляйте проверку прав и CSRF защиту:

router()->post('/news', [NewsController::class, 'store']) ->middleware(['auth', 'csrf', 'can:create_news']);

Структурируйте группы логически

router()->group(['prefix' => '/news'], function () { // Публичные маршруты router()->get('/', [NewsController::class, 'index'])->name('news.index'); router()->get('/{id}', [NewsController::class, 'show'])->name('news.show'); // Защищённые маршруты router()->group(['middleware' => 'auth'], function () { router()->post('/', [NewsController::class, 'store'])->name('news.store'); router()->put('/{id}', [NewsController::class, 'update'])->name('news.update'); }); });

Минимизируйте middleware

Для часто используемых маршрутов избегайте избыточных middleware.