Все мы используем простой синтаксис Route::get()
и Route::post()
, но в больших проектах это делать сложнее. В этой статье собраны несколько советов для различных ситуаций.
Совет 1. Route::get() ДО Route::resource()
Для Ресурсных контроллеров это одна из самых распространенных ошибок — смотрим пример:
Route::resource('photos', 'PhotoController'); Route::get('photos/popular', 'PhotoController@method');
Второй маршрут будет неточным, знаете почему? Потому, что он будет соответствовать методу show()
из Route::resource()
— соответственно /photos/{id}
, который назначит popular
в качестве параметра $id
.
Поэтому, если вы хотите добавить любой get/post маршрут, в дополнение к Route::resource()
, то размещайте их ДО ресурса. Например так:
Route::get('photos/popular', 'PhotoController@method'); Route::resource('photos', 'PhotoController');
Совет 2. Группа в другой группе
Практически все мы знаем, что можно группировать маршруты с помощью Route::group()
и назначать различные мидлвары/префиксы и другие параметры.
А что делать, если нужен определенный набор правил для подгрупп этих групп?
Типичный пример: есть публичные и аутентифицированные маршруты, но в пределах группы с аутентификацией вам нужно отделить администраторов от обычных пользователей.
Можно сделать это так:
// публичные маршруты Route::get('/', 'HomeController@index'); // Зарегистрированные пользователи - мидлвар «auth» Route::group(['middleware' => ['auth']], function () { // /user/XXX: В дополнении к «auth», эта группа использует мидлвар «simple_users» Route::group(['middleware' => ['simple_users'], 'prefix' => 'user'], function () { Route::resource('tasks', 'TaskController'); }); // /admin/XXX: В этой группе не будет «simple_users», но будут «auth» и «admins» Route::group(['middleware' => ['admins'], 'prefix' => 'admin'], function () { Route::resource('users', 'UserController'); }); });
Совет 3. Валидация параметров маршрута — мультиязычный пример
Типичный случай — префикс маршрутов, зависящий от локали, например, fr/blog
и en/article/333
. Как мы можем гарантировать, что две первые буквы будут использоваться только для переключения языка? А мы можем их проверить прямо в маршруте, с помощью параметра where
:
Route::group(['prefix' => '{locale}', 'where' => ['locale' => '[a-zA-Z]{2}']], function () { Route::get('/', 'HomeController@index'); Route::get('article/{id}', 'ArticleController@show'); });
Основная часть — 'where' => ['locale' => '[a-zA-Z]{2}']
, где мы используем регулярное выражение для сопоставления только двухбуквенных комбинаций.
Совет 4. Динамическая маршрутизация субдомены
Это есть в официальной документации Laravel, но используется редко, поэтому я решил рассказать об этом.
Если у вас есть динамические субдомены, например, отдельный для каждого пользователя, то он должен быть переменной, верно? Laravel делает это автоматически. Смотрим пример:
Route::domain('{account}.myapp.com')->group(function () { Route::get('user/{id}', function ($account, $id) { // }); });
Обратите внимание, что {account}
автоматически передается как параметр $account
во все методы контроллера, поэтому не забудьте её принять в каждом их них.
Совет 5. Будьте осторожны с неанглийской привязкой модели маршрута
Иногда URL-адреса должны содержать неанглийские слова. Например, у вас есть портал для книг на испанском языке, и вы хотите, чтобы у списка книг был URL /libros
, а у отдельной книги — /libros/1
, как в обычном ресурсном контроллере.
Но в базе данных все имена должны быть на английском языке, чтобы «магия» Laravel могла работать с единственным и множественным числом, верно?
И, когда вы создаете модель Book
с Миграцией и Контроллером, то используете эту команду:
php artisan make:model Book -mcr
Ключ -mcr
генерирует Модель и ресурсный Контроллер. В этом контроллере у вас будет:
/** * Display the specified resource. * * @param \App\Book $book * @return \Illuminate\Http\Response */ public function show(Book $book) { // ... }
Но в вашем routes/web.php
у вас сделано так:
Route::resource('libros', 'BookController');
Проблема в том, что это не заработает. Еще большая проблема в том, что не выдаст никакой ошибки, просто $book
будет пустым, и вы не поймете, почему.
Согласно официальному описанию контроллера ресурсов, имя переменной должно совпадать с параметром в единственном числе:
// Поэтому вместо public function show(Book $book) { // ... } // нужно сделать public function show(Book $libro) { // ... }
Но, честно говоря, в неанглийских проектах я бы рекомендовал вообще не использовать Route::resource
и Привязку Модели к Маршруту.
«Магия» слишком непредсказуема. Например, как бы Laravel догадался бы, что единственное число от «libros» — это «libro»?
Совет 6. Маршруты API — из V1 в V2
Представьте, что вы работаете с API-проектом, и вам необходимо выпустить его новую версию. Старые конечные точки останутся по адресу api/[что-то-там]
, а для новой версии вы будете использовать api/V2/[что-то-там]
.
Вся логика app/Providers/RouteServiceProvider.php
:
public function map() { $this->mapApiRoutes(); $this->mapWebRoutes(); // ... } protected function mapWebRoutes() { Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php')); } protected function mapApiRoutes() { Route::prefix('api') ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php')); }
Как видите, API-маршруты регистрируются в отдельной функции с префиксом api/
.
Итак, если вы хотите создать группу маршрутов V2, то вы можете создать отдельный файл routes/api_v2.php
и сделать так:
public function map() { // ... старый функции $this->mapApiV2Routes(); } // И новая функция protected function mapApiV2Routes() { Route::prefix('api/V2') ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api_v2.php')); }
Таким образом, и старые маршруты не поломаются, и вы легко создадите новый набор маршрутов.
Совет 7. Ограничение скорости — глобальное и для Гостей/Пользователей
Это также есть в официальной документации, но не так подробно.
Во-первых, вы можете ограничить некоторые URL-адреса для вызова максимум 60 раз в минуту, с помощью throttle:60,1
.
Route::middleware('auth:api', 'throttle:60,1')->group(function () { Route::get('/user', function () { // }); });
А вы знали, что можно это сделать отдельно для гостей и залогиненных пользователей?
// максимум 10 запросов в минуту для гостей и 60 для пользователей Route::middleware('throttle:10|60,1')->group(function () { // });
Также вы можете создать в БД поле users.rate_limit
и ограничить запросы для конкретного пользователя:
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () { Route::get('/user', function () { // }); });
Совет 8. Список Маршрутов и Кеширование Маршрутов
Последний совет — как проверить существующие маршруты.
Не все знают, какие именно маршруты скрыты в Route::resource()
или в более сложной Route::group
.
Но в любой момент вы можете это узнать с помощью artisan-команды:
php artisan route:list
Имейте в виду, что если вы используете кэширование маршрутов, то после каждого изменения маршрутов вам нужно запускать команду:
php artisan route:clear
Автор: Povilas Korop
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.