Маршрутизация:

Содержание:


Базовая маршрутизация:

Самый базовый маршрут для Ларавел принимает URL и возвращает функцию. Например, несколько слов в виде приветсвия:

Route::get('foo', function () {
    return 'Привет мир!';
});

Стандартный файл маршрутизации:

Все маршруты определены в файлах, которые располагаются в специализированной директории routes. Эти файлы загружаются фреймворком автоматически.

Для большинства типовых приложений, пути определены в файле web.php. Получить доступ можно просто набрав указанный URL в браузере. Например, наберите http://your-app.test/user в браузере, чтобы получить доступ к указанному пути:

Route::get('/user', 'UserController@index');

Пути, которые определены в файле api.php сгруппированы RouteServiceProvider. Префикс применяется автоматически и его не нужно переопределять для каждого маршрута. Префикс и другие параметры можно изменить в классе RouteServiceProvider.

Доступные методы:

Маршрутизатор позволяет регистрировать пути, которые отвечают на любую HTTP команду:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

Может возникнуть необходимость зарегистрировать маршрут, который отвечает на несколько команд одновременно. В этом случае, можно использовать метод match или any.

Route::match(['get', 'post'], '/', function () {
    //
});

Route::any('/', function () {
    //
});

CSRF Защита:

Любая HTML форма, которая отправляет даные методом POST, PUT или DELETE должна включать поле CSRF токена. В противном случае, запрос будет отклонён. Подробнее про CSRF защиту можно узнать в этом разделе. Пример CSRF поля:

<form method='POST' action='/profile'>
    @csrf
    ...
</form>

Перенаправление:

Можно использовать метод Route::redirect, чтобы перенаправить с одного адреса на другой. Этот метод дасть возможность перенаправить запрос без использования контроллера или чего-либо ещё:

Route::redirect('/here', '/there');

По умолчанию Route::redirect возвращает код 302. Это значение можно переопределить 3-м параметром:

Route::redirect('/here', '/there', 301);

Чтобы получить 301 код по умолчанию, можно использовать метод Route::permanentRedirect:

Route::permanentRedirect('/here', '/there');

Ссылка на представление:

Если необходимо вернуть представление, можно использовать метод Route::view. Как и в случае с перенаправлением, токой метод позволит вернуть представление без контроллера и чего-либо ещё. Первым параметром нужно указать адрес, вторым параметром представление. Дополнительно можно указать набор данных третьим параметром.

Route::view('/welcome', 'welcome');

Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

Параметры маршрута:

Требуемые параметры:

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

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

Можно определять любое количество параметров в маршруте:

Route::get('posts/{post}/comments/{comment}',
    function ($postId, $commentId) {
    //
});

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

Необязательные параметры:

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

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

Ограничение через регулярные выражения:

Вы можете ограничить формат параметров маршрута используя where метод. Берём заданный параметр, а регулярное выражение определяет какие ограничение у параметра могут быть:

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

Глобальные ограничения:

Если необходимо сделать так, чтобы параметры маршрута всегда были ограничены регулярными выражениями, то нужно использовать паттерн. Определить паттерн для метода boot можно в RouteServiceProvider:

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    Route::pattern('id', '[0-9]+');

    parent::boot();
}

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

Route::get('user/{id}', function ($id) {
    // Only executed if {id} is numeric...
});

Закодированные прямы слеши:

Компонент маршрутизации позволяет работать со всеми символами, кроме прямых слешей /. Чтобы их спользовать, необходимо явно разрешить их использование через регулярные выражения в условии where.

Route::get('search/{search}', function ($search) {
    return $search;
})->where('search', '.*');
Закодированные прямые слеши поддерживаются только для последнего сегмента.

Имя маршрута:

Имена маршрутов — это удобный способ работать с генерацией URL или редиректами. Вы можете указать имя маршрута через метод name в определении:

Route::get('user/profile', function () {
    //
})->name('profile');

Также можно указывать имя для действия контроллера:

Route::get('user/profile', 'UserProfileController@show')
        ->name('profile');

Формирование URL для названных маршрутов:

После того, как вы назвали маршрут, можно сгенерировать URL путём обращения к имени через глобальную функцию route.

// Generating URLs...
$url = route('profile');

// Generating Redirects...
return redirect()->route('profile');

Если в названном маршруте определны парамтры, то можно передать значение через второй параметр функции. Такие параметры автоматически будут включены в URL в нужной позиции.

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1]);

Проверка текущего маршрута:

Если нужно определить, соответсвует текущий запрос имени маршрута, можно использовать метод named. Например, проверить запрос в промежуточном слое можно так:

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if ($request->route()->named('profile')) {
        //
    }

    return $next($request);
}

Сгруппированные маршруты:

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

Кластеры дают возможность гибко управлять атрибутами. Можно объединить условия или промежуточный слой, в то время как простарство имён, имена и префиксы можно разделить. Разделители в прострастве имён и слеши автоматически добавляются в URL префиксы там, где необходимо.

Промежуточный слой:

Чтобы вписать промежуточный слой ко всей группе маршрутов, необходимо использовать метод middleware перед определением группы. Порядок выолнения соответсвует данным, указанным в массиве.

Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // Uses first & second Middleware
    });

    Route::get('user/profile', function () {
        // Uses first & second Middleware
    });
});

Пространство имён:

Ещё один распространённый случай использования групп для маршрутов — это назначение простраства имён к группе контроллеров с помощью метода namespace.

Route::namespace('Admin')->group(function () {
    // Controllers Within The "App\Http\Controllers\Admin" Namespace
});

По умолчанию, RouteServiceProvider включает файл маршрута с простаранством имён, что позволяет обращаться к контроллеру без детализации полного App\Http\Controllers пути. Поэтому, детализировать необходимо лишь оставшуюся часть:

Субдоменная маршрутизация:

Группирование может быть также использовано для субдоменных маршрутов. Параметры маршрута можно прописывать таким же образом, как и для URL-адреса. Для этого необходимо использовать метод domain перед определением группы.

Route::domain('{account}.myapp.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});
Необходимо регистрировать маршрут субдомена до регистрации путей основного домена для того, чтобы гарантировать доступность субдомена. Это позволит исключить наложение путей.

Префиксы маршрутов:

Метод prefix используется для того, чтобы назначить префикс в группе для каждого конкретного URL. Например, все следующие маршруты имеют префикс admin:

Route::prefix('admin')->group(function () {
    Route::get('users', function () {
        // Matches The "/admin/users" URL
    });
});

Префиксы имени маршрутов:

Метод name можно использовать для того, чтобы назначить префикс к каждому имени маршрута в данной группе. Например, можно назначить префикс ко всем маршрутам сгруппированных по имени и начинающийхся с admin. Префикс берётся в точности, как указан. Поэтому убедитесь в том, что точка . включена в указанный префикс:

Route::name('admin.')->group(function () {
    Route::get('users', function () {
        // Route assigned name "admin.users"...
    })->name('users');
});

Связь маршрута и модели:

При введение идентификатора модели в маршрут или действие контроллера, необходимо убедиться в том, что модель соответсвует идентификатору. Связь маршрута и модели в Ларавел даёт возможность автоматически внедрять модели в маршрут. Например, вместо того чтобы внедрять идентификатор пользователя, можно внедрить модель, которая будет соответствовать данному идентификатору.

Неявная привязка:

Модели Eloquent, которые определены в маршрутах или действиях котроллерах, соответсвуют имени переменной, указанной в сегменте маршрута. Например:

Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

Переменная $user вписана как App\User модель Eloquent и имя переменной соотвествует имени сегмента {user}, Laravel автоматически введёт сущность модели, которая совпадает по идентификатору и щзначение из запроса. В случае, если не удастся найти соответсвующую модель в базе данных, 404 HTTP ответ сгенерируется автоматически.

Настройка имени ключа:

Чтобы связать модель не с идентификатором, а другим столбцом из базы данных, необходимо перезаписать поле в модели Eloquent методом getRouteKeyName:

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

Явная привязка:

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

public function boot()
{
    parent::boot();

    Route::model('user', App\User::class);
}

После определите маршрут, который содержит парметр {user}.

Route::get('profile/{user}', function (App\User $user) {
    //
});

После того как мы привязали все параметры к модели App\User, модель будет внедрена в путь. Поэтому запрос profile/1 внедрит модель User из базы данных с идентификатором 1.

Если указанному идентификатору не найдётся записть в базе данных, то HTTP ответ 404 сгенерируется автоматически.

Настройка логики принятия решений:

Если вы хотите использовать свою логику работы, то используйте Route::bind метод. В результате чего, вы сможете получить сущность класса, которая должна быть внедрена в маршрут.

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Route::bind('user', function ($value) {
        return App\User::where('name', $value)->first() ?? abort(404);
    });
}

Как альтернатива, можно перезаписать метод resolveRouteBinding в Eloquent модели. Этот метод получит значение сегмента и вернёт объект, который и будет внедрён в маршрут.

/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value)
{
    return $this->where('name', $value)->first() ?? abort(404);
}

Маршруты ошибки:

Если ни один из маршрутов не соответствует запросу, то можно испоьзовать метод Route::fallback, чтобы определить порядок действий в этом случае. По умолчанию, такие запросы автоматически сгенерируют ответ ввиде страницы 404, и не приведит к ошибке приложеиня. После того, как вы определили правила поведения в routes/web.php файле, все запросы будут следовать этой логике. Вы можете добавить обработчик в промежуточном слое по желанию:

Route::fallback(function () {
    //
});
Маршрут ошибки должны быть последними в приложении.

Ограничение числа запросов:

В Laravel можно испоьзовать методологию ограничение числа запросов к маршруту или группе маршрутов. Для этого необходимо прописать к маршруту промежуточный слой с методом throttle, который включает 2 параметра: колчество запросов и временной интервал в минутах. Определим, что авторизированный пользователь может делать 60 запросов в минуту к группе маршрутов:

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Динамическое ограничение:

Можно указать динамический максимум запросов, основанный на атрибуте в модели. Например, если вы модель содержит rate_limit атрибут, то вы можете передать значение в промежуточный слой, чтобы высчитать максимум запросов:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Имитация методов в формах:

HTML формы не поддерживают методы PUT, PATCH или DELETE. Поэтому, чтобы определить PUT, PATCH или DELETE маршруты в HTML форме, вам необходимо добавть скрытое поле _method в форму. Значение, которое указано в поле, будет использовано как HTTP метод:

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

Вы можете использовать @method в шаблонизаторе Blade, чтобы сгенерировать _method поле ввода.

<form action="/foo/bar" method="POST">
    @method('PUT')
    @csrf
</form>

Текущий адрес:

Можете использовать current, currentRouteName и currentRouteAction методы, чтобы получить информацию о текущем запросе.

$route = Route::current();

$name = Route::currentRouteName();

$action = Route::currentRouteAction();

Обратитесь к API документации, чтобы получить список всех команд и методов.