{{TOC}} == Основы == **Контроллеры** - это классы, принимающие пользовательский ввод и взаимодействующие с //((docs/v3/models моделями))//, //((docs/v3/models библиотеками))// и //видами// (представлениями, "views"). В общем случае они запрашивают у //модели// данные и передают его //виду//, который формирует страницу, передаваемую клиенту. Использование //контроллеров// - обычная практика в современных вёб-приложениях, однако Laravel также позволяет разработчику реализовать собственную логику используя **((docs/v3/routing маршруты))** ("routes"). Новичкам следует начать с использования //контроллеров//, хотя в них нет ничего, что нельзя было бы реализовать с помощью //маршрутов//. **Классы контроллеров** хранятся в **application/controllers** и наследуются от класса %%Base_Controller%%. Изначально Laravel также содержит класс-заготовку %%Home_Controller%% для отображения домашней страницы (//вида// %%(t)home.index%%). === Простейший контроллер === %% class Admin_Controller extends Base_Controller { public function action_index() { // код отображения страницы index. } } %% ((#действия)) **Действия** ("actions") - это методы //контроллера//, которые должны быть доступны при запросе из сети. Методы //действий// начинаются с %%(t)action_%%; все прочие методы класса-контроллера будут не доступны из сети. %%Base_Controller%% расширяет фундаментальный класс %%Controller%% - вы можете поместить в него свои методы, используемые многими вашими //контроллерами// и наследовать их классы от него. == Маршрутизация == Важно понимать, что в Laravel все //((docs/v3/routing маршруты))// ("routes") должны быть явно зарегистрированы - даже те, что обрабатываются //контроллерами//. Это значит, что методы //контроллера//, которые не были зарегистрированы не доступны запросам из сети. Однако есть возможность автоматически зарегистрировать все //((#действия)) контроллера// - обычно это делается в **application/routes.php** (см. "((docs/v3/routing))"). == ((#пакеты)) Контроллеры в пакетах == Laravel предоставляет систему **пакетов**, или **сборок** ("bundles") - независимых модулей, которые вы можете использовать в своём приложении. //Пакеты// могут быть назначены на обработчики определённых запросов - см. "((docs/v3/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", открыв эту страницу в браузере: %%(t) http://localhost/home/ %% А если для этого //контроллера// была задана опция **handles** в **application/routes.php** (например, %%(t)admin%%) - то адрес доступа будет выглядеть так: %%(t) http://localhost/admin/home/ %% **Двойное двоеточие** (%%(t)::%%) используется в различных функциях Laravel для задания имени //((docs/v3/bundles пакета))//. == Фильтры для действий == **Фильтры** - это метод, вызываемые до или после вызова определённого //((#действия)) контроллера// ("controller action"). В Laravel, вы можете не только привязывать //фильтры// к //действиям//, но и определять, для какого из метода запроса ((ВП:HTTP)) (//GET//, //POST//, //PUT// или //DELETE//) этот //фильтр// будет вызван. Вы можете привязать //фильтр// "до" (**before**) или "после" (**after**) из конструктора класса-контроллера - например, так можно **привязать //фильтр// ко всем его действиям**: %% $this->filter('before', 'auth'); %% В этом примере //фильтр// **auth** будет вызван //перед// (before) вызовом любого действия, принадлежащего этому //контроллеру//. Действие **auth** - стандартное для Laravel и умолчательный обработчик для него уже задан в **application/routes.php** - если клиент не вошёл в систему, он переадресует его на форму авторизации. === ((#fo)) Привязка к действиям === %% $this->filter('before', 'auth')->only(array('index', 'list')); %% В этом примере //((#фильтр+ы))// **auth** будет вызван перед вызовом метода-действия %%action_index%% или %%action_list%% текущего контроллера (%%$this%%). Клиент должен быть авторизован для того, чтобы они были вызваны (таким образом, их страницы не будут доступны). Однако для всех других ((#действи+я))й этого не требуется. === Привязка ко всем, кроме... === %% $this->filter('before', 'auth')->except(array('add', 'posts')); %% Этот пример напоминает ((#fo пример выше)) - он привязывает //((#фильтр+ы))// к методам текущего //контроллера//, но не ко всем перечисленным, а **ко всем, кроме перечисленных**.. Это значит, что здесь мы определяем ((#действия)), для которых **не будет** запрошена авторизация - используется метод %%Filter_Collection->except%%. Иногда этот подход более безопасен, так как можно добавлять к //контроллеру// новые ((#действия)) без опасения забыть перечислить их в списке, требующих авторизации. === Привязка к POST-запросу === %% $this->filter('before', 'csrf')->on('post'); %% Этот пример показывает, как ((#фильтр+ы)) может быть привязан к определённому виду HTTP-запроса (так называемый "verb"). В этом случае //фильтр// **csrf** Будет вызван только для //POST//-запроса, то есть когда была отправлена форма. //Фильтр// **csrf** позволяет заблокировать отправку формы, которая не была заполнена непосредственно самим клиентом - это один из приёмов ((ВП:фишинга)), см. статью ((ВП:CSRF)). Фильтр **csrf** включен в состав Laravel и по умолчанию определён в **application/routes.php**. .(further_reading) Связанные темы: * ((docs/v3/routing#фильтры Фильтры маршрутов)) == Вложенные контроллеры == //Контроллеры// могут быть расположены в любой папке любой вложенности внутри **application/controllers**. Например, для определения //подконтроллера// "panel" //контроллера// "admin" поместите код его класса в **controllers/admin/panel.php**: %% class Admin_Panel_Controller extends Base_Controller { public function action_index() { // код действия index. } } %% Теперь зарегистрируйте вложенный //контроллер// в списке //маршрутов// используя синтаксис с точками: %% Route::controller('admin.panel'); %% .(alert) **Внимание:** регистрируя вложенные //контроллеры// всегда начинайте с самых вложенных, чтобы маршруты внешних //контроллеров// не перекрывали вложенные. Теперь этот //контроллер// доступен по этому адресу: %%(t) http://localhost/admin/panel %% == REST-контроллеры == **((ВП:REST))** (//передача состояния представления//, //Representational State Transfer//) - способ передачи информации о предыдущих действиях клиента в рамках его сессии. Сюда относятся, например, поля заполненной на предыдущей странице формы. Если имя метода ((#действи+я))е //контроллера// начинается не с %%(t)action_%%, а с одного из форм HTTP-запросов, то он будет отвечать только на него. Это требует **добавить свойство "restful" в класс-контроллер**: %% class Home_Controller extends Base_Controller { public $restful = true; } %% **Задание REST-действий:** %% class Home_Controller extends Base_Controller { public $restful = true; public function get_index() { // обработка GET-запроса страницы index. } public function post_index() { // обработка POST-запроса страницы index. } } %% Это особенно удобно при создании ((ВП:CRUD))-методов - вы можете отделить код, заполняющий и выводящий форму от кода проверки и сохранения её данных. == Внедрение зависимостей == Если вы стремитесь писать тестируемый код вы, возможно, хотите указать зависимости в конструкторе вашего //контроллера//. Это не проблема - просто зарегистрируйте его в ((docs/v3/ioc IoC-контейнере)), не забыв поставить перед ним префикс %%(t)controller:%%. Мы можем зарегистрировать наш //контроллер// **user** в **application/start.php**: %% IoC::register('controller: user', function () { return new User_Controller; }); %% Когда будет получен запрос вызова этого контроллера Laravel автоматически определит, зарегистрирован ли он в //контейнере// и если да, то он использует его для создания экземпляра класса //контроллера//. Перед внедрением зависимостей ознакомьтесь со статьёй об ((docs/v3/ioc IoC-контейнере)). == Фабрика контроллеров == Если вам нужно ещё больше контроля за созданием экземпляров класса-контроллера, например, при использовании стороннего //IoC-контейнера//, то обратитесь к **фабрике контроллеров**. **Регистрация события, создающего экземпляр //контроллера//:** %% Event::listen(Controller::factory, function ($controller) { return new $controller; }); %% Событие %%Controller::factory%% принимает имя //контроллера//, который должен быть создан. Всё, что вам нужно - вернуть экземпляр его класса.