Может войдёшь?
Черновики Написать статью Профиль

Контроллеры

перевод документация 5.х

  1. 1. Введение
  2. 2. Простейшие контроллеры
    1. 2.1. Определение контроллеров
    2. 2.2. Контроллеры и пространства имён
    3. 2.3. Контроллеры одного действия
  3. 3. Посредник контроллера
  4. 4. Контроллеры ресурсов
    1. 4.1. Частичные маршруты ресурсов
    2. 4.2. Именование маршрутов ресурсов
    3. 4.3. Именование параметров маршрута ресурса
    4. 4.4. Добавление дополнительных маршрутов в контроллеры ресурсов
  5. 5. Неявные контроллеры
  6. 6. Внедрение зависимостей и контроллеры
  7. 7. Кэширование маршрутов
Этот перевод актуален для англоязычной документации на (ветка 5.3) , (ветка 5.2) , (ветка 5.1) и (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Введение

Вместо того, чтобы определять всю логику обработки запросов в виде замыканий в файлах маршуртов, вы можете организовать её с помощью классов контроллеров. Контроллеры могут группировать связанную с обработкой HTTP-запросов логику в отдельный класс. Контроллеры хранятся в папке app/Http/Controllers.

Простейшие контроллеры

Определение контроллеров

Ниже приведён пример простейшего класса контроллера. Обратите внимание, контроллер наследует базовый класс контроллера, встроенный в Laravel. Базовый класс предоставляет несколько удобных методов, таких как метод PHPmiddleware(), используемый для назначения посредников на действия контроллера:

PHP
<?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) этого контроллера вот так:

PHP
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, то вам надо зарегистрировать маршруты к контроллеру вот так:

PHP
Route::get('foo''Photos\AdminController@method');
+ 5.3

добавлено в 5.3 ()

Контроллеры одного действия

Для определения контроллера, обрабатывающего всего одно действие, поместите в контроллер единственный метод PHP__invoke():

PHP
<?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)]);
  }
}

При регистрации маршрутов для контроллеров одного действия вам не надо указывать метод:

PHP
Route::get('user/{id}''ShowProfile');
+ 5.2 5.1 5.0

добавлено в 5.2 () 5.1 () 5.0 ()

Имена маршрутов контроллеров

Подобно маршрутам замыканий, вы можете указать имена для маршрутов контроллеров:

PHP
Route::get('foo', ['uses' => 'FooController@method''as' => 'name']);

Также вы можете использовать вспомогательную функцию PHProute(), чтобы сгенерировать URL маршрута названного контроллера:

PHP
$url route('name');
+ 5.1 5.0

добавлено в 5.1 () 5.0 ()

URL-адреса для действий контроллера

Также вы можете использовать вспомогательный метод PHPaction(), чтобы сгенерировать URL, используя имена классов и методов контроллера. И снова, нам надо указать только ту часть имени контроллера, которая идёт после базового пространства имён App\Http\Controllers:

PHP
$url action('FooController@method');

Получить имя действия, которое выполняется в данном запросе, можно методом PHPcurrentRouteAction() фасада Route:

PHP
$action Route::currentRouteAction();
+ 5.0

добавлено в 5.0 ()

Для получения URL для действия контроллера используйте метод PHPaction():

PHP
$url action('App\Http\Controllers\FooController@method');

Если вы хотите получить URL для действия контроллера, используя только часть имени класса относительно пространства имён контроллера, зарегистрируйте корневое пространство имён контроллера с помощью генератора URL:

PHP
URL::setRootControllerNamespace('App\Http\Controllers');

$url action('FooController@method');

Посредник контроллера

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

+ 5.3

добавлено в 5.3 ()

PHP
Route::get('profile''UserController@show')->middleware('auth');
+ 5.2 5.1 5.0

добавлено в 5.2 () 5.1 () 5.0 ()

PHP
Route::get('profile', [
  
'middleware' => 'auth',
  
'uses' => 'UserController@showProfile'
]);

Но удобнее указать посредника в конструкторе вашего контроллера. Используя метод PHPmiddleware() в конструкторе контроллера, вы легко можете назначить посредника для действия контроллера. Вы можете даже ограничить использование посредника, назначив его только для определённых методов класса контроллера:

+ 5.3

добавлено в 5.3 ()

PHP
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

добавлено в 5.2 () 5.1 () 5.0 ()

PHP
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

добавлено в 5.3 ()

Контроллеры также позволяют регистрировать посредников с помощью замыканий. Это удобный способ определения посредника для одного контроллера, не требующий определения целого класса посредника:

PHP
$this->middleware(function ($request$next) {
  
// ...

  
return $next($request);
});

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

Контроллеры ресурсов

Маршрутизация ресурсов Laravel назначает обычные CRUD-маршруты на контроллеры одной строчкой кода. Например, вы можете создать контроллер, обрабатывающий все HTTP-запросы к фотографиям, хранимым вашим приложением. Вы можете быстро создать такой контроллер с помощью Artisan-команды shmake:controller:

+ 5.3 5.2

добавлено в 5.3 () 5.2 ()

shphp artisan make:controller PhotoController --resource
+ 5.1 5.0

добавлено в 5.1 () 5.0 ()

shphp artisan make:controller PhotoController

Эта команда сгенерирует контроллер app/Http/Controllers/PhotoController.php. Контроллер будет содержать метод для каждой доступной операции с ресурсами.

Теперь мы можем зарегистрировать маршрут контроллера ресурса:

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.2 5.1 5.0

добавлено в 5.2 () 5.1 () 5.0 ()

Не забывайте, поскольку HTML-формы не могут выполнять запросы PUT, PATCH и DELETE, вам надо будет добавить скрытое поле _method, для спуффинга этих HTTP-команд:

PHP
<input type="hidden" name="_method" value="PUT">
+ 5.3

добавлено в 5.3 ()

Подмена методов формы

Поскольку HTML-формы не могут выполнять запросы PUT, PATCH и DELETE, вам надо добавить скрытое поле _method для подмены этих HTTP-запросов. Вспомогательный метод PHPmethod_field() создаст это поле для вас:

PHP
{{ method_field('PUT') }}

Частичные маршруты ресурсов

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

PHP
Route::resource('photo''PhotoController', ['only' => [
    
'index''show'
]]);

Route::resource('photo''PhotoController', ['except' => [
    
'create''store''update''destroy'
]]);

Именование маршрутов ресурсов

По умолчанию все действия контроллера ресурсов имеют имена маршрутов, но вы можете переопределить эти имена, передав массив names вместе с остальными параметрами:

PHP
Route::resource('photo''PhotoController', ['names' => [
    
'create' => 'photo.build'
]]);
+ 5.1 5.0

добавлено в 5.1 () 5.0 ()

Вложенные ресурсы

Иногда необходимо определить маршруты для «вложенных» ресурсов. Например, фото-ресурс может иметь множество «комментариев», которые могут быть прикреплены к фотографии. Используйте «точечную» нотацию в объявлении маршрута для контроллеров «вложенных» ресурсов:

PHP
Route::resource('photos.comments''PhotoCommentController');

Этот маршрут зарегистрирует «вложенный» ресурс, к которому можно обратиться по такому URL: photos/{photos}/comments/{comments}.

PHP
<?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)
  {
    
//
  
}
}
+ 5.3 5.2

добавлено в 5.3 () 5.2 ()

Именование параметров маршрута ресурса

По умолчанию PHPRoute::resource создаст параметры для ваших маршрутов ресурсов на основе имени ресурса в единственном числе. Это легко можно изменить для каждого ресурса, передав parameters в массив опций. Массив parameters должен быть ассоциативным массивом имён ресурсов и имён параметров:

PHP
Route::resource('user''AdminUserController', ['parameters' => [
    
'user' => 'admin_user'
]]);

Этот пример генерирует следующие URI для маршрута ресурса show:

PHP
/user/{admin_user}
+ 5.2

добавлено в 5.2 ()

Вместо передачи массива имён параметров вы можете просто передать слово singular, чтобы Laravel использовал имена параметров по умолчанию, но при этом «выделил» их (сингуляризовал):

PHP
Route::resource('users.photos''PhotoController', [
    
'parameters' => 'singular'
]);

// /users/{user}/photos/{photo}

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

PHP
Route::singularResourceParameters();

Route::resourceParameters([
    
'user' => 'person''photo' => 'image'
]);

При изменении параметров ресурса важно помнить о приоритете именования:

  1. Параметры явно передаются в PHPRoute::resource.
  2. Глобальное сопоставление параметра задаётся в PHPRoute::resourceParameters.
  3. Настройка singular передаётся через массив parameters в PHPRoute::resource или задаётся в PHPRoute::singularResourceParameters.
  4. Поведение по умолчанию.

Добавление дополнительных маршрутов в контроллеры ресурсов

Если вам надо добавить дополнительные маршруты в контроллер ресурсов, не входящие в набор маршрутов ресурсов по умолчанию, их надо определить до вызова PHPRoute::resource, иначе определенные методом PHPresource() маршруты могут нечаянно «победить» ваши дополнительные маршруты:

PHP
Route::get('photos/popular''PhotoController@method');

Route::resource('photos''PhotoController');

Старайтесь, чтобы контроллеры были узкоспециализированными. Если вам постоянно требуются методы вне стандартного набора действий с ресурсами, попробуйте разделить контроллер на два небольших контроллера.

+ 5.1 5.0

добавлено в 5.1 () 5.0 ()

Неявные контроллеры

Laravel позволяет вам легко создавать единый маршрут для обработки всех действий в классе контроллера. Для начала зарегистрируйте маршрут методом PHPRoute::controller(). Этот метод принимает два аргумента. Первый — обрабатываемый контроллером базовый URI, а второй — имя класса контроллера:

PHP
Route::controller('users''UserController');

После регистрации просто добавьте методы в контроллер, назвав их по имени URI с большой буквы и с префиксом в виде типа HTTP-запроса (HTTP verb), который они обрабатывают:

PHP
<?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

добавлено в 5.0 ()

Если имя действия вашего контроллера состоит из нескольких слов вы можете обратиться к нему по URI, используя синтаксис с дефисами (-). Например, следующее действие в нашем классе UserController будет доступно по адресу users/admin-profile:

PHP
public function getAdminProfile() {}

Назначение имён маршрутов

Если вы хотите назвать некоторые маршруты в контроллере, вы можете передать массив имён в качестве третьего аргумента в метод PHPcontroller():

PHP
Route::controller('users''UserController', [
  
'getShow' => 'user.show',
]);

Внедрение зависимостей и контроллеры

Внедрение в конструктор

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

PHP
<?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
<?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;

    
//
  
}
}

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

PHP
Route::put('user/{id}''UserController@update');

Вы по-прежнему можете указать тип Illuminate\Http\Request и обращаться к параметру id, определив метод контроллера вот так:

PHP
<?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

добавлено в 5.0 ()

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

Кэширование маршрутов

Маршруты на основе замыканий нельзя кэшировать. Чтобы использовать кэширование маршрутов, необходимо перевести все маршруты замыканий на классы контроллера.

Если ваше приложение единолично использует маршруты контроллера, то вы можете воспользоваться преимуществом кэширования маршрутов в Laravel. Использование кэша маршрутов радикально уменьшит время, требуемое для регистрации всех маршрутов вашего приложения. В некоторых случаях регистрация ваших маршрутов может стать быстрее в 100 раз. Для создания кэша маршрутов просто выполните Artisan-команду shroute:cache:

shphp artisan route:cache

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

Для очистки кэша маршрутов используйте команду shroute:clear:

shphp artisan route:clear

Комментарии (12)

marcuzy

Для генерации контроллера с методами-заглушками к команде php artisan make:controller PhotoController нужно добавить параметр --resource

Ololosha

А как удалить контроллер? artisan --help не помог

zZz

Клавиша DELETE

Zaklinatel

Контроллер — это просто файл, содержащий ваш класс контроллера (наследуемый от абстракции контроллера фреймворка, скорее всего). Чтобы удалить контроллер, надо просто удалить класс (файл). Найти его можно в app/Http/Controllers/

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

Alexandr5

Почему статьи для опытных, 200 лет программирующих специалистов? Где пояснение как этим пользоваться, как получать, что с чем взаимодействует, как ресурсный получает все обработчики и выдаёт один путь?
Везде написано — что лишь есть и чем можно пользоваться. Нифига не понятно.

paganez

200 лет опыта не обязательно. У меня сразу во время прочтения складываются алгоритмы использования. Достаточно опыта разработки на любом фреймворке, особенно старого(я писал на CodeIgniter) — сразу замечаешь разницу в лучшую сторону

ArtemBusygin

Согласен! Если ранее не сталкивался с подобным, то ничего не понятно. Можно как-нибудь поподробнее?

Voker57

Нужно дописать что «Неявные контроллеры» не работают начиная с версии 5.3

marataziat

Не полностью! Все ещё можно использовать:

Route::resource('products', 'ProductsController');

Aslero

на сайте есть регистрация и авторизация, которые работают, но нет контроллера UserController для работы с пользователями как в админке так и на сайте, подскажите, мне его нужно создать?

JekaYaroshenko

Если контроллер создавался как ресурс с привязкой к модели

php artisan make:controller PhotoController --resource --model=Photo

То роут для этого обработчика неясно как будет принимать обьект, как-то через модель ?

public function show(Photo $photo){...
Route::get('photos/{photo}', 'PhotoController@show');

Но в роут show не приходит обьект,а только может $id прийти если переделать роут на

Route::get('photos/{id}', 'PhotoController@show');

Есть примеры работы с моделью?

Gamelot

Обязательно ли методы контроллера, указанные в маршруте, должны что-то возвращать?

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.