Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Вместо того чтобы определять всю логику обработки запросов в виде замыканий в файлах маршрутов, вы можете захотеть организовать это поведение с использованием классов "контроллера". Контроллеры могут группировать связанную логику обработки запросов в единый класс. Например, класс UserController
может обрабатывать все входящие запросы, связанные с пользователями, включая отображение, создание, обновление и удаление пользователей. По умолчанию контроллеры хранятся в каталоге app/Http/Controllers
.
Чтобы быстро создать новый контроллер, вы можете выполнить команду Artisan make:controller
. По умолчанию все контроллеры для вашего приложения хранятся в каталоге app/Http/Controllers
:
php artisan make:controller UserController
Давайте рассмотрим пример базового контроллера. Контроллер может иметь любое количество общедоступных методов, которые будут отвечать на входящие HTTP-запросы:
<?php namespace App\Http\Controllers; use App\Models\User;use Illuminate\View\View; class UserController extends Controller{ /** * Показать профиль для указанного пользователя. */ public function show(string $id): View { return view('user.profile', [ 'user' => User::findOrFail($id) ]); }}
После написания класса контроллера и метода вы можете определить маршрут для метода контроллера, как показано ниже:
use App\Http\Controllers\UserController; Route::get('/user/{id}', [UserController::class, 'show']);
Когда входящий запрос соответствует указанному URI маршрута, будет вызван метод show
класса App\Http\Controllers\UserController
, и параметры маршрута будут переданы в метод.
Примечание Контроллеры не обязаны расширять базовый класс. Однако у вас не будет доступа к удобным функциям, таким как методы
middleware
иauthorize
.
Если действие контроллера особенно сложное, вам может показаться удобным выделить целый класс контроллера для этого единственного действия. Для этого вы можете определить единственный метод __invoke
в контроллере:
<?php namespace App\Http\Controllers; class ProvisionServer extends Controller{ /** * Предоставьте новый веб-сервер. */ public function __invoke() { // ... }}
При регистрации маршрутов для контроллеров с единственным действием вам не нужно указывать метод контроллера. Вместо этого вы можете просто передать имя контроллера роутеру:
use App\Http\Controllers\ProvisionServer; Route::post('/server', ProvisionServer::class);
Вы можете создать контроллер, вызываемый с помощью опции --invokable
команды make:controller
Artisan:
php artisan make:controller ProvisionServer --invokable
Примечание Шаблоны контроллеров можно настраивать с помощью публикации шаблонов.
Промежуточное ПО может быть назначено маршрутам контроллера в ваших файлах маршрутов:
Route::get('profile', [UserController::class, 'show'])->middleware('auth');
Или вам может быть удобно указать промежуточное ПО в конструкторе вашего контроллера. Используя метод middleware
в конструкторе контроллера, вы можете назначить промежуточное ПО для действий контроллера:
class UserController extends Controller{ /** * Создайте новый экземпляр контроллера. */ public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); }}
Контроллеры также позволяют вам регистрировать промежуточное ПО, используя замыкание. Это предоставляет удобный способ определения встроенного промежуточного ПО для одного контроллера без создания целого класса промежуточного ПО:
use Closure;use Illuminate\Http\Request; $this->middleware(function (Request $request, Closure $next) { return $next($request);});
Если вы думаете о каждой модели Eloquent в вашем приложении как о "ресурсе", обычно выполняется один и тот же набор действий для каждого ресурса в вашем приложении. Например, представьте, что ваше приложение содержит модели Photo
и Movie
. Скорее всего, пользователи могут создавать, читать, обновлять или удалять эти ресурсы.
Из-за этого общего случая использования маршрутизации ресурсов Laravel автоматически назначает типичные маршруты создания, чтения, обновления и удаления ("CRUD") контроллеру одной строкой кода. Для начала мы можем использовать опцию --resource
команды Artisan make:controller
, чтобы быстро создать контроллер для обработки этих действий:
php artisan make:controller PhotoController --resource
Эта команда создаст контроллер по адресу app/Http/Controllers/PhotoController.php
. В контроллере будут содержаться методы для каждой из доступных операций с ресурсом. Затем вы можете зарегистрировать маршрут ресурса, указав контроллер:
use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class);
Это единственное определение маршрута создает несколько маршрутов для обработки различных действий с ресурсом. Сгенерированный контроллер уже будет содержать заготовки для каждого из этих действий. Помните, что вы всегда можете получить быстрый обзор маршрутов вашего приложения, запустив команду Artisan route:list
.
Вы можете зарегистрировать множество контроллеров ресурсов сразу, передав массив методу resources
:
Route::resources([ 'photos' => PhotoController::class, 'posts' => PostController::class,]);
Глагол | URI | Действие | Имя Маршрута |
---|---|---|---|
GET | /photos |
index | photos.index |
GET | /photos/create |
create | photos.create |
POST | /photos |
store | photos.store |
GET | /photos/{photo} |
show | photos.show |
GET | /photos/{photo}/edit |
edit | photos.edit |
PUT/PATCH | /photos/{photo} |
update | photos.update |
DELETE | /photos/{photo} |
destroy | photos.destroy |
Обычно будет сгенерирован HTTP-ответ 404, если не удается неявно связать модель ресурса. Однако вы можете настроить это поведение, вызвав метод missing
при определении маршрута ресурса. Метод missing
принимает замыкание, которое будет вызвано, если не удается найти неявно связанную модель для любого из маршрутов ресурса:
use App\Http\Controllers\PhotoController;use Illuminate\Http\Request;use Illuminate\Support\Facades\Redirect; Route::resource('photos', PhotoController::class) ->missing(function (Request $request) { return Redirect::route('photos.index'); });
Обычно неявная привязка модели не будет извлекать модели, которые были мягко удалены, и вместо этого вернет HTTP-ответ 404. Однако вы можете научить фреймворк обрабатывать мягко удаленные модели, вызвав метод withTrashed
при определении маршрута ресурса:
use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class)->withTrashed();
Вызов withTrashed
без аргументов разрешит мягко удаленные модели для маршрутов ресурса show
, edit
и update
. Вы можете указать подмножество этих маршрутов, передав массив методу withTrashed
:
Route::resource('photos', PhotoController::class)->withTrashed(['show']);
Если вы используете привязку модели к маршруту и хотите, чтобы методы контроллера ресурсов имели типизированный экземпляр модели, вы можете использовать опцию --model
при создании контроллера:
php artisan make:controller PhotoController --model=Photo --resource
Вы можете использовать опцию --requests
при создании контроллера ресурсов, чтобы указать Artisan на генерацию классов формных запросов для методов хранения и обновления контроллера:
php artisan make:controller PhotoController --model=Photo --resource --requests
При объявлении маршрута ресурса вы можете указать подмножество действий, которые контроллер должен обрабатывать, вместо полного набора действий по умолчанию:
use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class)->only([ 'index', 'show']); Route::resource('photos', PhotoController::class)->except([ 'create', 'store', 'update', 'destroy']);
При объявлении маршрутов ресурсов, которые будут использоваться в API, вы обычно захотите исключить маршруты, представляющие HTML-шаблоны, такие как create
и edit
. Для удобства вы можете использовать метод apiResource
, чтобы автоматически исключить эти два маршрута:
use App\Http\Controllers\PhotoController; Route::apiResource('photos', PhotoController::class);
Вы можете зарегистрировать сразу много контроллеров ресурсов API, передав массив методу apiResources
:
use App\Http\Controllers\PhotoController;use App\Http\Controllers\PostController; Route::apiResources([ 'photos' => PhotoController::class, 'posts' => PostController::class,]);
Чтобы быстро создать контроллер ресурсов API, не включающий методы create
или edit
, используйте ключ --api
при выполнении команды make:controller
:
php artisan make:controller PhotoController --api
Иногда вам может потребоваться определить маршруты к вложенному ресурсу. Например, ресурс фотографии может иметь несколько комментариев, которые могут быть привязаны к фотографии. Чтобы вложить контроллеры ресурсов, вы можете использовать "точечную" нотацию в объявлении вашего маршрута:
use App\Http\Controllers\PhotoCommentController; Route::resource('photos.comments', PhotoCommentController::class);
Этот маршрут зарегистрирует вложенный ресурс, к которому можно получить доступ с помощью URI, подобных следующим:
/photos/{photo}/comments/{comment}
Функция неявной привязки модели Laravel может автоматически облачить вложенные привязки так, чтобы удостовериться, что разрешенная дочерняя модель принадлежит родительской модели. Используя метод scoped
при определении вашего вложенного ресурса, вы можете включить автоматическую облачность, а также указать Laravel, какое поле следует использовать для получения дочернего ресурса. Для получения дополнительной информации об этом см. документацию по облачиванию маршрутов ресурсов.
Часто не совсем необходимо иметь идентификаторы как родителя, так и ребенка в URI, поскольку идентификатор ребенка уже является уникальным идентификатором. При использовании уникальных идентификаторов, таких как автоинкрементные первичные ключи для идентификации ваших моделей в сегментах URI, вы можете выбрать использование "поверхностного вложения":
use App\Http\Controllers\CommentController; Route::resource('photos.comments', CommentController::class)->shallow();
Это определение маршрута создаст следующие маршруты:
Глагол | URI | Действие | Имя Маршрута |
---|---|---|---|
GET | /photos/{photo}/comments |
index | photos.comments.index |
GET | /photos/{photo}/comments/create |
create | photos.comments.create |
POST | /photos/{photo}/comments |
store | photos.comments.store |
GET | /comments/{comment} |
show | comments.show |
GET | /comments/{comment}/edit |
edit | comments.edit |
PUT/PATCH | /comments/{comment} |
update | comments.update |
DELETE | /comments/{comment} |
destroy | comments.destroy |
По умолчанию у всех действий контроллера ресурсов есть имя маршрута; однако вы можете переопределить эти имена, передав массив names
с вашими желаемыми именами маршрутов:
use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class)->names([ 'create' => 'photos.build']);
По умолчанию Route::resource
создаст параметры маршрута для ваших ресурсных маршрутов на основе "сингуляризированной" версии имени ресурса. Вы можете легко переопределить это для каждого ресурса, используя метод parameters
. Передаваемый в метод parameters
массив должен быть ассоциативным массивом имен ресурсов и имен параметров:
use App\Http\Controllers\AdminUserController; Route::resource('users', AdminUserController::class)->parameters([ 'users' => 'admin_user']);
В приведенном выше примере генерируется следующий URI для маршрута show
ресурса:
/users/{admin_user}
Функция облачивания неявной привязки модели Laravel может автоматически облачивать вложенные привязки так, чтобы удостовериться, что разрешенная дочерняя модель принадлежит родительской модели. Используя метод scoped
при определении вашего вложенного ресурса, вы можете включить автоматическую облачность, а также указать Laravel, какое поле следует использовать для получения дочернего ресурса:
use App\Http\Controllers\PhotoCommentController; Route::resource('photos.comments', PhotoCommentController::class)->scoped([ 'comment' => 'slug',]);
Этот маршрут зарегистрирует вложенный ресурс с облачиванием, к которому можно получить доступ с помощью URI, подобных следующим:
/photos/{photo}/comments/{comment:slug}
При использовании неявной привязки с пользовательским ключом вложенного маршрута Laravel автоматически облачивает запрос для получения вложенной модели по ее родителю, используя соглашения для угадывания имени отношения на родителе. В этом случае предполагается, что у модели Photo
есть отношение с именем comments
(множественное число имени параметра маршрута), которое можно использовать для получения модели Comment
.
По умолчанию Route::resource
создает URI ресурсов, используя английские глаголы и правила множественного числа. Если вам нужно локализовать глаголы действий create
и edit
, вы можете использовать метод Route::resourceVerbs
. Это можно сделать в начале метода boot
в вашем App\Providers\RouteServiceProvider
приложения:
/** * Определите привязки модели к маршруту, фильтры шаблона и т.д. */public function boot(): void{ Route::resourceVerbs([ 'create' => 'crear', 'edit' => 'editar', ]); // ...}
Множественное число в Laravel поддерживает несколько разных языков, которые вы можете настроить в соответствии с вашими потребностями. После того как глаголы и язык множественного числа были настроены, регистрация маршрута ресурса, такого как Route::resource('publicacion', PublicacionController::class)
создаст следующие URI:
/publicacion/crear /publicacion/{publicaciones}/editar
Если вам нужно добавить дополнительные маршруты к контроллеру ресурсов помимо стандартного набора ресурсных маршрутов, вы должны определить эти маршруты до вызова метода Route::resource
; в противном случае маршруты, определенные методом resource
, могут непреднамеренно преобразовывать ваши дополнительные маршруты:
use App\Http\Controller\PhotoController; Route::get('/photos/popular', [PhotoController::class, 'popular']);Route::resource('photos', PhotoController::class);
Примечание Не забывайте делать ваши контроллеры фокусированными. Если вы часто обнаруживаете, что вам нужны методы вне типичного набора действий ресурса, рассмотрите возможность разделения вашего контроллера на два более мелких контроллера.
Иногда в вашем приложении могут быть ресурсы, которые могут иметь только один экземпляр. Например, у пользователя может быть редактируемый или обновляемый "профиль", но у пользователя не может быть более одного "профиля". Точно так же у изображения может быть один "эскиз". Эти ресурсы называются "одиночными ресурсами", что означает, что может существовать только один экземпляр ресурса. В этих сценариях вы можете зарегистрировать "одиночный" контроллер ресурсов:
use App\Http\Controllers\ProfileController;use Illuminate\Support\Facades\Route; Route::singleton('profile', ProfileController::class);
Определение одиночного ресурса выше зарегистрирует следующие маршруты. Как видите, маршруты "создания" не регистрируются для одиночных ресурсов, и зарегистрированные маршруты не принимают идентификатор, поскольку может существовать только один экземпляр ресурса:
Глагол | URI | Действие | Имя Маршрута |
---|---|---|---|
GET | /profile |
show | profile.show |
GET | /profile/edit |
edit | profile.edit |
PUT/PATCH | /profile |
update | profile.update |
Одиночные ресурсы также могут быть вложены в стандартный ресурс:
Route::singleton('photos.thumbnail', ThumbnailController::class);
В этом примере ресурс photos
будет получать все стандартные маршруты ресурсов; однако ресурс thumbnail
будет одиночным ресурсом со следующими маршрутами:
Глагол | URI | Действие | Имя Маршрута |
---|---|---|---|
GET | /photos/{photo}/thumbnail |
show | photos.thumbnail.show |
GET | /photos/{photo}/thumbnail/edit |
edit | photos.thumbnail.edit |
PUT/PATCH | /photos/{photo}/thumbnail |
update | photos.thumbnail.update |
Иногда вам может потребоваться определить маршруты создания и хранения для одиночного ресурса. Для этого вы можете вызвать метод creatable
при регистрации маршрута одиночного ресурса:
Route::singleton('photos.thumbnail', ThumbnailController::class)->creatable();
В этом примере будут зарегистрированы следующие маршруты. Как видите, для одиночных ресурсов, доступных для создания, также будет зарегистрирован маршрут DELETE
:
Глагол | URI | Действие | Имя Маршрута |
---|---|---|---|
GET | /photos/{photo}/thumbnail/create |
create | photos.thumbnail.create |
POST | /photos/{photo}/thumbnail |
store | photos.thumbnail.store |
GET | /photos/{photo}/thumbnail |
show | photos.thumbnail.show |
GET | /photos/{photo}/thumbnail/edit |
edit | photos.thumbnail.edit |
PUT/PATCH | /photos/{photo}/thumbnail |
update | photos.thumbnail.update |
DELETE | /photos/{photo}/thumbnail |
destroy | photos.thumbnail.destroy |
Если вы хотите, чтобы Laravel регистрировала маршрут DELETE
для одиночного ресурса, но не регистрировала маршруты создания или хранения, вы можете воспользоваться методом destroyable
:
Route::singleton(...)->destroyable();
Метод apiSingleton
можно использовать для регистрации одиночного ресурса, который будет обрабатываться через API, тем самым избавляясь от необходимости регистрации маршрутов create
и edit
:
Route::apiSingleton('profile', ProfileController::class);
Конечно же, API-ресурсы-одиночки также могут быть creatable
, что приведет к регистрации маршрутов store
и destroy
для ресурса:
Route::apiSingleton('photos.thumbnail', ProfileController::class)->creatable();
В Laravel контейнере служб используется для разрешения всех контроллеров Laravel. В результате вы можете указать зависимости, которые ваш контроллер может потребовать в своем конструкторе. Объявленные зависимости будут автоматически разрешаться и внедряться в экземпляр контроллера:
<?php namespace App\Http\Controllers; use App\Repositories\UserRepository; class UserController extends Controller{ /** * Создайте новый экземпляр контроллера. */ public function __construct( protected UserRepository $users, ) {}}
Помимо инъекции через конструктор, вы также можете указывать зависимости в методах вашего контроллера. Обычным случаем использования для инъекции метода является внедрение экземпляра Illuminate\Http\Request
в методы вашего контроллера:
<?php namespace App\Http\Controllers; use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request; class UserController extends Controller{ /** * Сохраните нового пользователя. */ public function store(Request $request): RedirectResponse { $name = $request->name; // Сохраните пользователя... return redirect('/users'); }}
Если ваш метод контроллера также ожидает ввод из параметра маршрута, укажите свои аргументы маршрута после других зависимостей. Например, если ваш маршрут определен следующим образом:
use App\Http\Controllers\UserController; Route::put('/user/{id}', [UserController::class, 'update']);
Вы все равно можете указать тип Illuminate\Http\Request
и получить доступ к вашему параметру id
, определив метод контроллера следующим образом:
<?php namespace App\Http\Controllers; use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request; class UserController extends Controller{ /** * Обновите указанного пользователя. */ public function update(Request $request, string $id): RedirectResponse { // Обновите пользователя... return redirect('/users'); }}