Laravel и первый маршрут портала заявок
Оглавление серии «Laravel 13 и PHP: портал «Заявка»»
Портал «Заявка» принимает обращения сотрудников: например, «Нужен доступ к макетам» и «Обновить описание проекта». В шестнадцати уроках построим серверный проект с HTML-страницами, базой, входом, правами и фоновой квитанцией. Первый результат скромнее: запрос браузера получает страницу через маршрут Laravel. Вы должны знать классы PHP, массивы, функции, Composer и различие между URL и файлом на диске.
Редакционный профиль зафиксирован на Laravel Framework 13.35.0 и PHP 8.4.25. Официальный релиз Framework существует, а таблица поддержки Laravel 13 допускает PHP от 8.3. Выбранная версия PHP опубликована в официальном архиве выпусков. Это проверка документации и доступности версий, а не результат установки или запуска.
Путь запроса к ответу
Приложение использует официальный каркас Laravel, описанный в base/README.md архива. В нём public/index.php является входом HTTP, bootstrap/app.php собирает приложение, routes/web.php описывает веб-маршруты. Нельзя назначать корнем сайта папку всего проекта: тогда закрытые настройки и исходники окажутся рядом с публичными ресурсами. Для разработки предусмотрен сервер localhost, а настоящий выпуск потребует отдельной серверной конфигурации.
Laravel связывает метод HTTP и путь с обработчиком. Адрес /tickets не обязан соответствовать файлу tickets.php. GET означает чтение представления, а будущий POST будет означать создание заявки. Один и тот же путь может иметь разные обработчики методов. Такое разделение полезно ещё до базы: браузерная навигация и запись данных получают разные намерения и разные требования к защите.
Полностью заменим routes/web.php. Пока маршрут возвращает простое представление без пользовательских данных и без изменений состояния.
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', fn () => redirect()->route('tickets.index'));
Route::get('/tickets', fn () => view('tickets.start'))->name('tickets.index');
Теперь создадим полный resources/views/tickets/start.blade.php. На этом первом шаге Blade работает как обычный HTML-шаблон: динамический список появится позднее.
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Заявка</title>
</head>
<body>
<main><h1>Портал «Заявка»</h1>
<p>Учебный кабинет обращений сотрудников.</p>
</main>
</body>
</html>
Ожидаемый GET /tickets получает документ с заголовком портала и одной подписью. GET / перенаправляет на именованный маршрут списка. Здесь ещё нет отдельного TicketController: обработчик короткий, а предметная работа отсутствует. Когда появится чтение записей, вынесем его в контроллер. Не создавайте крупный слой абстракций ради возврата двух постоянных строк.
Именованный маршрут
name задаёт устойчивое имя tickets.index, через которое redirect получает адрес. Если путь списка позже станет /requests, можно сохранить имя и изменить одну декларацию. Это не означает, что уже опубликованные внешние адреса автоматически перенаправятся: для них понадобится отдельное правило. Именованный маршрут уменьшает внутреннее дублирование строк, но не заменяет заботу о постоянных URL.
Документация маршрутов Laravel описывает веб-группу middleware и именование. В нашем проекте web.php получает привычные механизмы сессии и защиты форм стандартного каркаса. Не следует переносить будущую форму в маршрут без этой группы, ожидая того же поведения old input и CSRF. Контекст middleware является частью пути запроса, хотя его реализация не помещена в короткий листинг маршрута.
Полезный ошибочный случай — запрос /ticket вместо /tickets. Никакое сходство слов не заставляет Laravel выбрать маршрут, поэтому ожидается отсутствие совпадения. Другой случай — POST /tickets, для которого пока нет обработчика создания. Он не должен случайно использовать GET и сохранять данные. В дальнейшем различение методов позволит не выполнять изменения через обычные ссылки.
Если view не находит tickets.start, проверьте точный путь resources/views/tickets/start.blade.php. Точка в имени представления обозначает переход к вложенной папке, расширение blade.php в вызове не пишется. Перемещать файл в public ради исправления такого отказа неправильно: шаблон принадлежит серверному приложению и должен обрабатываться через выбранный маршрут. Его исходный текст не является самостоятельным публичным ресурсом.
Окружение отдельно от кода
Базовый .env.example выбирает SQLite, file-сессии, database-очередь и log-почту. Эти настройки не означают, что база уже создана или очередь работает. Перед собственным использованием потребуется файл учебной базы, ключ приложения и разрешённые зависимости. Команды подготовки описаны в архиве и не выполнялись в этой работе. Такая точность позволит дальше назвать SQL и HTTP-результаты ожидаемыми, не выдавая их за наблюдавшиеся.
APP_KEY не является паролем пользователя. Он участвует в механизмах приложения и должен создаваться для конкретного окружения. Нельзя вставлять один опубликованный ключ из статьи в несколько рабочих установок. Значение APP_DEBUG в локальном профиле помогает разработке, но будущая передача изменит его для внешней среды. Сейчас портал должен слушать localhost и использовать только вымышленные обращения.
У PHP-проекта есть две зависимости от версии. Синтаксис приложения должен поддерживаться интерпретатором, а установленные библиотеки должны допускать его по Composer. Точная верхнеуровневая версия Framework не фиксирует все транзитивные пакеты без composer.lock. Архив не содержит фиктивного lockfile, поскольку разрешение не выполнялось. После собственной установки его нужно сохранить и использовать при воспроизведении окружения.
Мы также не используем starter kit с автоматически сгенерированным фронтендом. Портал будет показывать HTML через Blade и построит ограниченный сессионный вход в соответствующей главе. Это не полноценная система регистрации сотрудников. Для реального SaaS понадобятся проверка адресов, восстановление паролей и управление организацией. Вводить эти обещания в первый маршрут было бы неверно, даже если будущая форма выглядит похожей на рабочий кабинет.
Основа следующего изменения
Перед продолжением найдите три отдельные сущности: URL /tickets, имя tickets.index и имя шаблона tickets.start. Они связаны декларацией маршрута, но не совпадают по назначению. Если изменить только одно, последствия будут разными: внешний путь, внутренние ссылки либо поиск файла. Такой разбор предотвращает привычку искать любую ошибку в одном «адресе страницы».
Для самостоятельного изменения добавьте в шаблон описание первого обращения постоянным текстом и заранее определите, какие PHP-файлы должны измениться. Маршрут останется прежним, потому что задача касается представления. Следующий урок передаст в Blade массив заявок и выделит общий HTML-каркас, после чего данные и оформление смогут развиваться независимо.
Для самостоятельного воспроизведения результата «Разделить фронт-контроллер, маршрут и ответ» выберите lesson-01 в архиве исходников. Статус выполнения этого состояния: not_run.