Введение
Вместо того, чтобы определять всю логику обработки запросов в виде замыканий в файлах маршуртов, вы можете организовать её с помощью классов контроллеров. Контроллеры могут группировать связанную с обработкой HTTP-запросов логику в отдельный класс. Контроллеры хранятся в папке app/Http/Controllers.
Простейшие контроллеры
Определение контроллеров
Ниже приведён пример простейшего класса контроллера. Обратите внимание, контроллер наследует базовый класс контроллера, встроенный в Laravel. Базовый класс предоставляет несколько удобных методов, таких как метод PHPmiddleware()
, используемый для назначения посредников на действия контроллера:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Показать профиль данного пользователя.
*
* @param int $id
* @return Response
*/
public function show($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
Мы можем определить маршрут для действия (action) этого контроллера вот так:
Route::get('user/{id}', 'UserController@show');
Теперь при соответствии запроса указанному URI маршрута будет выполняться метод PHPshow()
класса UserController. Само собой параметры маршрута также будут переданы в метод.
Контроллерам не обязательно наследовать базовый класс. Но тогда у вас не будет таких удобных возможностей, как методы PHPmiddleware()
, PHPvalidate()
и PHPdispatch()
.
Контроллеры и пространства имён
Важно помнить, что при определении маршрута контроллера нам не надо указывать полное пространство имён контроллера, а только ту часть имени класса, которая следует за «корнем» пространства имён — App\Http\Controllers. Потому что RouteServiceProvider загружает ваши файлы маршрутов вместе с группой маршрутизации, содержащей корневое пространство имён контроллера.
Если вы решите разместить свои контроллеры в поддиректориях App\Http\Controllers, то просто используйте конкретное имя класса относительно корня пространства имён App\Http\Controllers. Тогда, если полный путь к вашему классу будет App\Http\Controllers\Photos\AdminController, то вам надо зарегистрировать маршруты к контроллеру вот так:
Route::get('foo', 'Photos\AdminController@method');
добавлено в 5.3 ()
Контроллеры одного действия
Для определения контроллера, обрабатывающего всего одно действие, поместите в контроллер единственный метод PHP__invoke()
:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
/**
* Показать профиль данного пользователя.
*
* @param int $id
* @return Response
*/
public function __invoke($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
При регистрации маршрутов для контроллеров одного действия вам не надо указывать метод:
Route::get('user/{id}', 'ShowProfile');
добавлено в 5.2 () 5.1 () 5.0 ()
Подобно маршрутам замыканий, вы можете указать имена для маршрутов контроллеров:
Route::get('foo', ['uses' => 'FooController@method', 'as' => 'name']);
Также вы можете использовать вспомогательную функцию PHProute()
, чтобы сгенерировать URL маршрута названного контроллера:
$url = route('name');
URL-адреса для действий контроллера
Также вы можете использовать вспомогательный метод PHPaction()
, чтобы сгенерировать URL, используя имена классов и методов контроллера. И снова, нам надо указать только ту часть имени контроллера, которая идёт после базового пространства имён App\Http\Controllers:
$url = action('FooController@method');
Получить имя действия, которое выполняется в данном запросе, можно методом PHPcurrentRouteAction()
фасада Route:
$action = Route::currentRouteAction();
добавлено в 5.0 ()
Для получения URL для действия контроллера используйте метод PHPaction()
:
$url = action('App\Http\Controllers\FooController@method');
Если вы хотите получить URL для действия контроллера, используя только часть имени класса относительно пространства имён контроллера, зарегистрируйте корневое пространство имён контроллера с помощью генератора URL:
URL::setRootControllerNamespace('App\Http\Controllers');
$url = action('FooController@method');
Посредник контроллера
Посредник можно указать для маршрутов контроллера в файлах маршрутов:
добавлено в 5.2 () 5.1 () 5.0 ()
Route::get('profile', [
'middleware' => 'auth',
'uses' => 'UserController@showProfile'
]);
Но удобнее указать посредника в конструкторе вашего контроллера. Используя метод PHPmiddleware()
в конструкторе контроллера, вы легко можете назначить посредника для действия контроллера. Вы можете даже ограничить использование посредника, назначив его только для определённых методов класса контроллера:
добавлено в 5.3 ()
class UserController extends Controller
{
/**
* Создание нового экземпляра контроллера.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
добавлено в 5.2 () 5.1 () 5.0 ()
class UserController extends Controller
{
/**
* Создание нового экземпляра UserController.
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log', ['only' => [
'fooAction',
'barAction',
]]);
$this->middleware('subscribed', ['except' => [
'fooAction',
'barAction',
]]);
}
}
добавлено в 5.3 ()
Контроллеры также позволяют регистрировать посредников с помощью замыканий. Это удобный способ определения посредника для одного контроллера, не требующий определения целого класса посредника:
$this->middleware(function ($request, $next) {
// ...
return $next($request);
});
Вы можете назначить посредника на определённый набор действий контроллера, но если возникает такая необходимость, возможно ваш контроллер стал слишком велик. Вместо этого вы можете разбить контроллер на несколько маленьких контроллеров.
Контроллеры ресурсов
Маршрутизация ресурсов Laravel назначает обычные CRUD-маршруты на контроллеры одной строчкой кода. Например, вы можете создать контроллер, обрабатывающий все HTTP-запросы к фотографиям, хранимым вашим приложением. Вы можете быстро создать такой контроллер с помощью Artisan-команды shmake:controller
:
Эта команда сгенерирует контроллер app/Http/Controllers/PhotoController.php. Контроллер будет содержать метод для каждой доступной операции с ресурсами.
Теперь мы можем зарегистрировать маршрут контроллера ресурса:
Route::resource('photos', 'PhotoController');
Один этот вызов создаёт множество маршрутов для обработки различных действий для ресурса. Сгенерированный контроллер уже имеет методы-заглушки для каждого из этих действий с комментариями о том, какие URI и типы запросов они обрабатывают.
Действия, обрабатываемые контроллером ресурсов
Тип | 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 |
добавлено в 5.3 ()
Частичные маршруты ресурсов
При объявлении маршрута вы можете указать подмножество всех возможных действий, которые должен обрабатывать контроллер вместо полного набора стандартных действий:
Route::resource('photo', 'PhotoController', ['only' => [
'index', 'show'
]]);
Route::resource('photo', 'PhotoController', ['except' => [
'create', 'store', 'update', 'destroy'
]]);
Именование маршрутов ресурсов
По умолчанию все действия контроллера ресурсов имеют имена маршрутов, но вы можете переопределить эти имена, передав массив names вместе с остальными параметрами:
Route::resource('photo', 'PhotoController', ['names' => [
'create' => 'photo.build'
]]);
Иногда необходимо определить маршруты для «вложенных» ресурсов. Например, фото-ресурс может иметь множество «комментариев», которые могут быть прикреплены к фотографии. Используйте «точечную» нотацию в объявлении маршрута для контроллеров «вложенных» ресурсов:
Route::resource('photos.comments', 'PhotoCommentController');
Этот маршрут зарегистрирует «вложенный» ресурс, к которому можно обратиться по такому URL: photos/{photos}/comments/{comments}.
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class PhotoCommentController extends Controller
{
/**
* Показать определённый комментарий к фото.
*
* @param int $photoId
* @param int $commentId
* @return Response
*/
public function show($photoId, $commentId)
{
//
}
}
Именование параметров маршрута ресурса
По умолчанию PHPRoute::resource
создаст параметры для ваших маршрутов ресурсов на основе имени ресурса в единственном числе. Это легко можно изменить для каждого ресурса, передав parameters в массив опций. Массив parameters должен быть ассоциативным массивом имён ресурсов и имён параметров:
Route::resource('user', 'AdminUserController', ['parameters' => [
'user' => 'admin_user'
]]);
Этот пример генерирует следующие URI для маршрута ресурса show:
/user/{admin_user}
добавлено в 5.2 ()
Вместо передачи массива имён параметров вы можете просто передать слово singular, чтобы Laravel использовал имена параметров по умолчанию, но при этом «выделил» их (сингуляризовал):
Route::resource('users.photos', 'PhotoController', [
'parameters' => 'singular'
]);
// /users/{user}/photos/{photo}
Или, вы можете глобально задать, чтобы параметры маршрута вашего ресурса были сингулярными, или задать глобальное сопоставление имён параметров ресурса:
Route::singularResourceParameters();
Route::resourceParameters([
'user' => 'person', 'photo' => 'image'
]);
При изменении параметров ресурса важно помнить о приоритете именования:
- Параметры явно передаются в
PHPRoute::resource
. - Глобальное сопоставление параметра задаётся в
PHPRoute::resourceParameters
. - Настройка singular передаётся через массив parameters в
PHPRoute::resource
или задаётся вPHPRoute::singularResourceParameters
. - Поведение по умолчанию.
Добавление дополнительных маршрутов в контроллеры ресурсов
Если вам надо добавить дополнительные маршруты в контроллер ресурсов, не входящие в набор маршрутов ресурсов по умолчанию, их надо определить до вызова PHPRoute::resource
, иначе определенные методом PHPresource()
маршруты могут нечаянно «победить» ваши дополнительные маршруты:
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
Старайтесь, чтобы контроллеры были узкоспециализированными. Если вам постоянно требуются методы вне стандартного набора действий с ресурсами, попробуйте разделить контроллер на два небольших контроллера.
Неявные контроллеры
Laravel позволяет вам легко создавать единый маршрут для обработки всех действий в классе контроллера. Для начала зарегистрируйте маршрут методом PHPRoute::controller()
. Этот метод принимает два аргумента. Первый — обрабатываемый контроллером базовый URI, а второй — имя класса контроллера:
Route::controller('users', 'UserController');
После регистрации просто добавьте методы в контроллер, назвав их по имени URI с большой буквы и с префиксом в виде типа HTTP-запроса (HTTP verb), который они обрабатывают:
<?php
namespace App\Http\Controllers;
class UserController extends Controller
{
/**
* Отклик на запрос GET /users
*/
public function getIndex()
{
//
}
/**
* Отклик на запрос GET /users/show/1
*/
public function getShow($id)
{
//
}
/**
* Отклик на запрос GET /users/admin-profile
*/
public function getAdminProfile()
{
//
}
/**
* Отклик на запрос POST /users/profile
*/
public function postProfile()
{
//
}
}
Как видите, в этом примере методы index обрабатывают корневой URI контроллера — в нашем случае это users.
добавлено в 5.0 ()
Если вы хотите назвать некоторые маршруты в контроллере, вы можете передать массив имён в качестве третьего аргумента в метод PHPcontroller()
:
Route::controller('users', 'UserController', [
'getShow' => 'user.show',
]);
Внедрение зависимостей и контроллеры
Сервис-контейнер в Laravel используется для работы всех контроллеров Laravel. В результате вы можете указывать типы любых зависимостей, которые могут потребоваться вашему контроллеру в его конструкторе. Заявленные зависимости будут автоматически получены и внедрены в экземпляр контроллера:
<?php
namespace App\Http\Controllers;
//для версии 5.1 и ранее:
//use Illuminate\Routing\Controller;
use App\Repositories\UserRepository;
class UserController extends Controller
{
/**
* Экземпляр репозитория пользователя.
*/
protected $users;
/**
* Создание нового экземпляра контроллера.
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
Разумеется, вы можете также указать тип любого контракта Laravel. Если контейнер может с ним работать, значит вы можете указывать его тип. В некоторых случаях внедрение зависимостей в контроллер обеспечивает лучшую тестируемость приложения.
Кроме внедрения в конструктор, вы также можете указывать типы зависимостей в методах вашего контроллера. Распространённый пример внедрения в метод — внедрение экземпляра Illuminate\Http\Request в один из методов контроллера:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
//для версии 5.1 и ранее:
//use Illuminate\Routing\Controller;
class UserController extends Controller
{
/**
* Сохранить нового пользователя.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->name;
//
}
}
Если метод вашего контроллера также ожидает данных из параметра маршрута, просто перечислите аргументы маршрута после остальных зависимостей. Например, если ваш маршрут определён так:
Route::put('user/{id}', 'UserController@update');
Вы по-прежнему можете указать тип Illuminate\Http\Request и обращаться к параметру id, определив метод контроллера вот так:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
//для версии 5.1 и ранее:
//use Illuminate\Routing\Controller;
class UserController extends Controller
{
/**
* Обновить данного пользователя.
*
* @param Request $request
* @param string $id
*
* //для версии 5.1 и ранее
* @param int $id
*
* @return Response
*/
public function update(Request $request, $id)
{
//
}
}
добавлено в 5.0 ()
Внедрение в метод полностью совместимо с привязкой к модели. Контейнер автоматически определит, какие из аргументов привязаны к модели, а какие аргументы должны быть внедрены.
Кэширование маршрутов
Маршруты на основе замыканий нельзя кэшировать. Чтобы использовать кэширование маршрутов, необходимо перевести все маршруты замыканий на классы контроллера.
Если ваше приложение единолично использует маршруты контроллера, то вы можете воспользоваться преимуществом кэширования маршрутов в Laravel. Использование кэша маршрутов радикально уменьшит время, требуемое для регистрации всех маршрутов вашего приложения. В некоторых случаях регистрация ваших маршрутов может стать быстрее в 100 раз. Для создания кэша маршрутов просто выполните Artisan-команду shroute:cache
:
shphp artisan route:cache
После выполнения этой команды ваши кэшированные маршруты будут загружаться при каждом запросе. Помните, после добавления новых маршрутов, вам необходимо заново сгенерировать свежий кэш маршрутов. Поэтому нужно выполнить команду shroute:cache
уже при развёртывании вашего проекта.
Для очистки кэша маршрутов используйте команду shroute:clear
:
shphp artisan route:clear
Комментарии (12)
Для генерации контроллера с методами-заглушками к команде
php artisan make:controller PhotoController
нужно добавить параметр --resourceА как удалить контроллер? artisan --help не помог
Клавиша DELETE
Контроллер — это просто файл, содержащий ваш класс контроллера (наследуемый от абстракции контроллера фреймворка, скорее всего). Чтобы удалить контроллер, надо просто удалить класс (файл). Найти его можно в app/Http/Controllers/
Артисан для этого не нужен. Он просто помогает создавать шаблоны этих классов, чтобы вам меньше было писать кода. Удалить вы можете и сами.
Почему статьи для опытных, 200 лет программирующих специалистов? Где пояснение как этим пользоваться, как получать, что с чем взаимодействует, как ресурсный получает все обработчики и выдаёт один путь?
Везде написано — что лишь есть и чем можно пользоваться. Нифига не понятно.
200 лет опыта не обязательно. У меня сразу во время прочтения складываются алгоритмы использования. Достаточно опыта разработки на любом фреймворке, особенно старого(я писал на CodeIgniter) — сразу замечаешь разницу в лучшую сторону
Согласен! Если ранее не сталкивался с подобным, то ничего не понятно. Можно как-нибудь поподробнее?
Нужно дописать что «Неявные контроллеры» не работают начиная с версии 5.3
Не полностью! Все ещё можно использовать:
Route::resource('products', 'ProductsController');
на сайте есть регистрация и авторизация, которые работают, но нет контроллера UserController для работы с пользователями как в админке так и на сайте, подскажите, мне его нужно создать?
Если контроллер создавался как ресурс с привязкой к модели
То роут для этого обработчика неясно как будет принимать обьект, как-то через модель ?
Но в роут
show
не приходит обьект,а только может$id
прийти если переделать роут наЕсть примеры работы с моделью?
Обязательно ли методы контроллера, указанные в маршруте, должны что-то возвращать?