Основы
Контроллеры — это классы, принимающие пользовательский ввод и взаимодействующие с моделями, библиотеками и видами (представлениями, «views»). В общем случае они запрашивают у модели данные и передают его виду, который формирует страницу, передаваемую клиенту.
Использование контроллеров — обычная практика в современных вёб-приложениях, однако Laravel также позволяет разработчику реализовать собственную логику используя маршруты («routes»). Новичкам следует начать с использования контроллеров, хотя в них нет ничего, что нельзя было бы реализовать с помощью маршрутов.
Классы контроллеров хранятся в application/controllers и наследуются от класса PHPBase_Controller
. Изначально Laravel также содержит класс-заготовку PHPHome_Controller
для отображения домашней страницы (вида home.index).
Простейший контроллер
class Admin_Controller extends Base_Controller {
public function action_index() {
// код отображения страницы index.
}
}
Действия («actions») — это методы контроллера, которые должны быть доступны при запросе из сети. Методы действий начинаются с action_; все прочие методы класса-контроллера будут не доступны из сети.
PHPBase_Controller
расширяет фундаментальный класс PHPController
— вы можете поместить в него свои методы, используемые многими вашими контроллерами и наследовать их классы от него.
Маршрутизация
Важно понимать, что в Laravel все маршруты («routes») должны быть явно зарегистрированы — даже те, что обрабатываются контроллерами.
Это значит, что методы контроллера, которые не были зарегистрированы не доступны запросам из сети. Однако есть возможность автоматически зарегистрировать все действия контроллера — обычно это делается в application/routes.php (см. «Маршрутизация»).
Контроллеры в пакетах
Laravel предоставляет систему пакетов, или сборок («bundles») — независимых модулей, которые вы можете использовать в своём приложении. Пакеты могут быть назначены на обработчики определённых запросов — см. «Пакеты».
Создание контроллеров, принадлежащих пакету, почти не отличается от создания обычных контроллеров для вашего вёб-приложения (в application/controllers) — для начала начните имя класса-контроллеров с имени пакета. Например, для пакета «admin» класс-контроллер «home» может выглядеть так:
class Admin_Home_Controller extends Base_Controller {
public function action_index() {
return "Hello Admin!";
}
}
Как зарегистрировать пакетный контроллер? Просто:
Route::controller('admin::home');
Отлично! Теперь мы можем запросить наш контроллер «home» пакета «admin», открыв эту страницу в браузере:
http://localhost/home/
А если для этого контроллера была задана опция handles в application/routes.php (например, admin) — то адрес доступа будет выглядеть так:
http://localhost/admin/home/
Двойное двоеточие (::) используется в различных функциях Laravel для задания имени пакета.
Фильтры для действий
Фильтры — это метод, вызываемые до или после вызова определённого действия контроллера («controller action»). В Laravel, вы можете не только привязывать фильтры к действиям, но и определять, для какого из метода запроса HTTP (GET, POST, PUT или DELETE) этот фильтр будет вызван.
Вы можете привязать фильтр «до» (before) или «после» (after) из конструктора класса-контроллера — например, так можно привязать фильтр ко всем его действиям:
$this->filter('before', 'auth');
В этом примере фильтр auth будет вызван перед (before) вызовом любого действия, принадлежащего этому контроллеру. Действие auth — стандартное для Laravel и умолчательный обработчик для него уже задан в application/routes.php — если клиент не вошёл в систему, он переадресует его на форму авторизации.
Привязка к действиям
$this->filter('before', 'auth')->only(array('index', 'list'));
В этом примере фильтр auth будет вызван перед вызовом метода-действия PHPaction_index
или PHPaction_list
текущего контроллера (PHP$this
). Клиент должен быть авторизован для того, чтобы они были вызваны (таким образом, их страницы не будут доступны). Однако для всех других действий этого не требуется.
Привязка ко всем, кроме...
$this->filter('before', 'auth')->except(array('add', 'posts'));
Этот пример напоминает пример выше — он привязывает фильтр к методам текущего контроллера, но не ко всем перечисленным, а ко всем, кроме перечисленных.. Это значит, что здесь мы определяем действия, для которых не будет запрошена авторизация — используется метод PHPFilter_Collection->except
.
Иногда этот подход более безопасен, так как можно добавлять к контроллеру новые действия без опасения забыть перечислить их в списке, требующих авторизации.
Привязка к POST-запросу
$this->filter('before', 'csrf')->on('post');
Этот пример показывает, как фильтр может быть привязан к определённому виду HTTP-запроса (так называемый «verb»). В этом случае фильтр csrf Будет вызван только для POST-запроса, то есть когда была отправлена форма. Фильтр csrf позволяет заблокировать отправку формы, которая не была заполнена непосредственно самим клиентом — это один из приёмов фишинга, см. статью CSRF.
Фильтр csrf включен в состав Laravel и по умолчанию определён в application/routes.php.
Вложенные контроллеры
Контроллеры могут быть расположены в любой папке любой вложенности внутри application/controllers.
Например, для определения подконтроллера «panel» контроллера «admin» поместите код его класса в controllers/admin/panel.php:
class Admin_Panel_Controller extends Base_Controller {
public function action_index() {
// код действия index.
}
}
Теперь зарегистрируйте вложенный контроллер в списке маршрутов используя синтаксис с точками:
Route::controller('admin.panel');
Внимание: регистрируя вложенные контроллеры всегда начинайте с самых вложенных, чтобы маршруты внешних контроллеров не перекрывали вложенные.
Теперь этот контроллер доступен по этому адресу:
http://localhost/admin/panel
REST-контроллеры
REST (передача состояния представления, Representational State Transfer) — способ передачи информации о предыдущих действиях клиента в рамках его сессии. Сюда относятся, например, поля заполненной на предыдущей странице формы.
Если имя метода действие контроллера начинается не с action_, а с одного из форм HTTP-запросов, то он будет отвечать только на него. Это требует добавить свойство «restful» в класс-контроллер:
class Home_Controller extends Base_Controller {
public $restful = true;
}
class Home_Controller extends Base_Controller {
public $restful = true;
public function get_index() {
// обработка GET-запроса страницы index.
}
public function post_index() {
// обработка POST-запроса страницы index.
}
}
Это особенно удобно при создании CRUD-методов — вы можете отделить код, заполняющий и выводящий форму от кода проверки и сохранения её данных.
Внедрение зависимостей
Если вы стремитесь писать тестируемый код вы, возможно, хотите указать зависимости в конструкторе вашего контроллера. Это не проблема — просто зарегистрируйте его в IoC-контейнере, не забыв поставить перед ним префикс controller:. Мы можем зарегистрировать наш контроллер user в application/start.php:
IoC::register('controller: user', function () {
return new User_Controller;
});
Когда будет получен запрос вызова этого контроллера Laravel автоматически определит, зарегистрирован ли он в контейнере и если да, то он использует его для создания экземпляра класса контроллера.
Перед внедрением зависимостей ознакомьтесь со статьёй об IoC-контейнере.
Фабрика контроллеров
Если вам нужно ещё больше контроля за созданием экземпляров класса-контроллера, например, при использовании стороннего IoC-контейнера, то обратитесь к фабрике контроллеров.
Регистрация события, создающего экземпляр контроллера:
Event::listen(Controller::factory, function ($controller) {
return new $controller;
});
Событие PHPController::factory
принимает имя контроллера, который должен быть создан. Всё, что вам нужно — вернуть экземпляр его класса.