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

## Основы маршрутизации

Самые простые маршруты Laravel принимают URI и `Closure`, обеспечивая очень простой и выразительный метод определения маршрутов:

```php
Route::get('foo', function () {
    return 'Hello World';
});
```

### Файлы маршрутов по умолчанию

Все маршруты Laravel определены в файлах, расположенных в каталоге `routes`. Эти файлы автоматически загружаются фреймворком. Файл `routes/web.php` определяет маршруты для веб-интерфейса. Эти маршруты относятся к группе посредников `web`, которая предоставляет такие возможности, как состояние сеанса и защита от CSRF. Маршруты в `routes/api.php` являются stateless (без состояния) и относятся к группе посредников `api`.

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

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

Маршруты, определенные в файле `routes/api.php`, вложены в группу маршрутов `RouteServiceProvider`. Внутри этой группы автоматически применяется префикс URI `/api`, поэтому нет необходимости вручную указывать его в каждом маршруте в этом файле. Изменить префикс и другие опции группы маршрутов можно, изменив класс `RouteServiceProvider`.

### Доступные методы маршрутизации

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

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

Иногда вам может понадобиться зарегистрировать маршрут, который отвечает на несколько типов HTTP-запросов. Это можно сделать, используя метод `match`. Или даже можно зарегистрировать маршрут, который отвечает на все типы HTTP-запросов, используя метод `any`:

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

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

#### **CSRF защита**

Любые HTML формы, указывающие на маршруты `POST`, `PUT`, `PATCH` или `DELETE`, определенные в файле маршрутов `web`, должны включать поле токена CSRF. В противном случае запрос будет отклонен. Подробнее о защите CSRF Вы можете прочитать в [документации по CSRF защите](/laravel-ru/the-basics/csrf.md):

```markup
<form method="POST" action="/profile">
    @csrf
    ...
</form>
```

### Перенаправленные маршруты

Если вы определяете маршрут, который перенаправляет на другой URI, то можете использовать метод `Route::redirect`. Этот метод является удобным ярлыком, так что вам не придется определять полный маршрут или контроллер для выполнения простого перенаправления:

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

По умолчанию `Route::redirect` возвращает код состояния `302`. Код статуса можно настроить, используя дополнительный третий параметр:

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

Вы можете использовать метод `Route::permanentRedirect` для возврата кода статуса `301`:

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

### Маршруты с представлениями

Если маршрут должен только вернуть представление, вы можете использовать метод `Route::view`. Как и `redirect`, этот метод предоставляет простой ярлык, так что Вам не нужно определять полный маршрут или контроллер. Метод `view` принимает URI в качестве первого аргумента, и имя представления — в качестве второго. Кроме того, вы можете предоставить массив данных для передачи в представление третьим необязательным аргументом:

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

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

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

### Обязательные параметры

Иногда нужно определить сегменты URI в пределах маршрута. Например, вам может понадобиться определить идентификатор пользователя из URL. Вы можете сделать это, определив параметры маршрута:

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

Вы можете определить столько параметров маршрута, сколько требуется:

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

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

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

Иногда может понадобиться указать параметр маршрута, но сделать его присутствие необязательным. Вы можете сделать это, поставив символ `?` после имени параметра. Убедитесь, что соответствующая переменная маршрута имеет значение по умолчанию:

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

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

### Ограничения регулярными выражениями

Вы можете ограничить формат параметров вашего маршрута, используя метод `where` на экземпляре маршрута. Метод `where` принимает имя параметра и регулярное выражение, определяющее, как параметр должен быть ограничен:

```php
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]+']);
```

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

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

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

    parent::boot();
}
```

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

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

### Использоание прямого слэша

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

```php
Route::get('search/{search}', function ($search) {
    return $search;
})->where('search', '.*');
```

{% hint style="warning" %}
Использование прямого слэша поддерживаются только в пределах последнего сегмента маршрута.
{% endhint %}

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

Именованные маршруты позволяют удобно генерировать URL или перенаправлять для конкретных маршрутов. Вы можете задать имя, вызвав метод `name` в определении маршрута:

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

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

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

{% hint style="warning" %}
Названия маршрутов всегда должны быть уникальными.
{% endhint %}

### Генерация URL-адресов по имени маршрута

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

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

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

Если именованный маршрут определяет параметры, то можете передать параметры в качестве второго аргумента в функцию `route`. Данные параметры будут автоматически вставлены в URL в правильном порядке:

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

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

Если вы передадите в массив дополнительные параметры, то эти пары ключ/значение будут автоматически добавлены в строку запроса сгенерированного URL:

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

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

// /user/1/profile?photos=yes
```

{% hint style="info" %}
Иногда нужно указать значения по умолчанию для URL-параметров в масштабе всего запроса, например, для текущей локали. Для этого можно использовать [метод `URL::defaults`](/laravel-ru/the-basics/urls.md#znacheniya-po-umolchaniyu).
{% endhint %}

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

Если вы хотите определить, был ли текущий запрос направлен на заданный именованный маршрут, то можете использовать метод `named` на экземпляре Route. Например, вы можете проверить текущее название маршрута из посредника маршрута:

```php
/**
 * 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`.

Вложенные группы пытаются умно "объединить" атрибуты со своей родительской группой. Посредники и условия `where` объединяются, в то время как имена, пространства имен и префиксы добавляются. Разделители пространств имен и слэши в префиксах URI добавляются при необходимости автоматически.

### Посредники

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

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

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

### Пространства имен

Другим распространенным случаем использования групп маршрутов является назначение одного и того же пространства имён PHP группе контроллеров методом `namespace`:

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

Помните, что по умолчанию `RouteServiceProvider` включает файлы маршрутов в группу пространств имен, позволяя регистрировать маршруты контроллеров без указания полного префикса `App\Http\Controllers`. Таким образом, вам нужно указать только ту часть пространства имен, которая идет после базового `App\Http\Controllers` пространства имен.

### Маршрутизация поддоменов

Группы маршрутов также могут использоваться для обработки субдоменной маршрутизации. Поддоменам могут быть назначены параметры маршрута, такие же как и URI маршрута, что позволяет вам захватить часть поддомена для использования в вашем маршруте или контроллере. Поддомен можно указать, вызвав метод `domain` перед определением группы:

```php
Route::domain('{account}.myapp.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});
```

{% hint style="warning" %}
Для того чтобы убедиться, что ваши маршруты субдоменов доступны, необходимо зарегистрировать маршруты субдоменов до регистрации маршрутов корневых доменов. Это не позволит маршрутам корневого домена перезаписывать маршруты субдоменов, которые имеют один и тот же путь URI.
{% endhint %}

### Префиксы маршрута

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

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

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

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

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

## Внедрение моделей в маршруты

При введении идентификатора модели в маршрут или действие контроллера, вы часто запрашиваете модель, соответствующую этому идентификатору. Привязка модели к маршруту обеспечивает удобный способ автоматического внедрения экземпляров модели непосредственно в маршруты. Например, вместо того, чтобы внедрить ID пользователя, вы можете ввести весь экземпляр модели `User`, соответствующий данному ID.

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

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

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

Так как переменная `$user` имеет подсказку типа `App\User` Eloquent модели, а имя переменной совпадает с URI сегментом `{user}`, Laravel автоматически внедрит экземпляр модели, имеющий ID, совпадающий с соответствующим значением из URI запроса. Если соответствующий экземпляр модели не найден в базе данных, автоматически будет сгенерирован ответ HTTP 404.

**Настройка ключа**

Иногда вы можете захотеть разрешить модели Eloquent, используя колонку, отличную от `id`. Для этого вы можете указать столбец в определении параметра маршрута:

```php
Route::get('api/posts/{post:slug}', function (App\Post $post) {
    return $post;
});
```

**Пользовательские ключи и область видимости**

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

```php
use App\Post;
use App\User;

Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});
```

При использовании неявной привязки по пользовательскому ключу в качестве вложенного параметра маршрута, Laravel автоматически выполнит запрос на получение вложенной модели от ее родителя, используя соглашения для угадывания имени отношения на родительском. В этом случае, предполагается, что модель `User` имеет отношение с именем `posts`  (множественное число имени параметра маршрута), которое может быть использовано для получения модели `Post`.

**Настройка имени ключа по умолчанию**

Если Вы хотите, чтобы привязка модели использовала столбец базы данных по умолчанию, отличный от `id`, при получении заданного класса модели, Вы можете переопределить метод `getRouteKeyName` на модели Eloquent:

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

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

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

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

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

Далее определите маршрут, содержащий параметр `{user}`:

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

Так как мы привязали все параметры `{user}` к модели `App\User`, в маршрут будет вставлен экземпляр `User`. Так, например, запрос к `profile/1` будет внедрять экземпляр `User` из базы данных, имеющей ID `1`.

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

**Настройка логики разрешения**

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

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

    Route::bind('user', function ($value) {
        return App\User::where('name', $value)->firstOrFail();
    });
}
```

В качестве альтернативы, вы можете переопределить метод `resolveRouteBinding` на модели Eloquent. Этот метод получит значение сегмента URI и должен вернуть экземпляр класса, который должен быть внедрен в маршрут:

```php
/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value, $field = null)
{
    return $this->where('name', $value)->firstOrFail();
}
```

## Запасные маршруты

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

```php
Route::fallback(function () {
    //
});
```

{% hint style="warning" %}
Запасной маршрут всегда должен быть последним маршрутом, зарегистрированным в вашем приложении.
{% endhint %}

## Ограничение скорости

Laravel включает в себя [посредника](/laravel-ru/the-basics/middleware.md) для ограничения доступа к маршрутам внутри приложения. Для начала, назначьте посредника `throttle` маршруту или группе маршрутов. Этот посредник принимает два параметра, которые определяют максимальное количество запросов, которые могут быть сделаны в заданное количество минут. Например, укажем, что аутентифицированный пользователь может получить доступ к следующей группе маршрутов 60 раз в минуту:

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

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

Вы можете указать динамический максимум запроса, основываясь на атрибуте аутентифицированной модели `User`. Например, если Ваша `User` модель содержит атрибут `rate_limit`, Вы можете передать имя атрибута в посредник `throttle`, чтобы оно использовалось для вычисления максимального количества запросов:

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

**Различные ограничения для гостевых и аутентифицированных пользователей**

Вы можете указать разные ограничения для гостевых и аутентифицированных пользователей. Например, Вы можете указать максимум `10` запросов в минуту для гостей и `60` для аутентифицированных пользователей:

```php
Route::middleware('throttle:10|60,1')->group(function () {
    //
});
```

Вы также можете комбинировать эту функциональность с динамическим ограничением скорости. Например, если Ваша `User` модель содержит атрибут `rate_limit`, Вы можете передать имя атрибута в `throttle` промежуточное программное обеспечение, чтобы оно использовалось для вычисления максимального количества запросов для аутентифицированных пользователей:

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

**Ограничения для сегментов**

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

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

    Route::middleware('throttle:60,1,deletes')->group(function () {
        Route::delete('/servers/{id}', function () {
            //
        });
    });
});
```

## Подмена метода запроса в формах

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

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

Вы можете использовать Blade директиву `@method` для генерации поля `_method`:

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

## Доступ к текущему маршруту

Вы можете использовать методы `current`, `currentRouteName` и `currentRouteAction` на фасаде `Route` для доступа к информации о маршруте, по которому обрабатывается входящий запрос:

```php
$route = Route::current();

$name = Route::currentRouteName();

$action = Route::currentRouteAction();
```

Для просмотра всех доступных методов обратитесь к документации API [класса фасада Route](https://laravel.com/api/7.x/Illuminate/Routing/Router.html), и [экземпляра Route](https://laravel.com/api/7.x/Illuminate/Routing/Route.html).

## Cross-Origin Resource Sharing (CORS)

Laravel может автоматически отвечать на запросы CORS OPTIONS значениями, которые вы настраиваете. Все настройки CORS могут быть сконфигурированы в конфигурационном файле `cors`, а запросы OPTIONS будут автоматически обрабатываться посредником `HandleCors`, который по умолчанию включен в глобальный стек посредников.

{% hint style="info" %}
Для получения дополнительной информации о CORS и заголовках CORS обратитесь к [документации MDN по CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers).
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://delphinpro.gitbook.io/laravel-ru/the-basics/routing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
