Знакомимся с Laravel routing и controllers

Автор: | 26.05.2017

laravel-routing-i-controllersВсем доброго времени суток!

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

На данный момент мы уже установили HTML-шаблон, откорректировали его для своих нужд и сделали «хлебные крошки» с помощью Laravel middleware.

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

Не буду затягивать со вступительным словом. Начинаем :-)

СОДЕРЖАНИЕ

Laravel routing — что, как, зачем?

Laravel routing — это механизм, позволяющий связывать url нашего приложения с какими-то конкретными действиями.

К примеру, у нас есть страница с url ‘http://site.com/contacts’. Как нам сообщить нашему сайту, что, когда в приложение поступает запрос по данному url, нужно выполнить какую-то функцию?

Если бы мы делали самописный движок сайта на чистом PHP, то мы бы написали в нашем index.php (поскольку данный файл распознаётся веб-серверами как точка входа) нечто следующее:

$url = $_SERVER['REQUEST_URI'];
if($url == '/contacts')
{
    //какое-то действие
    echo 'Это страница контактов';
}

else die('404');

Суть в том, что мы проверяем url, по которому поступил запрос в приложение, и при определённых значениях выполняем какие-то действия.

И так для каждого url, который должен быть обработан нашим веб-приложением, т.е. сайтом. Для всех остальных будет выдаваться 404 ошибка.

Какие тут минусы?

  • Во-первых, приведённый выше способ обработки применим только к простым url и абсолютно не учитывает параметры и тип запроса, а также много других факторов;
  • Во-вторых, для сложных url нужно будет ещё писать парсер, который будет разбивать адрес на сегменты;
  • В-третьих, вся эта красота будет лежать в index.php, внося разнообразие в его скучный и короткий код :-)

Ну, и самое главное, всё это придётся писать самостоятельно, т.е. «изобретать велосипед».

Но создатели Laravel избавили нас от такой необходимости, написав свой роутер (router, маршрутизатор), реализующий механизм роутинга (маршрутизации), который решает все приведённые выше недостатки. Кроме того, Laravel routing предоставляет следующие возможности:

  1. Именованные роуты (маршруты);
  2. Группы роутов;
  3. Маршруты для поддоменов;
  4. Передача данных в виде параметров роута;
  5. Фильтрация параметров с помощью регулярных выражений.

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

Итак, как же пользоваться Laravel routing (кстати, как и множество англоязычных терминов его можно адаптировать к русскому языку в виде слова «роутинг»)?

Создаём Laravel routes

Для того, чтобы создать Laravel routes (правила маршрутизации) нам нужно будет работать с каталогом Laravel приложения под названием «routes» и, в частности, с файлом web.php, находящемся внутри.

Ещё до версии Laravel 5.3 файл с правилами роутинга был всего один и располагался в корне каталога «app». Но после создатели Laravel решили разделить роуты по назначению, создав для правил сайта, API и команд консоли отдельные файлы web, api и console соответственно.

Также для правил в файлах web и api в движок были добавлены базовые группы middleware, описанные в файле App/Http/Kernel.php, которые там можно и править при необходимости.

Многие фанаты Laravel, кстати, восприняли такие меры в штыки, посчитав их усложняющими жизнь.

Помню, когда я только осваивал Laravel и искал в сети подобные мануалы по созданию Laravel сайтов, натолкнулся на одного автора, который сознательно вёл разработку на Laravel 4, хотя текущая версия на тот момент была 5.3, вроде как. Свой выбор он аргументировал как раз-таки раздуванием фреймворка за счёт во многом лишних фич.

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

Кстати, с этой целью я решил обновить движок нашего будущего сайта, т.к., несмотря на то, что статьи по Laravel я начал публиковать сравнительно недавно на сайте, материал был написал ещё в октябре 2016 года, когда версия Laravel была 5.3. Теперь же она 5.4.23.

Если хотите обновить версию Laravel или какого-либо другого установленного через Composer пакета, прописанного в composer.json, просто зайдите в данный файл, лежащий в корне сайта, и пропишите интересующую вас версию или ветку в формате 5.4.*, например. После запустите в консоли команду composer update. Использовать системную консоль или консоль сервера — зависит от того, как вы устанавливали Composer.

Итак, приступаем к написанию наших роутов.

Забегая наперёд, скажу, что я не буду демонстрировать вам использование всех возможностей Laravel routes. Будем решать проблемы по мере их поступления 😉

Заходим в файл routes/web.php и смотрим, что у нас там есть:

Route::get('/', function () {
    $data = array('description' => 'Moderna - Главная страница', 
                  'title' => 'Moderna - Главная страница');
    return view('index', $data);
});

Route::get('/{page}', function ($page) {
    $data = array('description' => 'Moderna - ' . $page, 
                  'title' => 'Moderna - ' . $page);
    $data['breadcrumbs'] = Request::Get('breadcrumbs');
    
    return view($page, $data);
})->middleware('breadcrumbs');

У нас уже прописаны два правила роутинга: отдельно для главной страницы и для всех остальных, попутно применяя к ним middleware breadcrumbs, которые мы создали ранее. Я люблю универсальные решения, но в данном примере лучше будет создать отдельные правила роутинга для каждой страницы, чтобы назначить каждому url отдельное действие.

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

Итак, добавляем в файл routes/web.php Laravel routes для всех наших существующих страниц:

Route::get('/', 'MainController@index');
Route::get('/pricingbox', 'PriceController@index');
Route::get('/portfolio', 'PortfolioController@index');
Route::get('/blog', 'BlogController@index');
Route::get('/contact', 'ContactController@index');

Вот и всё. Получилось даже меньше строк кода, чем было раньше :-)

Давайте теперь разберёмся, что же я тут такое написал.

Route — это фасад Laravel, который нужен для работы с url. В данном случае, для его обработки.

get — это метод фасада, соответствующий методу, которым отправляется HTTP-запрос на данный url. Из доступных в Laravel имеются:

  • get;
  • post;
  • put;
  • patch;
  • delete;
  • options;

Также есть два метода фасада Route, позвляющие задавать одно действие для запросов, отправленных разными методами. Это match() и any(). Первый позволяет перечислять необходимые методы, а второй будет выполнять действие по url, не зависимо от того, каким методом был отправлен запрос.

Применяются они следующим образом:

Route::match(['get', 'post'], '/', function () {
    //действие
});

Route::any('/page', function () {
    //действие
});

Если вы, к примеру, отправляете HTTP-запрос на сервер методом POST, а правило обработки запроса на данный url будет описано для GET, то запрос не обработается.

Функция get() принимает два параметра:

  1. непосредственно url (лучше указывать со слэшом в начале, сообщая, что путь относительно корня сайта, иначе при создании админки придётся все url переписывать);
  2. действие, которое должно происходить после получения соответствующего запроса.

Действие может быть описано в разных форматах. Самый простой предполагает просто безымянную функцию, в теле которой будет прописано какое-либо действие. Пример данного подхода — наши старые Laravel маршруты, которые ещё находятся в файле web.php.

Также действие может быть прописано в таком формате, в каком я указал:

AboutController@index

Эта запись означает, что для обработки Laravel route будет вызываться определённый метод контроллера. Наименование контроллера — слева от символа «@», а метод — справа. В данном случае будет вызываться метод index() контроллера AboutController — всё просто :-)

Доведём файл routes/web до ума. Для этого нам нужно применить к нашим новым Laravel routes, отвечающим за страницы сайта (кроме главной) middleware для вывода хлебных крошек. Напомню, что можно сделать это двумя способами: применением его к каждому url в отдельности и к групповым применением ко всем роутам.

Первый способ мы использовали ранее с помощью конструкции:

Route::get('/{page}', function ($page) { ... })->middleware('breadcrumbs');

Можно было бы его снова применить к каждому роуту отдельно, но я предпочту массовое применение Laravel middleware:

Route::group(['middleware' => 'breadcrumbs'], function(){
    Route::get('/pricingbox', 'PriceController@index');
    Route::get('/portfolio', 'PortfolioController@index');
    Route::get('/blog', 'BlogController@index');
    Route::get('/contact', 'ContactController@index');
});

Предыдущие Laravel routes, которые у нас были в файле до этого, предлагаю пока что просто закомментировать, потому что в будущем, когда мы будем создавать контроллеры, данный код нам ещё пригодится.

Итак, файл с правилами Laravel маршрутизации у нас готов. Но, если мы сейчас попробуем перейти по url сайта в браузере, то увидим следующее:

laravel-routes-oshibka-vyzova-controllera

Эта ошибка вполне логична, т.к. ни контроллера, ни вызываемого метода у нас ещё нет.

Настало время исправить это:-)

Создаём Laravel controllers

Контроллер — это компонент паттерна программирования MVC, согласно которому код приложения разделяется на модели, контроллеры и представления.

Назначение контроллера — это реализация логики приложения и вывод обработанных данных, полученных с помощью моделей, в представления, которые представляют собой HTML-код, т.е. то, что мы видим в браузере.

Следовательно, в соответствующих контроллерах мы будем прописывать логику и выводить её в представления (Laravel views).

Файлы контроллеров Laravel хранятся в каталоге app/Http/Controllers. По умолчанию там расположен один-единственный базовый контроллер Controller.php, от которого будут наследоваться все остальные.

Для создания нового Laravel controller, как и в случае создания Laravel middleware, воспользуемся Laravel artisan. Для начала создадим контроллер, ответственный за вывод на экран кода главной страницы.

Запускаем консоль, переходим в папку проекта с помощью команды cd путь_к_проекту и запускаем следующую команду:

php artisan make:controller MainController

После успешного выполнения у нас в папке app/Http/Controllers появится новый файл MainController.php со следующим кодом:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MainController extends Controller
{
    //
}

Всё просто и без излишеств — так и должен выглядеть пустой контроллер, внутри которого можно создавать всё, что угодно. Если посмотреть на файл Laravel роутов, то увидите, что я решил сделать однородную структуру контроллеров, т.к. в каждом из них для вывода HTML-кода в браузер будет вызываться метод index(), к созданию которого мы и приступаем.

Для этого создаём функцию index и переносим в её тело закомментированный код из app/routes/web:

public function index()
{
    $data = [
        'title' => 'Наша компания',
        'description' => 'Наша компания - самая лучшая в своём роде'
    ];
        
    return view('index', $data);
}

После этого, при обращении к url сайта в браузере, мы увидим рабочую главную страницу. На остальных же страницах пока же будет та же ошибка, что и прежде.

Создаём остальные контроллеры страниц приведённым выше способом. Единственное, чем они будут отличаться от MainController.php — это содержимое метода index(), которое будет взято из другого закомментированного универсального правила Laravel маршрутизации. К примеру, для страницы с url «portfolio» он будет выглядеть так:

public function index()
{
    $data = [
        'title' => 'Портфолио',
        'description' => 'Наши лучшие работы'
    ];
        
    $data['breadcrumbs'] = \Request::get('breadcrumbs');
        
    return view('portfolio', $data);
}

Тут, кстати, тоже нужно сделать небольшое уточнение по поводу слэша перед Request. Он необходим, когда вам нужно воспользоваться глобальным фасадом (классом) Laravel из числа описанных в файле config/app.php в массиве aliases, если использование фасада не описано прямо путём следующей директивы в начале файла php:

use Request;

Мораль сей басни такова: если код составлен верно, но Laravel выдаёт ошибку, что какой-то класс не найден, то проверьте, подключен ли он в файле или попробуйте перед его именем поставить слэш. Но этот способ работает не всегда, так что сильно на него на надейтесь и пропишите прямо.

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

В итоге, у нас должно появиться на одну рабочую страницу больше :-)

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

В завершение, удалите закомментированный код из app/routes.web.php.

Напоминаю, что все сегодняшние изменения вы сможете посмотреть в репозитории на Github в виде четвёртого коммита. Ну, и, ествественно, если у вас что-то не получилось и возникли какие-то трудности — пишите о них в комментариях, постараюсь всем помочь :-)

На этом у меня сегодня всё.

Laravel routes мы создали и перенесли код из файла роутинга в Laravel controllers. В следующей статье мы с вами будем создавать контактную форму и реализовывать отправку email на Laravel различными способами.

Поэтому не забывайте подписываться на обновления проекта и вступать в сообщества в социальных сетях, чтобы быть в курсе.

До новых встреч.

  1. 5
  2. 4
  3. 3
  4. 2
  5. 1
5 голосов, в среднем: 5 из 5

6 комментариев к статье "Знакомимся с Laravel routing и controllers"

  1. Edred

    В этом уроке все ясно и понятно, получилось с первого раза.

    Только один вопрос по поводу создания контролеров. Мне, чтобы запустить команду
    php artisan make:controller MainController
    надо зайти в WinSCP, ввести дополнительный пароль (который не запоминается), вызвать командную строку, и только тогда могу через SSH задавать команды. В общем, куча лишних телодвижений. Можно ли, создав один контролер MainController, просто размножить его копированием на все нужное количество, изменяя имя и тэги title и description, или при создании контролеров через artisan они где-то дополнительно фиксируются?

    1. Pashaster Автор

      По поводу WinSCP — не замечал, что при его использовании столько сложностей. Сам им пользуюсь и пароли у меня все сохраняются. Возможно, Вам версию программы обновить нужно? А вообще я Putty предпочитаю. Да, там пароли точно не сохраняются, но работать удобнее и приятнее (лично мне).

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

      1. Edred

        При использовании WinSCP сложностей никаких, да и пароль, конечно, запоминается, это я неточно сказал. Не запоминается openssh-key. Его запрашивает каждый раз при соединении с хостингом. А так как я немного сдвинут на безопасности, то у меня этот key, естественно, 12 символов разных регистров с цифрами и доп.знаками. Ничего, еще раз десять введу — и сменю на «12345» :-)

        На самом деле, вполне вероятно, что где-то в недрах настроек WinSCP этот ключ можно записать, чтобы не спрашивала. Или на Putty перейти. Но лучше я найду время и настрою Netbox в Фаре, потому что по FTP я все равно через него на хостинг захожу (да вообще активно им пользуюсь, даже код по мелочи прямо в нем правлю), осталось только SSH настроить (с первого захода не получилось просто).

        1. Pashaster Автор

          Far для FTP? Filezilla не понравилась или не пробовали? SSH-key там, кстати, подтверждается одним нажатием кнопки «ОК» :-)

          1. Edred

            Я просто Фар использую постоянно, на экране всегда одно-два окна открыто. Привычка. И поэтому по ftp, конечно же, хожу им же — потому что и по сети домашней им же хожу, а в фаре и то, и другое организовано одинаково. И по SSH хочется им пользоваться, и он поддерживает это, просто что-то там с настройками у меня не получилось.

            Но ладно, это явно за пределами темы урока, а вот по теме хочу сказать кое-что еще.

            Во-первых, еще раз спасибо за внятное объяснение что такое роуты и зачем они нужны. Я уже несколько дней как залез в справочник на laravel.ru и изучаю описания роутов там, и экспериментирую на своих сайтах. По идее, разобрался нормально.

            Во-вторых, плохо то, что вы не используете терминологию, которая применяется в справочнике на laravel.ru. Там не пишут «роуты / роутинг» и т. д. — там пишут «маршруты». Если вы не планируете создавать свою собственную документацию по фреймворку, то хорошо бы придерживаться единообразия в терминологии с тем сайтом, где такая документация уже есть.

          2. Pashaster Автор

            Спасибо за ответ, но я лично документацию на laravel.ru эталонной не считаю, поэтому и принимать её за образец терминологии тоже смысла не вижу :-)

            Хотя в качестве синонима, наверное, вплету в текст.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *