{{TOC}} {{DOCVER 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11}} == Введение == Вместо того, чтобы определять всю логику обработки запросов в виде замыканий в файлах маршуртов, вы можете организовать её с помощью классов контроллеров. Контроллеры могут группировать связанную с обработкой HTTP-запросов логику в отдельный класс. Контроллеры хранятся в папке %%(t)app/Http/Controllers%%. == Простейшие контроллеры == === Определение контроллеров === Ниже приведён пример простейшего класса контроллера. Обратите внимание, контроллер наследует базовый класс контроллера, встроенный в Laravel. Базовый класс предоставляет несколько удобных методов, таких как метод %%middleware()%%, используемый для назначения посредников на действия контроллера: %% User::findOrFail($id)]); } } %% Мы можем определить маршрут для действия (//action//) этого контроллера вот так: %% Route::get('user/{id}', 'UserController@show'); %% Теперь при соответствии запроса указанному URI маршрута будет выполняться метод %%show()%% класса %%(t)UserController%%. Само собой параметры маршрута также будут переданы в метод. .(alert) Контроллерам не **обязательно** наследовать базовый класс. Но тогда у вас не будет таких удобных возможностей, как методы %%middleware()%%, %%validate()%% и %%dispatch()%%. === Контроллеры и пространства имён === Важно помнить, что при определении маршрута контроллера нам не надо указывать полное пространство имён контроллера, а только ту часть имени класса, которая следует за "корнем" пространства имён - %%(t)App\Http\Controllers%%. Потому что %%(t)RouteServiceProvider%% загружает ваши файлы маршрутов вместе с группой маршрутизации, содержащей корневое пространство имён контроллера. Если вы решите разместить свои контроллеры в поддиректориях %%(t)App\Http\Controllers%%, то просто используйте конкретное имя класса относительно корня пространства имён %%(t)App\Http\Controllers%%. Тогда, если полный путь к вашему классу будет %%(t)App\Http\Controllers\Photos\AdminController%%, то вам надо зарегистрировать маршруты к контроллеру вот так: %% Route::get('foo', 'Photos\AdminController@method'); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) === Контроллеры одного действия === Для определения контроллера, обрабатывающего всего одно действие, поместите в контроллер единственный метод %%__invoke()%%: ~%% User::findOrFail($id)]); } } ~%% При регистрации маршрутов для контроллеров одного действия вам не надо указывать метод: ~%% Route::get('user/{id}', 'ShowProfile'); ~%% %% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) **Имена маршрутов контроллеров** Подобно маршрутам замыканий, вы можете указать имена для маршрутов контроллеров: ~%% Route::get('foo', ['uses' => 'FooController@method', 'as' => 'name']); ~%% Также вы можете использовать вспомогательную функцию %%route()%%, чтобы сгенерировать URL маршрута названного контроллера: ~%% $url = route('name'); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) **URL-адреса для //действий// контроллера** Также вы можете использовать вспомогательный метод %%action()%%, чтобы сгенерировать URL, используя имена классов и методов контроллера. И снова, нам надо указать только ту часть имени контроллера, которая идёт после базового пространства имён %%(t)App\Http\Controllers%%: ~%% $url = action('FooController@method'); ~%% Получить имя //действия//, которое выполняется в данном запросе, можно методом %%currentRouteAction()%% фасада %%(t)Route%%: ~%% $action = Route::currentRouteAction(); ~%% %% %%(DOCNEW 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Для получения URL для //действия// контроллера используйте метод %%action()%%: ~%% $url = action('App\Http\Controllers\FooController@method'); ~%% Если вы хотите получить URL для //действия// контроллера, используя только часть имени класса относительно пространства имён контроллера, зарегистрируйте корневое пространство имён контроллера с помощью генератора URL: ~%% URL::setRootControllerNamespace('App\Http\Controllers'); $url = action('FooController@method'); ~%% %% == Посредник контроллера == ((/docs/v5/middleware Посредник)) можно указать для маршрутов контроллера в файлах маршрутов: %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) ~%% Route::get('profile', 'UserController@show')->middleware('auth'); ~%% %% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) ~%% Route::get('profile', [ 'middleware' => 'auth', 'uses' => 'UserController@showProfile' ]); ~%% %% Но удобнее указать посредника в конструкторе вашего контроллера. Используя метод %%middleware()%% в конструкторе контроллера, вы легко можете назначить посредника для действия контроллера. Вы можете даже ограничить использование посредника, назначив его только для определённых методов класса контроллера: %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) ~%% class UserController extends Controller { /** * Создание нового экземпляра контроллера. * * @return void */ public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); } } ~%% %% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) ~%% class UserController extends Controller { /** * Создание нового экземпляра UserController. */ public function __construct() { $this->middleware('auth'); $this->middleware('log', ['only' => [ 'fooAction', 'barAction', ]]); $this->middleware('subscribed', ['except' => [ 'fooAction', 'barAction', ]]); } } ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) Контроллеры также позволяют регистрировать посредников с помощью замыканий. Это удобный способ определения посредника для одного контроллера, не требующий определения целого класса посредника: ~%% $this->middleware(function ($request, $next) { // ... return $next($request); }); ~%% .(alert) Вы можете назначить посредника на определённый набор действий контроллера, но если возникает такая необходимость, возможно ваш контроллер стал слишком велик. Вместо этого вы можете разбить контроллер на несколько маленьких контроллеров. %% == ((#ресурс)) Контроллеры ресурсов == Маршрутизация ресурсов Laravel назначает обычные CRUD-маршруты на контроллеры одной строчкой кода. Например, вы можете создать контроллер, обрабатывающий все HTTP-запросы к фотографиям, хранимым вашим приложением. Вы можете быстро создать такой контроллер с помощью Artisan-команды %%(sh)make:controller%%: %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) %%(sh) php artisan make:controller PhotoController --resource ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) %%(sh) php artisan make:controller PhotoController ~%% %% Эта команда сгенерирует контроллер %%(t)app/Http/Controllers/PhotoController.php%%. Контроллер будет содержать метод для каждой доступной операции с ресурсами. Теперь мы можем зарегистрировать маршрут контроллера ресурса: %% Route::resource('photos', 'PhotoController'); %% Один этот вызов создаёт множество маршрутов для обработки различных действий для ресурса. Сгенерированный контроллер уже имеет методы-заглушки для каждого из этих //действий// с комментариями о том, какие URI и типы запросов они обрабатывают. **//Действия//, обрабатываемые контроллером ресурсов** %%(hvlraw)
Тип URI Действие Имя маршрута
GET /photos index photo.index
GET /photos/create create photo.create
POST /photos store photo.store
GET /photos/{photo} show photo.show
GET /photos/{photo}/edit edit photo.edit
PUT/PATCH /photos/{photo} update photo.update
DELETE /photos/{photo} destroy photo.destroy
%% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Не забывайте, поскольку HTML-формы не могут выполнять запросы PUT, PATCH и DELETE, вам надо будет добавить скрытое поле %%(t)_method%%, для спуффинга этих HTTP-команд: ~%% ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) **Подмена методов формы** Поскольку HTML-формы не могут выполнять запросы %%(t)PUT%%, %%(t)PATCH%% и %%(t)DELETE%%, вам надо добавить скрытое поле %%(t)_method%% для подмены этих HTTP-запросов. Вспомогательный метод %%method_field()%% создаст это поле для вас: ~%% {{ method_field('PUT') }} ~%% %% === Частичные маршруты ресурсов === При объявлении маршрута вы можете указать подмножество всех возможных //действий//, которые должен обрабатывать контроллер вместо полного набора стандартных действий: %% Route::resource('photo', 'PhotoController', ['only' => [ 'index', 'show' ]]); Route::resource('photo', 'PhotoController', ['except' => [ 'create', 'store', 'update', 'destroy' ]]); %% === Именование маршрутов ресурсов === По умолчанию все //действия// контроллера ресурсов имеют имена маршрутов, но вы можете переопределить эти имена, передав массив %%(t)names%% вместе с остальными параметрами: %% Route::resource('photo', 'PhotoController', ['names' => [ 'create' => 'photo.build' ]]); %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) **Вложенные ресурсы** Иногда необходимо определить маршруты для "вложенных" ресурсов. Например, фото-ресурс может иметь множество "комментариев", которые могут быть прикреплены к фотографии. Используйте "точечную" нотацию в объявлении маршрута для контроллеров "вложенных" ресурсов: ~%% Route::resource('photos.comments', 'PhotoCommentController'); ~%% Этот маршрут зарегистрирует "вложенный" ресурс, к которому можно обратиться по такому URL: %%(t)photos/{photos}/comments/{comments}%%. ~%% [ 'user' => 'admin_user' ]]); ~%% Этот пример генерирует следующие URI для маршрута ресурса %%(t)show%%: ~%% /user/{admin_user} ~%% %% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Вместо передачи массива имён параметров вы можете просто передать слово %%(t)singular%%, чтобы Laravel использовал имена параметров по умолчанию, но при этом "выделил" их (сингуляризовал): ~%% Route::resource('users.photos', 'PhotoController', [ 'parameters' => 'singular' ]); // /users/{user}/photos/{photo} ~%% Или, вы можете глобально задать, чтобы параметры маршрута вашего ресурса были сингулярными, или задать глобальное сопоставление имён параметров ресурса: ~%% Route::singularResourceParameters(); Route::resourceParameters([ 'user' => 'person', 'photo' => 'image' ]); ~%% При изменении параметров ресурса важно помнить о приоритете именования: 1. Параметры явно передаются в %%Route::resource%%. 2. Глобальное сопоставление параметра задаётся в %%Route::resourceParameters%%. 3. Настройка %%(t)singular%% передаётся через массив %%(t)parameters%% в %%Route::resource%% или задаётся в %%Route::singularResourceParameters%%. 4. Поведение по умолчанию. %% === Добавление дополнительных маршрутов в контроллеры ресурсов === Если вам надо добавить дополнительные маршруты в контроллер ресурсов, не входящие в набор маршрутов ресурсов по умолчанию, их надо определить до вызова %%Route::resource%%, иначе определенные методом %%resource()%% маршруты могут нечаянно "победить" ваши дополнительные маршруты: %% Route::get('photos/popular', 'PhotoController@method'); Route::resource('photos', 'PhotoController'); %% .(alert) Старайтесь, чтобы контроллеры были узкоспециализированными. Если вам постоянно требуются методы вне стандартного набора действий с ресурсами, попробуйте разделить контроллер на два небольших контроллера. %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) == Неявные контроллеры == Laravel позволяет вам легко создавать единый маршрут для обработки всех //действий// в классе контроллера. Для начала зарегистрируйте маршрут методом %%Route::controller()%%. Этот метод принимает два аргумента. Первый - обрабатываемый контроллером базовый ((ВП:URI)), а второй - имя класса контроллера: ~%% Route::controller('users', 'UserController'); ~%% После регистрации просто добавьте методы в контроллер, назвав их по имени URI с большой буквы и с префиксом в виде типа HTTP-запроса (//HTTP verb//), который они обрабатывают: ~%% 'user.show', ]); %% == Внедрение зависимостей и контроллеры == **Внедрение в конструктор** ((/docs/v5/container Сервис-контейнер)) в Laravel используется для работы всех контроллеров Laravel. В результате вы можете указывать типы любых зависимостей, которые могут потребоваться вашему контроллеру в его конструкторе. Заявленные зависимости будут автоматически получены и внедрены в экземпляр контроллера: %% users = $users; } } %% Разумеется, вы можете также указать тип любого ((/docs/v5/contracts контракта Laravel)). Если контейнер может с ним работать, значит вы можете указывать его тип. В некоторых случаях внедрение зависимостей в контроллер обеспечивает лучшую тестируемость приложения. **Внедрение в метод** Кроме внедрения в конструктор, вы также можете указывать типы зависимостей в методах вашего контроллера. Распространённый пример внедрения в метод - внедрение экземпляра %%(t)Illuminate\Http\Request%% в один из методов контроллера: %% name; // } } %% Если метод вашего контроллера также ожидает данных из параметра маршрута, просто перечислите аргументы маршрута после остальных зависимостей. Например, если ваш маршрут определён так: %% Route::put('user/{id}', 'UserController@update'); %% Вы по-прежнему можете указать тип %%(t)Illuminate\Http\Request%% и обращаться к параметру %%(t)id%%, определив метод контроллера вот так: %%