КулЛиб - Классная библиотека! Скачать книги бесплатно 

Laravel 9. Быстрая разработка веб-сайтов на PHP [Владимир Александрович Дронов] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]
Владимир Дронов

Санкт-Петербург
«БХВ-Петербург»
2023

УДК 004.738.5+004.43
ББК 32.973.26-018.2
Д75

Дронов В. А.

Д75

Laravel 9. Быстрая разработка веб-сайтов на PHP. — СПб.: БХВ-Петербург,
2023. — 768 с.: ил. — (Профессиональное программирование)
ISBN 978-5-9775-1725-6
Книга представляет собой полное описание фреймворка Laravel 9 для быстрой
разработки сайтов на языке PHP. Дан краткий вводный курс для начинающих,
в котором описывается разработка простого учебного сайта — электронной доски
объявлений. Описаны базовые инструменты Laravel: миграции, модели, маршруты,
контроллеры, шаблоны, средства обработки пользовательского ввода и сохранения
выгруженных файлов, валидаторы, шаблоны, пагинаторы и инструменты разграничения доступа. Рассказано о более развитых средствах: внедрении зависимостей,
провайдерах, посредниках, событиях и их обработке, отправке электронной почты,
оповещениях, очередях и отложенных заданиях, встроенном планировщике, инструментах кеширования, локализации сайтов и расширении возможностей встроенной утилиты artisan. Описаны дополнительные библиотеки для обработки BBCodeтегов и CAPTCHA, вывода графических миниатюр, аутентификации через социальные сети. Рассмотрено программирование веб-служб REST, вещание по протоколу WebSocket и публикация сайта.
Электронный архив на сайте издательства содержит исходный код описанного
в книге сайта.
Для веб-программистов
УДК 004.738.5+004.43
ББК 32.973.26-018.2

Группа подготовки издания:
Руководитель проекта
Зав. редакцией
Редактор
Компьютерная верстка
Дизайн серии
Оформление обложки

Евгений Рыбаков
Людмила Гауль
Григорий Добин
Ольги Сергиенко
Инны Тачиной
Зои Канторович

"БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20

ISBN 978-5-9775-1725-6

© ООО "БХВ", 2023
© Оформление. ООО "БХВ-Петербург", 2023

Оглавление

Предисловие ................................................................................................................... 19
Почему именно Laravel? ............................................................................................................... 19
О чем эта книга? ............................................................................................................................ 20
Используемое ПО .......................................................................................................................... 21
Типографские соглашения ............................................................................................................ 22
ЧАСТЬ I. ОСНОВЫ LARAVEL НА ПРАКТИЧЕСКОМ ПРИМЕРЕ ................ 25
Глава 1. Простейший веб-сайт — доска объявлений ............................................. 27
1.1. Подготовительные действия .................................................................................................. 27
1.2. Проект и его создание. Папка проекта.................................................................................. 27
Теория .......................................................................................................................................... 27
Практика ...................................................................................................................................... 28
1.3. Запуск проекта. Отладочный веб-сервер PHP ...................................................................... 29
1.4. Контроллеры и действия ........................................................................................................ 30
Теория .......................................................................................................................................... 30
Практика ...................................................................................................................................... 31
1.5. Маршруты и списки маршрутов. Фасады............................................................................. 32
Теория .......................................................................................................................................... 32
Практика ...................................................................................................................................... 33
1.6. Настройки проекта. Подготовка проекта к работе с базой данных SQLite ....................... 34
Теория .......................................................................................................................................... 34
Практика ...................................................................................................................................... 34
1.7. Миграции................................................................................................................................. 36
Теория .......................................................................................................................................... 36
Практика ...................................................................................................................................... 36
1.8. Модели..................................................................................................................................... 38
1.9. Консоль Laravel....................................................................................................................... 39
1.10. Работа с базой данных .......................................................................................................... 40
1.11. URL-параметры. Внедрение зависимостей ........................................................................ 43
Теория .......................................................................................................................................... 43
Практика ...................................................................................................................................... 44

4

Оглавление

1.12. Шаблоны ............................................................................................................................... 46
Теория .......................................................................................................................................... 46
Практика ...................................................................................................................................... 46
1.13. Наследование шаблонов....................................................................................................... 51
Теория .......................................................................................................................................... 51
Практика ...................................................................................................................................... 51
1.14. Именованные маршруты ...................................................................................................... 53
1.15. Статические файлы ............................................................................................................... 54

Глава 2. Доска объявлений 2.0: разграничение доступа,
работа с объявлениями и локализация..................................................................... 55
2.1. Межтабличные связи. Работа со связанными записями...................................................... 55
2.2. Вход и выход. Раздел пользователя ...................................................................................... 58
Теория .......................................................................................................................................... 58
Практика ...................................................................................................................................... 59
2.3. Добавление, правка и удаление записей ............................................................................... 64
2.4. Валидация данных .................................................................................................................. 70
2.5. Разграничение доступа. Посредники, политики и провайдеры .......................................... 72
Теория .......................................................................................................................................... 72
Практика ...................................................................................................................................... 73
2.6. Получение сведений о текущем пользователе ..................................................................... 76
2.7. Локализация веб-сайта ........................................................................................................... 76
ЧАСТЬ II. БАЗОВЫЕ ИНСТРУМЕНТЫ ................................................................ 81
Глава 3. Создание, настройка и отладка проекта ................................................... 83
3.1. Подготовка к установке.......................................................................................................... 83
3.2. Создание проекта .................................................................................................................... 83
3.2.1. Создание проекта с помощью Composer ........................................................................ 83
3.2.2. Создание проекта с помощью Laravel Installer............................................................... 84
3.3. Папки и файлы проекта .......................................................................................................... 85
3.4. Настройки проекта ................................................................................................................. 87
3.4.1. Две разновидности настроек проекта ............................................................................. 87
3.4.1.1. Локальные настройки ............................................................................................. 87
3.4.1.2. Рабочие настройки .................................................................................................. 88
3.4.2. Настройки проекта по категориям .................................................................................. 89
3.4.2.1. Базовые настройки проекта .................................................................................... 89
3.4.2.2. Настройки режима работы веб-сайта .................................................................... 90
3.4.2.3. Настройки шифрования .......................................................................................... 90
3.4.2.4. Настройки баз данных ............................................................................................ 91
3.4.3. Доступ к настройкам из программного кода.................................................................. 94
3.4.4. Создание своих настроек ................................................................................................. 95
3.5. Базовые инструменты отладки ..............................................................................................96
3.5.1. Отладочный веб-сервер .................................................................................................... 96
3.5.2. Вывод сообщений об ошибках ........................................................................................ 97
Глава 4. Миграции и сидеры ...................................................................................... 99
4.1. Миграции................................................................................................................................. 99
4.1.1. Создание миграций ......................................................................................................... 100
4.1.2. Класс миграции ............................................................................................................... 100

Оглавление

5

4.1.3. Создание таблиц ............................................................................................................. 101
4.1.3.1. Создание полей ......................................................................................................101
4.1.3.2. Реализация «мягкого» удаления записей в таблицах ......................................... 105
4.1.3.3. Указание дополнительных параметров полей .................................................... 105
4.1.3.4. Создание индексов ................................................................................................ 107
4.1.3.5. Создание полей внешнего ключа ......................................................................... 108
4.1.3.6. Задание дополнительных параметров таблиц ..................................................... 111
4.1.4. Правка и удаление таблиц ..............................................................................................111
4.1.4.1. Правка и удаление полей ...................................................................................... 111
4.1.4.2. Переименование и удаление индексов ................................................................ 113
4.1.4.3. Удаление полей внешнего ключа и управление соблюдением
ссылочной целостности ..................................................................................................... 113
4.1.4.4. Переименование и удаление таблиц .................................................................... 114
4.1.5. Проверка существования таблиц и полей ..................................................................... 114
4.1.6. Указание базы данных, с которой будут работать миграции ..................................... 115
4.1.7. Обработка миграций....................................................................................................... 115
4.1.7.1. Применение миграций .......................................................................................... 115
4.1.7.2. Откат миграций, обновление, сброс и очистка базы данных ............................ 116
4.1.7.3. Создание журнала миграций и просмотр их состояния ..................................... 117
4.1.8. Дамп базы данных как альтернатива миграциям ......................................................... 118
4.2. Сидеры ................................................................................................................................... 118
4.2.1. Использование корневого сидера.................................................................................. 119
4.2.2. Использование подчиненных сидеров .......................................................................... 119
4.2.3. Выполнение сидеров ...................................................................................................... 120

Глава 5. Модели: базовые инструменты ................................................................ 121
5.1. Создание моделей ................................................................................................................. 121
5.2. Класс модели и соглашения по умолчанию ....................................................................... 122
5.3. Параметры модели................................................................................................................ 123
5.3.1. Параметры полей модели............................................................................................... 123
5.3.2. Параметры обслуживаемой таблицы ............................................................................ 123
5.3.3. Параметры преобразования типов ................................................................................ 124
5.3.4. Реализация «мягкого» удаления записей в моделях .................................................... 127
5.4. Создание связей между моделями....................................................................................... 127
5.4.1. Связь «один-со-многими» .............................................................................................. 127
5.4.2. Связь «один-с-одним из многих» .................................................................................. 129
5.4.3. Связь «один-с-одним» .................................................................................................... 131
5.4.4. Связь «многие-со-многими» .......................................................................................... 131
5.4.4.1. Использование связующих моделей .................................................................... 135
5.4.5. Пометка записи первичной модели как исправленной при правке или удалении
связанных записей вторичной модели .................................................................................... 136
5.4.6. Сквозная связь «один-со-многими» .............................................................................. 136
5.4.7. Сквозная связь «один-с-одним» .................................................................................... 137
5.4.8. Записи-заглушки ............................................................................................................. 137
5.4.9. Замкнутая связь............................................................................................................... 138
5.5. Методы моделей ................................................................................................................... 139
5.6. Преобразователи. Акцессоры и мутаторы .......................................................................... 139
5.6.1. Виртуальные поля........................................................................................................... 141
5.6.2. Акцессоры и мутаторы в предыдущих версиях Laravel .............................................. 141

6

Оглавление

Глава 6. Запись данных.............................................................................................. 143
6.1. Добавление, правка и удаление записей с помощью моделей .......................................... 143
6.1.1. Добавление записей. Построитель запросов ................................................................ 143
6.1.2. Правка записей................................................................................................................ 145
6.1.2.1. Правка значений отдельных полей ...................................................................... 146
6.1.2.2. Проверка, значения каких полей изменились ..................................................... 147
6.1.3. Удаление записей ........................................................................................................... 149
6.1.3.1. «Мягкое» удаление записей .................................................................................. 149
6.1.4. Работа со связанными записями .................................................................................... 150
6.1.4.1. Связи «один-со-многими» и «один-с-одним»: связывание
существующих записей...................................................................................................... 150
6.1.4.2. Связи «один-со-многими» и «один-с-одним»: добавление и правка
связанных записей .............................................................................................................. 151
6.1.4.3. Связь «один-с-одним из многих» ......................................................................... 152
6.1.4.4. Связь «многие-со-многими»: связывание записей ............................................. 153
6.1.4.5. Связь «многие-со-многими»: добавление и правка связанных записей ........... 155
6.1.5. Копирование записей ..................................................................................................... 156
6.2. Массовые добавление, правка и удаление записей............................................................ 156
6.2.1. Массовое добавление записей ....................................................................................... 156
6.2.2. Массовая правка записей ...............................................................................................158
6.2.3. Массовое удаление записей ........................................................................................... 159
6.2.4. Использование фасада DB для записи данных............................................................. 159

Глава 7. Выборка данных .......................................................................................... 161
7.1. Извлечение значений из полей записи ................................................................................ 161
7.2. Доступ к связанным записям ...............................................................................................161
7.2.1. Связь «один-со-многими»: доступ к связанным записям ............................................ 161
7.2.2. Связь «один-с-одним из многих»: доступ к связанным записям ................................ 162
7.2.3. Связь «один-с-одним»: доступ к связанным записям .................................................. 163
7.2.4. Связь «многие-со-многими»: доступ к связанным записям ........................................ 163
7.3. Выборка записей: базовые средства ................................................................................... 164
7.3.1. Выборка всех записей .................................................................................................... 164
7.3.2. Извлечение первой записи ............................................................................................. 164
7.3.3. Поиск записей ................................................................................................................. 165
7.3.4. Фильтрация записей ....................................................................................................... 167
7.3.4.1. Фильтрация записей по значениям полей типа JSON ........................................ 172
7.3.4.2. Фильтрация по полнотекстовому индексу .......................................................... 173
7.3.5. Сортировка записей ........................................................................................................ 174
7.3.6. Выборка указанного количества записей ..................................................................... 175
7.3.7. Выборка уникальных записей ....................................................................................... 175
7.3.8. Задание параметров запросов на основании выполнения указанного условия ......... 176
7.3.9. Смена типа выдаваемых значений ................................................................................ 176
7.3.10. Выполнение запроса и получение результата ............................................................ 176
7.3.11. Проверка наличия записей в полученном результате................................................ 177
7.3.12. Объединение результатов от разных запросов .......................................................... 177
7.4. Выборка связанных записей ................................................................................................178
7.5. Выборка записей: расширенные средства .......................................................................... 182
7.5.1. Указание выбираемых полей ......................................................................................... 182
7.5.2. Вставка фрагментов SQL-кода в запрос ....................................................................... 183
7.5.3. Связывание таблиц ......................................................................................................... 183

Оглавление

7

7.5.4. Использование вложенных запросов ............................................................................ 186
7.5.5. Использование фасада DB для выборки данных ......................................................... 189
7.6. Агрегатные вычисления ....................................................................................................... 189
7.6.1. Агрегатные вычисления по всем записям .................................................................... 189
7.6.2. Агрегатные вычисления по группам записей ............................................................... 190
7.6.3. Агрегатные вычисления по связанным записям .......................................................... 192
7.7. Извлечение «мягко» удаленных записей ............................................................................ 194
7.8. Сравнение записей ................................................................................................................ 195
7.9. Получение значения заданного поля................................................................................... 195
7.10. Повторное считывание записей ......................................................................................... 196

Глава 8. Маршрутизация ........................................................................................... 197
8.1. Настройки маршрутизатора .................................................................................................197
8.2. Списки маршрутов................................................................................................................ 198
8.3. Создание простых маршрутов ............................................................................................. 198
8.3.1. Специализированные маршруты ................................................................................... 199
8.3.2. Резервный маршрут ........................................................................................................ 200
8.4. Именованные маршруты ...................................................................................................... 200
8.5. URL-параметры и параметризованные маршруты ............................................................ 201
8.5.1. Указание правил для значений URL-параметров ........................................................ 202
8.5.2. Внедрение моделей......................................................................................................... 203
8.5.2.1. Неявное внедрение моделей ................................................................................. 203
8.5.2.2. Явное внедрение моделей..................................................................................... 205
8.5.3. Внедрение перечислений ............................................................................................... 207
8.5.4. Значения по умолчанию для URL-параметров ............................................................ 207
8.6. Дополнительные параметры маршрутов ............................................................................ 209
8.7. Группы маршрутов ............................................................................................................... 210
8.8. Маршруты на ресурсные контроллеры ............................................................................... 211
8.8.1. Маршруты на подчиненные ресурсные контроллеры ................................................. 213
8.8.2. Дополнительные параметры маршрутов на ресурсные контроллеры ....................... 213
8.9. Как Laravel обрабатывает списки маршрутов? .................................................................. 215
8.10. Вывод списка созданных маршрутов................................................................................ 215
Глава 9. Контроллеры и действия. Обработка запросов и генерирование
ответов ........................................................................................................................... 217
9.1. Разновидности контроллеров и особенности работы с ними ........................................... 217
9.1.1. Контроллеры-функции ...................................................................................................217
9.1.2. Контроллеры-классы ...................................................................................................... 218
9.1.2.1. Ресурсные контроллеры ....................................................................................... 218
9.1.2.2. Контроллеры одного действия ............................................................................. 220
9.1.2.3. Создание контроллеров-классов .......................................................................... 220
9.1.2.4. Связывание посредников с контроллерами ........................................................ 221
9.2. Внедрение зависимостей в контроллерах ........................................................................... 221
9.3. Обработка клиентских запросов.......................................................................................... 222
9.3.1. Извлечение данных, отправленных посетителем ........................................................ 223
9.3.2. Как узнать, присутствует ли в запросе нужное значение? .......................................... 225
9.3.3. Добавление в запрос произвольных значений ............................................................. 226
9.3.4. Получение сведений о запросе ...................................................................................... 227
9.4. Генерирование интернет-адресов ........................................................................................ 231

8

Оглавление

9.5. Генерирование серверных ответов...................................................................................... 233
9.5.1. Ответы на основе шаблонов .......................................................................................... 233
9.5.1.1. Ответы в виде объектов класса View ................................................................... 233
9.5.1.2. Ответы в виде объектов класса Response ............................................................ 234
9.5.2. Специальные ответы ...................................................................................................... 235
9.5.2.1. Отправка файла для отображения в веб-обозревателе ....................................... 235
9.5.2.2. Отправка файла для сохранения на локальном диске ........................................ 235
9.5.2.3. Отправка данных в форматах JSON и JSONP..................................................... 236
9.5.2.4. Текстовый ответ .................................................................................................... 237
9.5.2.5. «Пустой» ответ ......................................................................................................237
9.5.3. Дополнительные параметры ответов ............................................................................ 237
9.5.4. Перенаправления ............................................................................................................ 238
9.6. Обработка ошибок ................................................................................................................ 240

Глава 10. Обработка введенных данных. Валидация .......................................... 242
10.1. Извлечение введенных данных.......................................................................................... 242
10.2. Валидация данных .............................................................................................................. 244
10.2.1. Валидаторы ................................................................................................................... 244
10.2.1.1. Быстрая валидация с неявным созданием валидатора ..................................... 244
10.2.1.2. Валидация с явным созданием валидатора ....................................................... 246
10.2.2. Формальные запросы ...................................................................................................249
10.2.3. Правила валидации и написание их наборов ............................................................. 252
10.2.3.1. Валидация паролей.............................................................................................. 261
10.2.3.2. Валидация массивов элементов управления ..................................................... 262
10.2.4. Написание сообщений об ошибках ввода .................................................................. 264
10.2.4.1. Подстановки наименований ............................................................................... 265
10.2.5. Извлечение ранее введенных данных ......................................................................... 265
10.2.6. Извлечение сообщений об ошибках ввода ................................................................. 266
10.2.7. Создание своих правил валидации .............................................................................. 267
10.2.7.1. Правила-функции ................................................................................................ 267
10.2.7.2. Правила-расширения .......................................................................................... 267
10.2.7.3. Правила-объекты ................................................................................................. 268
10.3. Предварительная обработка введенных данных .............................................................. 270
10.4. Вывод веб-страниц добавления, правки и удаления записей.......................................... 272
Глава 11. Шаблоны: базовые инструменты .......................................................... 274
11.1. Настройки шаблонизатора .................................................................................................274
11.2. Директивы шаблонизатора ................................................................................................275
11.2.1. Директивы вывода данных .......................................................................................... 275
11.2.1.1. Вывод данных в формате JSON ......................................................................... 276
11.2.2. Управляющие директивы............................................................................................. 276
11.2.2.1. Условные директивы и директивы выбора ....................................................... 276
11.2.2.2. Директивы циклов ............................................................................................... 278
11.2.3. Прочие директивы ........................................................................................................ 280
11.2.4. Запрет на обработку директив ..................................................................................... 281
11.3. Вывод веб-форм и элементов управления ........................................................................ 282
11.3.1. Вывод веб-форм ............................................................................................................ 282
11.3.2. Вывод элементов управления ...................................................................................... 283
11.3.3. Вывод сообщений об ошибках ввода.......................................................................... 284
11.4. Наследование шаблонов..................................................................................................... 285
11.5. Стеки .................................................................................................................................... 288

Оглавление

9

11.6. Включаемые шаблоны ....................................................................................................... 290
11.6.1. Псевдонимы включаемых шаблонов .......................................................................... 291
11.7. Компоненты ........................................................................................................................ 291
11.7.1. Полнофункциональные компоненты .......................................................................... 292
11.7.1.1. Создание полнофункциональных компонентов ............................................... 292
11.7.1.2. Передача данных в компоненты. Атрибуты компонентов .............................. 295
11.7.1.3. Передача HTML-содержимого в компоненты. Слоты ..................................... 298
11.7.2. Упрощенные компоненты ............................................................................................ 299
11.7.2.1. Бесшаблонные компоненты ............................................................................... 299
11.7.2.2. Бесклассовые компоненты ................................................................................. 300
11.7.3. Динамический компонент ............................................................................................ 301
11.8. Передача данных в шаблоны: другие способы ................................................................ 302
11.8.1. Разделяемые значения ..................................................................................................302
11.8.2. Составители значений ..................................................................................................303
11.8.3. Создатели значений ...................................................................................................... 304
11.9. Обработка статических файлов ......................................................................................... 305

Глава 12. Пагинация................................................................................................... 307
12.1. Автоматическое создание пагинатора .............................................................................. 307
12.2. Дополнительные параметры пагинатора .......................................................................... 310
12.3. Настройка отображения пагинатора ................................................................................. 311
12.4. Создание пагинатора вручную .......................................................................................... 314
Глава 13. Разграничение доступа: базовые инструменты .................................. 316
13.1. Настройки подсистемы разграничения доступа .............................................................. 316
13.2. Создание недостающих модулей, реализующих разграничение доступа ...................... 318
13.3. Маршруты, ведущие на контроллеры разграничения доступа ....................................... 319
13.4. Служебные таблицы и модель ........................................................................................... 321
13.5. Регистрация новых пользователей .................................................................................... 322
13.6. Вход на веб-сайт ................................................................................................................. 325
13.7. Раздел пользователя ........................................................................................................... 327
13.8. Собственно разграничение доступа .................................................................................. 327
13.8.1. Разграничение доступа: простейшие инструменты ................................................... 327
13.8.1.1. Разграничение доступа с помощью посредников............................................. 327
13.8.1.2. Разграничение доступа в шаблонах ................................................................... 328
13.8.2. Гейты ............................................................................................................................. 329
13.8.2.1. Написание гейтов ................................................................................................ 329
13.8.2.2. Разграничение доступа посредством гейтов ..................................................... 330
13.8.2.3. Перехватчики .......................................................................................................332
13.8.2.4. Гейты с развернутыми ответами ........................................................................ 333
13.8.2.5. Простые гейты ..................................................................................................... 334
13.8.3. Политики ....................................................................................................................... 335
13.8.3.1. Создание и регистрация политик ....................................................................... 335
13.8.3.2. Разграничение доступа посредством политик .................................................. 338
13.8.3.3. Разграничение доступа в ресурсных контроллерах.......................................... 341
13.8.4. Разграничение доступа с помощью формальных запросов ...................................... 341
13.9. Получение сведений о текущем пользователе ................................................................. 342
13.10. Подтверждение пароля ..................................................................................................... 343

10

Оглавление

13.11. Выход с веб-сайта ............................................................................................................. 344
13.12. Проверка существования адреса электронной почты ................................................... 344
13.13. Сброс пароля ..................................................................................................................... 347
13.13.1. Отправка электронного письма с гиперссылкой сброса пароля............................. 347
13.13.2. Собственно сброс пароля ........................................................................................... 348
13.13.3. Удаление устаревших жетонов сброса пароля ......................................................... 349

Глава 14. Обработка строк, массивов и функции-хелперы ................................ 350
14.1. Обработка строк.................................................................................................................. 350
14.1.1. Составление строк ........................................................................................................ 351
14.1.2. Сравнение строк и получение сведений о строках .................................................... 352
14.1.3. Преобразование строк ..................................................................................................353
14.1.4. Извлечение фрагментов строк ..................................................................................... 358
14.1.5. Поиск и замена в строках .............................................................................................360
14.1.6. Обработка путей к файлам ........................................................................................... 364
14.1.7. Прочие инструменты для обработки строк ................................................................ 365
14.2. Обработка массивов ........................................................................................................... 367
14.2.1. Добавление, правка и удаление элементов массивов ................................................ 367
14.2.2. Извлечение элементов массива ................................................................................... 369
14.2.3. Проверка существования элементов массивов .......................................................... 371
14.2.4. Получение сведений о массиве ................................................................................... 372
14.2.5. Упорядочивание элементов массивов ........................................................................ 373
14.2.6. Прочие инструменты для обработки массивов .......................................................... 373
14.3. Функции-хелперы ............................................................................................................... 375
14.3.1. Функции, выдающие пути к ключевым папкам ......................................................... 376
14.3.2. Служебные функции.....................................................................................................376
Глава 15. Коллекции Laravel .................................................................................... 380
15.1. Обычные коллекции ........................................................................................................... 380
15.1.1. Создание обычных коллекций ..................................................................................... 380
15.1.2. Добавление, правка и удаление элементов коллекции .............................................. 381
15.1.3. Извлечение отдельных элементов и частей коллекции ............................................. 383
15.1.4. Получение сведений об элементах коллекции ........................................................... 389
15.1.5. Перебор элементов коллекции .................................................................................... 390
15.1.6. Поиск и фильтрация элементов коллекции ................................................................ 391
15.1.7. Упорядочивание элементов коллекции ...................................................................... 396
15.1.8. Группировка элементов коллекций ............................................................................. 398
15.1.9. Агрегатные вычисления в коллекциях ........................................................................ 399
15.1.10. Получение сведений о коллекции ............................................................................. 400
15.1.11. Прочие инструменты для обработки коллекций ........................................................ 401
15.2. Коллекции, заполняемые по запросу ................................................................................ 406
15.2.1. Создание коллекций, заполняемых по запросу .......................................................... 406
15.2.2. Работа с коллекциями, заполняемыми по запросу .................................................... 406
ЧАСТЬ III. РАСШИРЕННЫЕ ИНСТРУМЕНТЫ
И ДОПОЛНИТЕЛЬНЫЕ БИБЛИОТЕКИ ............................................................. 409
Глава 16. Базы данных и модели: расширенные инструменты ........................ 411
16.1. Отложенная и немедленная выборка связанных записей................................................ 411
16.2. Выборка наборов записей по частям ................................................................................ 413

Оглавление

11

16.3. Фильтрующие связи «многие-со-многими» ..................................................................... 415
16.4. Полиморфные связи ........................................................................................................... 417
16.4.1. Создание поля внешнего ключа для полиморфной связи ......................................... 417
16.4.2. Создание полиморфных связей ................................................................................... 418
16.4.2.1. Полиморфная связь «один-со-многими» ........................................................... 418
16.4.2.2. Полиморфная связь «один-с-одним из многих» ............................................... 420
16.4.2.3. Полиморфная связь «один-с-одним» ................................................................. 420
16.4.2.4. Полиморфная связь «многие-со-многими» ....................................................... 421
16.4.3. Работа с записями, связанными полиморфной связью ............................................. 423
16.4.4. Указание своих типов связываемых записей ............................................................. 424
16.5. Пределы ............................................................................................................................... 426
16.5.1. Локальные пределы ...................................................................................................... 426
16.5.2. Глобальные пределы ....................................................................................................427
16.6. Выполнение «сырых» SQL-запросов ................................................................................ 429
16.6.1. «Сырые» вызовы функций СУБД................................................................................ 429
16.6.2. «Сырые» команды SQL ................................................................................................ 429
16.5.3. «Сырые» SQL-запросы целиком.................................................................................. 431
16.7. Блокировка записей ............................................................................................................ 432
16.8. Управление транзакциями .................................................................................................432
16.8.1. Автоматическое управление транзакциями ............................................................... 433
16.8.2. Ручное управление транзакциями ............................................................................... 433
16.9. Очистка моделей ................................................................................................................. 433

Глава 17. Шаблоны: расширенные инструменты
и дополнительные библиотеки ................................................................................. 436
17.1. Библиотека Laravel HTML: создание веб-форм и элементов управления ..................... 436
17.1.1. Создание элементов управления ................................................................................. 436
17.1.2. Создание веб-форм ....................................................................................................... 439
17.1.3. Создание гиперссылок .................................................................................................441
17.2. Библиотека genert/bbcode: поддержка BBCode ................................................................ 443
17.2.1. Использование библиотеки genert/bbcode .................................................................. 443
17.2.2. Поддерживаемые BBCode-теги ................................................................................... 444
17.2.3. Добавление своих BBCode-тегов ................................................................................ 445
17.3. Библиотека Captcha for Laravel: поддержка CAPTCHA .................................................. 446
17.3.1. Настройка Captcha for Laravel ..................................................................................... 447
17.3.2. Использование Captcha for Laravel.............................................................................. 448
17.4. Написание своих директив шаблонизатора ...................................................................... 449
17.4.1. Написание простейших директив................................................................................ 450
17.4.1.1. Форматировщики объектов ................................................................................ 451
17.4.2. Написание условных директив .................................................................................... 451
17.5. Пакет Laravel Mix ............................................................................................................... 452
17.5.1. Исходные файлы и их расположение.......................................................................... 453
17.5.2. Конфигурирование Laravel Mix ................................................................................... 453
17.5.2.1. Обработка таблиц стилей ................................................................................... 454
17.5.2.2. Обработка веб-сценариев ................................................................................... 455
17.5.2.3. Копирование файлов и папок ............................................................................. 456
17.5.2.4. Мечение файлов .................................................................................................. 457
17.5.3. Запуск Laravel Mix ........................................................................................................ 458
17.6. Использование Bootstrap .................................................................................................... 459

12

Оглавление

Глава 18. Обработка выгруженных файлов .......................................................... 461
18.1. Настройки подсистемы обработки выгруженных файлов .............................................. 461
18.2. Создание символических ссылок на папки с выгруженными файлами ......................... 464
18.3. Хранение выгруженных файлов ........................................................................................ 465
18.4. Базовые средства для обработки выгруженных файлов.................................................. 465
18.4.1. Валидаторы для выгруженных файлов ....................................................................... 465
18.4.2. Получение выгруженных файлов ................................................................................ 467
18.4.3. Получение сведений о выгруженных файлах............................................................. 467
18.4.4. Сохранение выгруженных файлов .............................................................................. 468
18.4.5. Выдача выгруженных файлов посетителям ............................................................... 470
18.4.5.1. Вывод выгруженных файлов .............................................................................. 470
18.4.5.2. Реализация загрузки выгруженного файла ....................................................... 471
18.4.6. Удаление выгруженных файлов .................................................................................. 472
18.5. Расширенные средства для работы с выгруженными файлами...................................... 472
18.5.1. Чтение из файлов и запись в них ................................................................................. 473
18.5.2. Получение сведений о файле ....................................................................................... 473
18.5.3. Прочие манипуляции с файлами ................................................................................. 474
18.5.4. Работа с папками .......................................................................................................... 475
18.6. Библиотека bkwld/croppa: вывод миниатюр ..................................................................... 475
18.6.1. Настройки библиотеки bkwld/croppa .......................................................................... 476
18.6.2. Использование библиотеки bkwld/croppa ................................................................... 478
18.6.3. Удаление миниатюр .....................................................................................................481
Глава 19. Безопасность и разграничение доступа:
расширенные инструменты и дополнительная библиотека .............................. 482
19.1. Низкоуровневые средства для работы с пользователями ............................................... 482
19.1.1. Низкоуровневые средства для регистрации пользователей ...................................... 482
19.1.2. Низкоуровневые средства для входа........................................................................... 483
19.1.3. Низкоуровневые средства для выполнения выхода .................................................. 485
19.1.4. Низкоуровневые средства для подтверждения пароля.............................................. 485
19.1.5. Низкоуровневые средства для проверки существования адреса
электронной почты ................................................................................................................... 486
19.1.6. Низкоуровневые средства для сброса пароля ............................................................ 487
19.1.7. Корректная правка пароля ........................................................................................... 490
19.2. Библиотека Laravel Socialite: вход через сторонние интернет-службы ......................... 491
19.2.1. Создание приложения «ВКонтакте» ........................................................................... 491
19.2.2. Установка и настройка Laravel Socialite ..................................................................... 493
19.2.3. Использование Laravel Socialite .................................................................................. 494
19.2.3.1. Действие первое: обращение к сторонней интернет-службе........................... 495
19.2.3.2. Действие второе: поиск (регистрация) пользователя и вход ........................... 495
19.2.3.3. Завершающие операции: создание маршрутов и гиперссылки входа ............ 496
19.3. Защита от атак CSRF .......................................................................................................... 497
19.4. Ограничители частоты запросов ....................................................................................... 498
19.4.1. Простейшие ограничители частоты запросов ............................................................ 498
19.4.2. Именованные ограничители частоты запросов.......................................................... 499
19.4.3. Низкоуровневые ограничители частоты запросов ..................................................... 501

Глава 20. Внедрение зависимостей, провайдеры и фасады ................................ 504
20.1. Внедрение зависимостей .................................................................................................... 504
20.1.1. Простейшие случаи внедрения зависимостей ............................................................ 504

Оглавление

13

20.1.2. Управление внедрением зависимостей ....................................................................... 506
20.1.2.1. Простая регистрация классов и объектов ......................................................... 506
20.1.2.2. Подмена классов и реализации .......................................................................... 509
20.1.2.3. Гибкая подмена классов и реализации .............................................................. 510
20.1.2.4. Гибкая регистрация значений произвольного типа .......................................... 511
20.1.2.5. Переопределение регистрации ........................................................................... 512
20.1.2.6. Вызов методов и функций, в которых используется внедрение
зависимостей ...................................................................................................................... 512
20.1.2.7. Подмена методов................................................................................................. 514
20.2. Провайдеры ......................................................................................................................... 515
20.2.1. Список провайдеров, используемых веб-сайтом ....................................................... 515
20.2.2. Создание своих провайдеров ....................................................................................... 517
20.3. Фасады ................................................................................................................................. 518

Глава 21. Посредники ................................................................................................. 520
21.1. Посредники, используемые веб-сайтом ............................................................................ 520
21.1.1. Управление очередностью выполнения посредников ............................................... 523
21.1.2. Параметры посредников .............................................................................................. 523
21.2. Написание своих посредников .......................................................................................... 523
21.2.1. Как исполняется посредник? ....................................................................................... 523
21.2.2. Создание посредников .................................................................................................524
21.2.3. Посредники с завершающими действиями ................................................................ 526
Глава 22. События и их обработка ..........................................................................528
22.1. События-классы .................................................................................................................. 528
22.1.1. Обработка событий-классов: слушатели .................................................................... 528
22.1.1.1. Создание слушателей-классов............................................................................ 528
22.1.1.2. Явная привязка слушателей-классов к событиям ............................................. 530
22.1.1.3. Автоматическая привязка слушателей-классов к событиям ........................... 531
22.1.1.4. Слушатели-функции............................................................................................ 532
22.1.1.5. Просмотр списков слушателей, привязанных к событиям-классам ............... 532
22.1.2. Обработка событий-классов: подписчики .................................................................. 533
22.1.3. События-классы, поддерживаемые фреймворком..................................................... 534
22.1.3.1. События подсистемы разграничения доступа .................................................. 534
22.1.3.2. События других подсистем ................................................................................ 536
22.1.4. Создание и использование своих событий-классов ................................................... 536
22.1.4.1. Создание событий-классов ................................................................................. 536
22.1.4.2. Создание событий-классов и их слушателей .................................................... 537
22.1.4.3. Генерирование своих событий ........................................................................... 538
22.2. События-строки .................................................................................................................. 538
22.2.1. Привязка обработчиков к событиям-строкам ............................................................ 539
22.2.2. Генерирование событий-строк .................................................................................... 539
22.3. События моделей ................................................................................................................ 540
22.3.1. Обработка событий моделей ....................................................................................... 540
22.3.1.1. Обработка событий моделей посредством слушателей-функций ................... 540
22.3.1.2. Связывание событий моделей с событиями-классами ..................................... 540
22.3.1.3. Использование обозревателей............................................................................ 541
22.3.2. Список событий моделей ............................................................................................. 542
22.3.3. Временное отключение событий в моделях ............................................................... 543

14

Оглавление

Глава 23. Отправка электронной почты ................................................................ 544
23.1. Настройки подсистемы отправки электронной почты .................................................... 544
23.2. Создание электронных писем ............................................................................................ 547
23.2.1. Создание классов электронных писем ........................................................................ 547
23.2.2. Генерирование электронных писем ............................................................................ 548
23.2.3. Написание шаблонов электронных писем .................................................................. 551
23.2.4. Написание электронных писем на языке Markdown.................................................. 552
23.2.4.1. Классы писем, написанных на Markdown ......................................................... 552
23.2.4.2. Написание шаблонов писем на Markdown ........................................................ 552
23.2.4.3. Управление генерированием писем, написанных на Markdown ..................... 553
23.3. Отправка электронных писем ............................................................................................ 555
23.4. Предварительный просмотр электронных писем ............................................................ 556
23.5. События, генерируемые при отправке электронных писем ............................................ 557
23.6. Доступ к письмам, отправленным посредством службы array ...................................... 557
Глава 24. Оповещения................................................................................................ 558
24.1. Создание оповещений ........................................................................................................ 558
24.2. Написание оповещений ...................................................................................................... 560
24.2.1. Почтовые оповещения ................................................................................................. 560
24.2.1.1. Генерирование простых почтовых оповещений............................................... 560
24.2.1.2. Генерирование почтовых оповещений на основе текстовых
и HTML-шаблонов ............................................................................................................. 562
24.2.1.3. Генерирование почтовых оповещений на основе Markdown-шаблонов ........ 562
24.2.1.4. Указание адреса получателя ............................................................................... 563
24.2.2. SMS-оповещения .......................................................................................................... 563
24.2.2.1. Подготовительные действия и настройка службы SMS-оповещений ............ 563
24.2.2.2. Генерирование произвольных SMS-оповещений ............................................. 564
24.2.2.3. Указание телефона получателя .......................................................................... 565
24.2.3. Slack-оповещения ......................................................................................................... 565
24.2.3.1. Генерирование Slack-оповещений ..................................................................... 565
24.2.3.2. Добавление вложений ......................................................................................... 566
24.2.3.3. Указание интернет-адреса получателя .............................................................. 568
24.2.4. Табличные оповещения................................................................................................ 568
24.2.4.1. Создание таблицы для хранения табличных оповещений ............................... 568
24.2.4.2. Генерирование табличных оповещений ............................................................ 569
24.2.5. Оповещения, отправляемые по нескольким каналам ................................................ 570
24.3. Отправка оповещений ........................................................................................................ 570
24.3.1. Отправка оповещений произвольным получателям .................................................. 571
24.4. Предварительный просмотр почтовых оповещений ....................................................... 571
24.5. Работа с табличными оповещениями................................................................................ 571
24.6. События, генерируемые при отправке оповещений ........................................................ 573

Глава 25. Очереди и отложенные задания ............................................................. 574
25.1. Настройка подсистемы очередей ...................................................................................... 574
25.1.1. Настройка самих очередей........................................................................................... 574
25.1.2. Подготовка таблиц для хранения отложенных заданий ............................................ 577
25.1.3. Настройка баз данных Redis ........................................................................................ 578
25.2. Отложенные задания-классы ............................................................................................. 579
25.2.1. Создание отложенных заданий-классов ..................................................................... 579

Оглавление

15

25.2.1.1. Создание отложенных заданий-классов: базовые инструменты ..................... 579
25.2.1.2. Параметры отложенных заданий-классов ......................................................... 581
25.2.1.3. Обработка ошибок в отложенных заданиях-классах ....................................... 583
25.2.1.4. Взаимодействие с очередью ............................................................................... 584
25.2.1.5. Уникальные задания ........................................................................................... 584
25.2.1.6. Неотложные задания ........................................................................................... 586
25.2.2. Запуск отложенных заданий-классов .......................................................................... 586
25.3. Отложенные задания-функции .......................................................................................... 587
25.4. Цепочки отложенных заданий ........................................................................................... 588
25.5. Специфические разновидности отложенных заданий ..................................................... 589
25.5.1. Отложенные слушатели событий ................................................................................ 589
25.5.2. Отложенные электронные письма............................................................................... 591
25.5.3. Отложенные оповещения ............................................................................................. 593
25.6. Выполнение отложенных заданий .................................................................................... 594
25.6.1. Запуск обработчика отложенных заданий .................................................................. 594
25.6.2. Работа с проваленными заданиями ............................................................................. 596
25.6.3. Очистка очереди заданий ............................................................................................. 597
25.7. Пакеты отложенных заданий ............................................................................................. 597
25.7.1. Подготовка таблицы для хранения пакетов отложенных заданий ........................... 598
25.7.2. Создание отложенных заданий, пригодных для использования в пакетах.............. 598
25.7.3. Создание и запуск пакетов отложенных заданий ...................................................... 598
25.7.4. Взаимодействие с выполняющимся пакетом ............................................................. 600
25.7.5. Получение сведений о пакете ...................................................................................... 601
25.7.6. Выполнение пакетов отложенных заданий ................................................................ 602
25.8. Посредники отложенных заданий ..................................................................................... 603
25.8.1. Ограничение частоты выполнения заданий ............................................................... 603
25.8.2. Предотвращение наложения заданий ......................................................................... 604
25.8.3. Отложенное выполнение ошибочных заданий .......................................................... 605
25.9. События, генерируемые при выполнении отложенных заданий .................................... 607

Глава 26. Cookie, сессии, всплывающие сообщения и криптография.............. 609
26.1. Cookie .................................................................................................................................. 609
26.1.1. Настройки cookie .......................................................................................................... 609
26.1.2. Создание cookie ............................................................................................................ 609
26.1.3. Считывание cookie........................................................................................................ 611
26.1.4. Удаление cookie ............................................................................................................ 612
26.2. Сессии .................................................................................................................................. 612
26.2.1. Подготовка к работе с сессиями .................................................................................. 613
26.2.1.1. Настройки сессий ................................................................................................ 613
26.2.1.2. Создание таблицы для хранения сессий ............................................................ 614
26.2.2. Работа с сессиями ......................................................................................................... 615
26.2.2.1. Запись данных в сессию и их изменение........................................................... 615
26.2.2.2. Чтение данных из сессии .................................................................................... 616
26.2.2.3. Удаление данных из сессии ................................................................................ 616
26.2.2.4. Блокировка сессий .............................................................................................. 617
26.2.2.5. Предотвращение сетевых атак на сессии .......................................................... 617
26.3. Всплывающие сообщения ..................................................................................................618
26.4. Криптография...................................................................................................................... 619
26.4.1. Шифрование данных ....................................................................................................619

16

Оглавление

26.4.2. Хеширование и сверка паролей ................................................................................... 620
26.4.2.1. Настройки хеширования ..................................................................................... 620
26.4.2.2. Хеширование и сверка ........................................................................................ 620
26.4.3. Генерирование подписанных интернет-адресов ........................................................ 621

Глава 27. Планировщик заданий ............................................................................. 624
27.1. Создание заданий планировщика ...................................................................................... 624
27.1.1. Как пишутся задания планировщика?......................................................................... 624
27.1.2. Параметры заданий планировщика ............................................................................. 626
27.1.2.1. Расписание запуска заданий ............................................................................... 626
27.1.2.2. Дополнительные параметры заданий ................................................................ 628
27.1.3. Обработка вывода, генерируемого заданиями планировщика ................................. 630
27.1.4. Исполнение указанного кода перед выполнением задания и после него ................ 631
27.1.5. Отправка сигналов по указанным интернет-адресам ................................................ 631
27.2. Работа с заданиями планировщика ................................................................................... 632
27.2.1. Запуск планировщика заданий .................................................................................... 632
27.2.1.1. Запуск с использованием штатного планировщика
операционной системы ...................................................................................................... 632
27.2.1.2. Запуск в независимом режиме ........................................................................... 634
27.2.2. Вывод списка заданий планировщика ........................................................................ 634
27.2.3. Удаление распределенных блокировок ...................................................................... 635
27.3. События, генерируемые при выполнении заданий планировщика ................................ 635

Глава 28. Локализация ............................................................................................... 636
28.1. Быстрая локализация .......................................................................................................... 636
28.2. Локализация с применением обозначений ....................................................................... 637
28.2.1. Подстановка параметров в переведенные строки ...................................................... 639
28.2.2. Вывод существительных во множественном числе .................................................. 639
28.2.3. Локализация сообщений об ошибках ввода ............................................................... 641
28.3. Реализация переключения на другой язык ....................................................................... 642
28.4. Библиотека Laravel Lang: локализация на множество языков ........................................ 644
Глава 29. Кеширование .............................................................................................. 646
29.1. Кеширование на стороне сервера ...................................................................................... 646
29.1.1. Подготовка подсистемы кеширования ....................................................................... 646
29.1.1.1. Настройка подсистемы кеширования ................................................................ 646
29.1.1.2. Создание таблицы для хранения кеша .............................................................. 648
29.1.2. Работа с кешем стороны сервера ................................................................................ 649
29.1.2.1. Сохранение данных в кеше и их правка ............................................................ 649
29.1.2.2. Чтение данных из кеша ....................................................................................... 650
29.1.2.3. Удаление данных из кеша................................................................................... 651
29.1.3. Распределенные блокировки ....................................................................................... 652
29.1.3.1. Немедленные распределенные блокировки ...................................................... 652
29.1.3.2. Распределенные блокировки с ожиданием ....................................................... 654
29.1.3.3. Передача распределенных блокировок между процессами ............................ 655
29.1.4. События, генерируемые кешем ................................................................................... 656
29.2. Кеширование на стороне клиента ..................................................................................... 657

Оглавление

17

Глава 30. Разработка веб-служб ............................................................................... 658
30.1. Бэкенды: преобразование данных — базовые инструменты .......................................... 658
30.1.1. Выдача данных в формате JSON ................................................................................. 659
30.1.2. Задание структуры генерируемых JSON-объектов.................................................... 661
30.2. Бэкенды: преобразование данных — ресурсы и ресурсные коллекции ......................... 664
30.2.1. Ресурсы .......................................................................................................................... 664
30.2.1.1. Написание ресурсов ............................................................................................ 664
30.2.1.2. Задание структуры JSON-объектов, генерируемых ресурсами ....................... 665
30.2.1.3. Дополнительные параметры ресурсов .............................................................. 668
30.2.1.4. Использование ресурсов ..................................................................................... 669
30.2.2. Ресурсные коллекции ...................................................................................................670
30.2.2.1. Быстрое JSON-кодирование коллекции записей .............................................. 670
30.2.2.2. Написание ресурсных коллекций....................................................................... 670
30.2.2.3. Пагинация в ресурсных коллекциях .................................................................. 673
30.3. Бэкенды: обработка данных ...............................................................................................674
30.3.1. Выдача записей ............................................................................................................. 674
30.3.2. Добавление, правка и удаление записей ..................................................................... 674
30.3.3. Совмещенная обработка данных ................................................................................. 676
30.4. Бэкенды: разграничение доступа....................................................................................... 676
30.5. Фронтенды: взаимодействие с бэкендами ........................................................................ 679
30.6. Фронтенды: использование React и Vue ........................................................................... 681
Глава 31. Вещание ....................................................................................................... 683
31.1. Бэкенд: подготовка подсистемы вещания ........................................................................ 683
31.1.1. Настройка подсистемы вещания ................................................................................. 683
31.1.2. Подготовка проекта к реализации вещания ............................................................... 685
31.1.3. Установка и настройка Laravel Websockets ................................................................ 685
31.2. Бэкенд: вещаемые события и оповещения ....................................................................... 687
31.2.1. Вещаемые события ....................................................................................................... 687
31.2.1.1. Вещаемые события моделей .............................................................................. 690
31.2.2. Вещаемые оповещения ................................................................................................ 693
31.3. Бэкенд: каналы вещания .................................................................................................... 695
31.3.1. Общедоступные каналы вещания................................................................................ 695
31.3.2. Закрытые каналы вещания ........................................................................................... 695
31.3.3. Каналы присутствия ..................................................................................................... 697
31.4. Фронтенд: прослушивание каналов вещания ................................................................... 699
31.4.1. Использование Laravel Echo ........................................................................................ 699
31.4.2. Прослушивание общедоступных каналов .................................................................. 701
31.4.3. Прослушивание закрытых каналов ............................................................................. 703
31.4.4. Прослушивание каналов присутствия......................................................................... 703
31.4.5. Отправка произвольных уведомлений ........................................................................ 704
31.5. Запуск вещания ................................................................................................................... 705
Глава 32. Команды утилиты artisan ........................................................................ 706
32.1. Получение сведений о командах утилиты artisan ............................................................ 706
32.2. Команды-классы ................................................................................................................. 707
32.2.1. Создание команд-классов ............................................................................................ 707
32.2.2. Описание формата вызова команд .............................................................................. 709
32.2.3. Получение значений аргументов ................................................................................. 711

18

Оглавление

32.2.4. Получение данных от пользователя ............................................................................ 712
32.2.5. Вывод данных ............................................................................................................... 713
32.2.5.1. Вывод индикатора процесса............................................................................... 714
32.2.6. Вызов из команды других команд............................................................................... 715
32.2.7. Регистрация команд-классов ....................................................................................... 716
32.3. Команды-функции .............................................................................................................. 716
32.4. Программный вызов команд.............................................................................................. 718
32.5. События утилиты artisan .................................................................................................... 718

Глава 33. Обработка ошибок .................................................................................... 719
33.1. Настройка веб-страниц с сообщениями об ошибках ....................................................... 719
33.2. Создание и использование своих исключений ................................................................. 720
33.2.1. Создание своих исключений........................................................................................ 720
33.2.2. Возбуждение своих исключений ................................................................................. 722
33.3. Настройка обработки существующих исключений ......................................................... 723
33.4. Подавление исключений .................................................................................................... 725
Глава 34. Журналирование и дополнительные средства отладки .................... 728
34.1. Подсистема журналирования............................................................................................. 728
34.1.1. Настройка подсистемы журналирования ................................................................... 728
34.1.2. Занесение записей в журнал ........................................................................................ 731
34.1.2.1. Разделяемая дополнительная информация ....................................................... 732
34.1.3. Событие, генерируемое при занесении записи в журнал .......................................... 733
34.2. Дополнительные средства отладки ................................................................................... 733
Глава 35. Публикация веб-сайта .............................................................................. 735
35.1. Подготовка веб-сайта к публикации ................................................................................. 735
35.1.1. Удаление ненужного кода и данных ........................................................................... 735
35.1.2. Настройка под платформу публикации ...................................................................... 736
35.1.3. Переключение в режим эксплуатации ........................................................................ 736
35.1.4. Задание списка доверенных прокси-серверов ............................................................ 736
35.1.5. Задание списка доверенных хостов............................................................................. 737
35.1.6. Компиляция шаблонов ................................................................................................. 738
35.1.7. Кеширование маршрутов ............................................................................................. 738
35.1.8. Кеширование настроек .................................................................................................739
35.1.9. Кеширование обработчиков событий ......................................................................... 739
35.1.10. Приведение таблиц стилей и веб-сценариев к виду,
оптимальному для публикации................................................................................................ 740
35.2. Перенос веб-сайта на платформу для публикации........................................................... 740
35.3. Настройка веб-сервера и запуск сторонних программ .................................................... 741
35.4. Режим обслуживания.......................................................................................................... 741

Заключение ................................................................................................................... 744
Приложение. Описание электронного архива ....................................................... 746
Предметный указатель .............................................................................................. 747

Предисловие
Laravel — сейчас самый популярный в мире PHP-фреймворк, предназначенный для
разработки веб-сайтов. Более того, он остается номером один с 2015 года, до сих пор
никому не уступив призовое место.

Почему именно Laravel?
Да потому, что:
 Laravel — полнофункциональный фреймворк.

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

не все конкуренты.
Хотите рассылать пользователям сайта короткие оповещения о каких-либо событиях (например, о появлении новых статей)? Нет ничего проще: подсистема оповещений Laravel позволяет отправлять такие оповещения не только традиционно, по
электронной почте, но и по SMS. Хотите производить на сайте какие-либо технические работы по определенному расписанию (например, очищать мусорные данные
каждый месяц)? Никаких проблем: встроенный планировщик Laravel запустит
выполнение задачи в нужный момент. Может, желаете повысить отзывчивость сайта, перенеся наиболее «медленные» операции (скажем, рассылку почты) в параллельный процесс? И это не составит труда — достаточно лишь задействовать подсистему отложенных заданий!
 У Laravel низкий порог вхождения.

Для программирования сайтов с применением Laravel достаточно базовых знаний
PHP и основ веб-разработки. Фреймворк не требует сложного конфигурирования и
готов к работе сразу после установки. Отдельные модули, составляющие код сайта,
не требуется явно связывать друг с другом — достаточно «разложить» их по нужным папкам, и сайт будет прекрасно работать.

20

Предисловие

 Существует множество дополнительных библиотек, расширяющих функциональ-

ность фреймворка, и программ, помогающих в работе.
Дополнительные библиотеки добавляют фреймворку поддержку BBCode, создания
миниатюр графических изображений, выполнения входа на сайт через сторонние
интернет-службы (например, социальные сети) и многое другое. В число дополнительных программ входят мощные отладочные панели, гибко настраиваемые административные подсистемы, различные инструментальные утилиты и пр. Часть этих
библиотек и программ написана самим сообществом разработчиков Laravel.
На фоне столь значимых достоинств теряются отдельные недостатки фреймворка:
 местами — чрезмерная функциональность.

Например, существуют функции __() (два подчеркивания) и trans(), выполняющие
одинаковое действие. Ряд классов содержат методы, выполняющие одну и ту же задачу. Зачем это было сделано — непонятно…
 плохая официальная документация.

Она неполна, местами поверхностна, местами хаотична. Некоторые ключевые моменты не описаны, и приходится искать информацию о них в сторонних источниках
и даже в программном коде фреймворка. Полностью отсутствует руководство для
начинающих, дающее основные знания в процессе разработки какого-либо учебного
сайта.
ВНИМАНИЕ!
Автор предполагает, что читатели этой книги знакомы с языками HTML, CSS, JavaScript,
PHP, принципами работы СУБД и имеют базовые навыки в веб-разработке. В книге
все это описываться не будет.

О чем эта книга?
Автор книги поставил перед собой задачи:
 привести в начале книги вводный курс для начинающих.

В нем описано программирование учебного веб-сайта — простой доски объявлений.
И попутно объясняются основные понятия и принципы Laravel;
 дать максимально полное описание всех программных инструментов Laravel, при-

меняемых при разработке среднестатистического сайта.
За кадром остались лишь средства, чья полезность, по мнению автора, сомнительна
(наподобие подсистемы автоматического тестирования), или применяемые в крайне
специфических случаях (скажем, встроенный HTTP-клиент), а также создание дополнительных служб и библиотек для Laravel. Также не рассмотрены наиболее сложные дополнительные библиотеки и программы: средства для электронной коммерции, отладочные панели и административные подсистемы — поскольку объем книги ограничен;
 в том числе — рассказать о том, о чем молчит официальная документация.

Для этого автор изучал сторонние источники информации, программный код Laravel
и активно экспериментировал;

Предисловие

21

 привести побольше практических примеров применения того или иного программ-

ного инструмента.
Код многих примеров взят с работающего экспериментального сайта, написанного
автором.
ЭЛЕКТРОННЫЙ АРХИВ
Сопровождающий книгу электронный архив содержит программный код учебного сайта электронной доски объявлений, разработка которого описывается в части I книги.
Архив доступен для скачивания с сервера издательства «БХВ» по ссылке https://zip.
bhv.ru/9785977517256.zip, ссылка на него также ведет со страницы книги на сайте
https://bhv.ru/ (см. приложение).

Используемое ПО
Автор применял в работе над книгой следующее ПО:
 Microsoft Windows 10, русская 64-разрядная редакция со всеми установленными об-

новлениями;
 PHP — 8.1.5;
 Composer — 2.3.5;
 библиотека-комплект laravel/laravel — 9.1.1, включающая:

• фреймворк Laravel (laravel/framework) — 9.9.0;
• консоль Laravel (laravel/tinker) — 2.7.2;
• Laravel Mix — 6.0.49;
 laravel/ui — 3.4.5;
 Laravel Lang — 10.7.1;
 LaravelLang — 10.0.01;
 doctrine/dbal — 3.3.6;
 Laravel HTML — 6.3.0;
 genert/bbcode — 1.1.2;
 Captcha for Laravel — 3.2.7;
 bkwld/croppa — 6.0.1;
 Laravel Socialite — 5.5.2;
 провайдер «ВКонтакте» для Laravel Socialite — 4.2.2;
 predis — 1.1.10;
 Laravel Websockets — 1.13.1;
 Laravel Echo — 1.12.0;
 pusher-js — 7.1.1-beta.
1

Laravel Lang и LaravelLang — это разные библиотеки.

22

Предисловие

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

ляемых в исходный код (например, параметров функций и методов), которые
дополнительно выделяются курсивом. Например:
environment()

Здесь вместо слова режим должно быть подставлено реальное обозначение режима,
в котором работает сайт.
 В квадратные скобки ([]) заключаются фрагменты кода, необязательные к указа-

нию. Например:
php artisan key:generate [--force]

Здесь командный ключ --force может быть указан, а может и не указываться.
У необязательных параметров функций и методов ставятся значения по умолчанию.
Пример:
unsignedInteger([, =false])

Здесь у необязательного параметра автоинкрементное значение по умолчанию false.
 Вертикальной чертой (|) разделяются различные варианты языковой конструкции,

из которых следует указать лишь какой-то один. Пример:
dropColumn(|)

Здесь в качестве параметра метода dropColumn() следует поставить либо имя поля,
либо массив имен полей.
 Слишком длинные, не помещающиеся на одной строке языковые конструкции автор

разрывал на несколько строк и в местах разрывов ставил знак . Например:
php artisan queue:retry 49a473d6-198e-45df-a17e-4e885e7875fc 
91401d2c-0784-4f43-824c-34f94a33c24d

Приведенный код разбит на две строки, но должен быть набран в одну. Символ 
при этом вводить не нужно.
 Троеточием (. . .) помечены фрагменты кода, пропущенные ради сокращения объ-

ема текста. Пример:

. . .


Здесь пропущено содержимое тега , не представляющее интереса при рассмотрении примера.
Обычно такое можно встретить в исправленных впоследствии фрагментах кода —
приведены лишь собственно исправленные выражения, а оставшиеся неизмененны-

Предисловие

23

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

мер:
class Bb extends Model {
. . .
protected $fillable = ['title', 'content', 'price'];
}

Здесь в класс Bb был добавлен код, объявляющий свойство fillable.
 Зачеркнутым шрифтом выделяется код, подлежащий удалению. Пример:
public function detail(Bb $bb) {
$bb = Bb::find($bb);
$s = $bb->title . "\r\n\r\n";
. . .
}

Первое выражение тела метода detail() следует удалить.

ЧАСТЬ

I

Основы Laravel
на практическом примере
Глава 1.

Простейший веб-сайт — доска объявлений

Глава 2.

Доска объявлений 2.0: разграничение доступа,
работа с объявлениями и локализация

ГЛАВА

1

Простейший веб-сайт —
доска объявлений
В этой главе мы начнем писать с применением Laravel простой сайт — электронную
доску объявлений. И на практическом примере рассмотрим принципы, положенные
в основу этого PHP-фреймворка.

1.1. Подготовительные действия
1. Установим исполняющую среду PHP. Ее дистрибутив и инструкции по установке
можно найти на «домашнем» сайте платформы (https://www.php.net/).
Для запуска разрабатываемых сайтов удобнее всего применять отладочный вебсервер, встроенный в PHP. Отдельную программу веб-сервера для этого использовать необязательно.
2. Установим программу Composer, чей дистрибутив находится на «домашнем» сайте
этой утилиты (https://getcomposer.org/).
Composer — это установщик PHP-библиотек и утилит вместе с зависимостями (библиотеками, используемыми устанавливаемой библиотекой). Composer самостоятельно ищет указанную библиотеку в интернет-репозитории https://repo.packagist.org/,
загружает и распаковывает ее.
В процессе установки Composer необходимо указать путь к файлу php.exe (консольной редакции исполняющей среды PHP) и предписать добавить этот путь в список
путей системной переменной PATH, установив соответствующий флажок.
Установив необходимые программы, начнем разработку сайта, создав его проект.

1.2. Проект и его создание. Папка проекта
Теория
Проект — это совокупность файлов, хранящих программный, HTML- и CSS-код сайта,
а также всевозможные дополнительные данные (например, параметры сайта и используемую им базу данных). Можно сказать, что проект — это и есть сайт.

28

Часть I. Основы Laravel на практическом примере

Все файлы, составляющие проект, должны храниться в одной папке, называемой папкой проекта. Папка проекта может иметь произвольное местоположение в файловой
системе.
При создании проекта его папка получает то же имя, что и сам проект. Однако в дальнейшем ее можно переименовать и даже переместить в другое место.
Во вновь созданном проекте следует установить дополнительную библиотеку laravel/ui,
служащую для быстрого создания базовых средств разграничения доступа (с ними мы
познакомимся в главе 2).

Практика
Создадим проект нашего сайта, дав ему имя bboard.
1. В командной строке выполним переход в папку, в которой будет находиться папка
создаваемого проекта (у автора книги это папка C:\work\projects):
c:
cd \
cd work\projects

2. Создадим проект bboard:
composer create-project laravel/laravel bboard "9.1.*"

Команда create-project программы Composer (установленной в разд. 1.1) создает
новый проект PHP-сайта. После этой команды через пробелы последовательно указываются имя ключевой библиотеки, закладываемой в основу создаваемого проекта
(у нас — laravel/laravel, то есть комплект из фреймворка Laravel и некоторых дополнительных библиотек), имя проекта (bboard) и версия ключевой библиотеки
(9.1.*1).
Через некоторое время в текущей папке появится папка bboard, содержащая только
что созданный проект сайта.
3. Перейдем в папку проекта, отдав команду:
cd bboard

4. Установим библиотеку laravel/ui командой:
composer require laravel/ui

Папка проекта хранит множество вложенных папок и файлов. Так, папка app содержит
все программные PHP-модули, составляющие код сайта, относящиеся к разным типам
и «разложенные» по разным папкам, папка config — модули конфигурации, папка
database\migrations — модули миграций, папка public является корневой папкой сайта
(в ней можно сохранять файлы с таблицами стилей и веб-сценариями), папка
resources\views хранит шаблоны, папка routes — модули со списками маршрутов, папка
vendor — сам фреймворк и все его зависимости, а файл .env — локальные настройки
проекта. Более подробно содержимое папки проекта мы рассмотрим в главе 3.
1

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

Глава 1. Простейший веб-сайт — доска объявлений

29

ПОЛЕЗНО ЗНАТЬ


Существует еще одна возможность создать новый Laravel-проект — посредством
утилиты laravel (подробности — в главе 3). Однако с ее помощью невозможно указать версию Laravel, на которой будет основан создаваемый проект.



Установщик Composer может устанавливать библиотеки и утилиты на уровне проекта или на уровне системы.
o При установке на уровне проекта — библиотеки и утилиты записываются в папку vendor текущего проекта и доступны только в текущем проекте. Таким образом устанавливаются библиотеки, используемые в коде проекта. Установка на
уровне проекта выполняется по умолчанию.
o При установке на уровне системы — библиотеки и утилиты записываются
в папке \AppData\Roaming\Composer\vendor и доступны везде. Таким образом устанавливаются инструментальные утилиты.
Установка на уровне системы выполняется отдачей основной команды global
и дополнительной команды require.

Только что созданный «пустой» проект Laravel можно запустить на исполнение и открыть в веб-обозревателе.

1.3. Запуск проекта.
Отладочный веб-сервер PHP
1. В командной строке проверим, находимся ли мы в папке проекта (см. разд. 1.2),
и если это не так, перейдем в эту папку.
2. Запустим отладочный веб-сервер PHP, набрав команду:
php artisan serve

Artisan — это утилита, написанная на PHP, хранящаяся непосредственно в папке
проекта и служащая для выполнения различных действий над проектом. Команда
serve этой утилиты запускает встроенный в PHP отладочный веб-сервер.
3. Прочитаем появившееся в командной строке сообщение, выведенное утилитой
artisan:
Starting Laravel development server: http://127.0.0.1:8000

В нем говорится, что текущий проект Laravel-сайта скоро будет запущен и доступен
через TCP-порт 8000.
4. Запустим веб-обозреватель и перейдем по интернет-адресу http://localhost:8000/.
Веб-обозреватель выведет единственную страницу «пустого» сайта (рис. 1.1).
В процессе работы отладочный веб-сервер будет выводить в командной строке журнал работы. В каждой строке журнала будут показываться: дата и время получения
очередного клиентского запроса, интернет-адрес и TCP-порт, с которых пришел
запрос, и статус серверного ответа.
5. Завершим работу отладочного веб-сервера, переключившись в командную строку,
где он был запущен, и нажав комбинацию клавиш + или +.

30

Часть I. Основы Laravel на практическом примере

Рис. 1.1. Единственная веб-страница «пустого» веб-сайта Laravel

ЕСЛИ ВЫ ИСПРАВИЛИ ИСХОДНЫЙ КОД,

НО НЕ ВИДИТЕ НА ЭКРАНЕ РЕЗУЛЬТАТА ПРАВОК...

...остановите отладочный веб-сервер и запустите его снова.
Имейте в виду, что отладочный сервер весьма медленный, и первый вывод страницы
после значительных правок исходного кода может занять несколько секунд (далее та
же страница будет выводиться быстрее).

Создадим теперь первый контроллер нашего сайта.

1.4. Контроллеры и действия
Теория
Контроллер — это программный модуль, реализующий функциональность одного из
разделов сайта (например, раздела, выводящего объявления). Действие (action) — одна
из операций, выполняемых контроллером (вывод страницы с перечнем объявлений,
вывод отдельного объявления, вывод страницы для добавления объявления, сохранение
добавленного объявления в базе и пр.).
Laravel позволяет создавать контроллеры трех разновидностей. Наиболее часто на
практике применяются контроллеры-классы, реализуемые в виде классов. Контроллеркласс может содержать произвольное количество действий, каждое из которых реализуется в виде общедоступного метода.

Глава 1. Простейший веб-сайт — доска объявлений

31

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

Практика
Напишем контроллер-класс BbsController, обрабатывающий список объявлений, с действием index(), которое в будущем станет выводить страницу с перечнем объявлений, а
сейчас — временную «заглушку» в виде обычного текста.
1. В командной строке проверим, находимся ли мы в папке проекта, и если это не так,
перейдем в эту папку.
ИМЕЙТЕ В ВИДУ!
В дальнейшем автор больше не будет напоминать об этом.

2. Создадим контроллер BbsController:
php artisan make:controller BbsController

Команда make:controller утилиты artisan создает модуль с классом контроллера, чье
имя указано после команды через пробел.
3. Откроем только что сгенерированный модуль app\Http\Controllers\BbsController.php
в текстовом редакторе и посмотрим на его код, приведенный в листинге 1.1 (служебный код и комментарии опущены ради краткости).
Листинг 1.1. Код «пустого» контроллера BbsController
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class BbsController extends Controller {
}

Контроллер объявлен в пространстве имен App\Http\Controllers и является производным от класса Controller. Изначально он «пуст» — не содержит ни одного метода-действия.
4. Объявим в контроллере-классе BbsController действие index(), выводящее временную текстовую «заглушку»:
class BbsController extends Controller {
public function index() {
return response('Здесь будет перечень объявлений.')
->header('Content-Type', 'text/plain');
}
}

Функция response() генерирует серверный ответ, представленный объектом класса
Illuminate\Http\Response, на основе строки, переданной в параметре, и возвращает
его в качестве результата.

32

Часть I. Основы Laravel на практическом примере

Метод header() класса Illuminate\Http\Response помещает в текущий серверный ответ заголовок с заданными в параметрах именем и значением. Мы используем этот
метод, чтобы поместить в ответ заголовок Content-Type со значением text/plain, тем
самым указав веб-обозревателю, что ответ содержит обычный текст.
Готовый ответ следует вернуть из метода-действия в качестве результата — чтобы
Laravel смог отправить его клиенту.
НЕ ЗАБЫВАЕМ СОХРАНЯТЬ ИСПРАВЛЕННЫЕ ФАЙЛЫ!
Автор далее не будет напоминать об этом.

5. Запустим отладочный веб-сервер и откроем разрабатываемый сайт в веб-обозревателе.
В результате мы опять увидим страницу, показанную на рис. 1.1, но не заданную нами
текстовую «заглушку». А все потому, что мы не исправили маршрут.
СОВЕТ
Пользователи текстового редактора Visual Studio Code могут установить весьма полезный набор расширений Laravel Extension Pack. Он обеспечивает улучшенную синтаксическую подсветку, автозавершение кода, автоматическое создание шаблонов и
многое другое.

ПОЛЕЗНО ЗНАТЬ


В Laravel используется принятое в PHP соглашение, согласно которому вложенные
друг в друга пространства имен, в которых объявлен класс, должны соответствовать вложенным друг в друга папкам файловой системы, в которых хранится модуль с кодом этого класса. Так, код класса App\Http\Controllers\BbsController
должен храниться в модуле app\Http\Controllers\BbsController.php.
Следование этому соглашению позволяет программному ядру Laravel быстро найти модуль с нужным классом.



Класс App\Http\Controllers\Controller, являющийся базовым для всех контроллеров-классов Laravel, хранится в модуле app\Http\Controllers\Controller.php. Изначально
он практически «пуст» — лишь включает три трейта (которые мы рассмотрим
в следующих главах).

1.5. Маршруты и списки маршрутов. Фасады
Теория
Каждая операция, производимая сайтом (вывод страницы, сохранение введенных данных в базе и пр.), выполняется при получении им от веб-обозревателя клиентского запроса, выполненного по определенному пути с применением определенного HTTPметода (GET, POST, PATCH и др.).
Путь — это часть интернет-адреса, находящаяся между адресом хоста и набором GETпараметров и идентифицирующая запрашиваемую страницу (например, интернет-адрес
http://localhost:8000/items/34?from=index содержит путь items/34).
Следовательно, чтобы какое-либо действие контроллера выполнилось при получении
запроса, выполненного по определенному пути определенным HTTP-методом, это действие следует связать с нужными путем и методом, создав маршрут.

Глава 1. Простейший веб-сайт — доска объявлений

33

Маршрут Laravel — это объект особого класса, содержащий следующие сведения:
 шаблонный путь — задает нужный формат путей;
 допустимый HTTP-метод — которым должен быть выполнен клиентский запрос;
 действие контроллера — выполняется при совпадении шаблонного пути и допусти-

мого метода с путем и методом, извлеченными из полученного клиентского запроса
(т. е. если маршрут является совпавшим).

В качестве примера рассмотрим следующие маршруты (записаны в формате «шаблонный путь — допустимый метод — выполняемая операция»):
 / (прямой слеш — «корень» сайта) — GET — вывод перечня объявлений;
 // — GET — вывод объявления с заданным ключом;
 /add/ — GET — вывод страницы для добавления объявления;
 / — POST — сохранение добавленного объявления в базе.

Созданные маршруты записываются в особый список. Список веб-маршрутов (ведущих на действия контроллеров, которые выдают обычные страницы) хранится в модуле
routes\web.php.
Просмотр списка маршрутов в поисках совпавшего выполняет подсистема фреймворка,
называемая маршрутизатором. Если ни один маршрут не совпал, маршрутизатор
выводит страницу с сообщением об ошибке 404(запрашиваемый путь не поддерживается).

Практика
Создадим веб-маршрут, связывающий шаблонный путь / («корень» сайта) и допустимый HTTP-метод GET с действием index() контроллера BbsController.
1. Откроем модуль routes\web.php со списком веб-маршрутов в текстовом редакторе и
посмотрим на имеющийся там код (листинг 1.2) — служебный код и комментарии
в нем опущены.
Листинг 1.2. Код списка маршрутов routes\web.php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});

Класс Route — это фасад маршрутизатора (фасадом называется класс, служащий
своего рода «пультом управления» одной из подсистем фреймворка). Статический
метод get(), вызванный у этого фасада, указывает маршрутизатору создать новый
объект маршрута, связывающий допустимый HTTP-метод GET (одноименный методу фасада), шаблонный путь из первого параметра (у нас — /, «корень» сайта)
и контроллер, заданный вторым параметром. Здесь использован контроллерфункция, реализованный в виде функции и содержащий лишь одно действие. Он
генерирует на основе шаблона welcome.blade.php (шаблонами мы займемся далее
в этой главе) страницу, показанную на рис. 1.1.

34

Часть I. Основы Laravel на практическом примере

2. Свяжем изначально созданный маршрут с действием index() контроллера
BbsController, переписав его код следующим образом:
use App\Http\Controllers\BbsController;
Route::get('/', function () {
return view('welcome');
});
Route::get('/', [BbsController::class, 'index']);

Запустим отладочный веб-сервер, откроем сайт и посмотрим на выведенную текстовую
«заглушку» (рис. 1.2).

Рис. 1.2. Текстовая «заглушка», временно выводимая вместо перечня объявлений

Это была разминка. Далее мы займемся серьезным делом — создадим базу данных,
запишем в нее пару-тройку объявлений и будем генерировать перечень объявлений на
основе содержимого базы. Но сначала произведем необходимые настройки.

1.6. Настройки проекта. Подготовка проекта
к работе с базой данных SQLite
Теория
Настройки Laravel-проекта делятся на два вида:
 локальные (или настройки окружения) — задают параметры, относящиеся к текущей платформе (в частности, имя базы данных и сведения для подключения к ней).
Не заносятся в коммиты Git. Хранятся в файле .env, который располагается непосредственно в папке проекта;
 рабочие — задают все параметры разрабатываемого сайта. Заносятся в коммиты Git.
Хранятся в папке config в виде 15 PHP-модулей, каждый из которых содержит
настройки какой-либо из подсистем фреймворка. Настройки, записанные в таком
модуле, организованы в виде ассоциативного массива PHP.

Практика
Настроим проект для работы с базой данных формата SQLite, хранящейся в файле
database\data.sqlite, и заодно создадим эту базу данных.
1. Откроем файл .env, хранящий локальные настройки, в текстовом редакторе и найдем
в нем фрагмент кода, настраивающий подключение к базе данных:
DB_CONNECTION=mysql
. . .
DB_DATABASE=laravel

Глава 1. Простейший веб-сайт — доска объявлений

35

2. Укажем формат базы данных SQLite и дадим файлу, хранящему базу, имя
data.sqlite, исправив значения настроек DB_CONNECTION и DB_DATABASE следующим
образом:
DB_CONNECTION=sqlite
. . .
DB_DATABASE=data.sqlite

В настройке DB_DATABASE мы указали лишь имя файла, в то время как фреймворку
для работы с базой SQLite требуется дать абсолютный путь к файлу. Сейчас сделаем
так, чтобы этот путь формировался автоматически.
3. Откроем модуль config\database.php, хранящий рабочие настройки баз данных, в текстовом редакторе и найдем в нем следующий код:
return [
. . .
'connections' => [
'sqlite' => [
. . .
'database' => env('DB_DATABASE',
database_path('database.sqlite')),
. . .
],
. . .
],
. . .
];

Настройка connections.sqlite.database задает абсолютный путь к файлу базы данных SQLite.
Функция env() возвращает значение, записанное в файле .env, в настройке, чье имя
указано в первом параметре. Если в файле .env нет такой настройки, функция env()
возвращает значение заданного в ней второго параметра.
Функция database_path() принимает в качестве параметра относительный путь
к файлу, заданный от папки database, и возвращает абсолютный путь этого файла.
Таким образом, изначально в рабочую настройку connections.sqlite.database заносится значение локальной настройки DB_DATABASE или, если таковая отсутствует, —
абсолютный путь к несуществующему файлу database\database.sqlite.
К сожалению, значение, извлекаемое из настройки DB_DATABASE файла .env, не «пропускается» через функцию database_path(), что вынуждает программистов указывать там абсолютный путь к файлу с базой. Устраним эту досадную недоработку
разработчиков Laravel, для чего…
4. …перепишем приведенный ранее код следующим образом:
. . .
'database' => database_path(env('DB_DATABASE',
'database.sqlite')),
. . .

36

Часть I. Основы Laravel на практическом примере

5. Создадим в папке database «пустой» файл data.sqlite.
Проще всего сделать это, воспользовавшись контекстным меню Создать | Текстовый документ и переименовав получившийся файл в data.sqlite.
Итак, база данных у нас есть. Осталось создать в ней необходимые таблицы, поля, индексы и связи. Используем для этого миграцию.
ПОЛЕЗНО ЗНАТЬ
Функции env(), database_path(), response() (рассмотрена в разд. 1.4) и многие другие,
описанные в следующих главах, могут быть вызваны в любом месте кода проекта и
носят название хелперов.

1.7. Миграции
Теория
Миграция — программный PHP-модуль, вносящий какие-либо изменения в структуру
базы данных. Миграция может, например, создать таблицу вместе со всеми полями и
индексами, исправить имя или тип поля в существующей таблице, создать или удалить
индекс. Миграция реализуется в виде класса.
Миграцию можно применить или откатить. В процессе применения миграция выполняет все описанные в ней действия. При откате же она возвращает базу данных в состояние, существовавшее перед применением этой миграции. Понятно, что откатить
можно лишь миграцию, примененную ранее.
Программные модули с миграциями хранятся в папке database\migrations. Список всех
примененных миграций в хронологическом порядке сохраняется в особой таблице базы
данных, автоматически создаваемой перед применением самой первой миграции.

Практика
Напишем миграцию create_bbs_table, создающую в базе данных таблицу bbs со следующими полями:
 title — заголовок объявления с названием продаваемого товара (тип — строковый,

длина — 50 символов);

 content — сам текст объявления, описание товара (тип — memo);
 price — цена (тип — вещественное число).

1. В командной строке создадим «пустую» миграцию create_bbs_table:
php artisan make:migration create_bbs_table --create=bbs

Команда make:migration утилиты artisan создает миграцию с заданным именем. Дополнительный параметр --create предписывает вставить в миграцию код, создающий таблицу, чье имя указано в параметре.
2. Откроем только что созданный модуль с именем формата database\migrations\
_create_bbs_table.php, хранящий созданную нами ми-

Глава 1. Простейший веб-сайт — доска объявлений

37

грацию, в текстовом редакторе и посмотрим на содержащийся в нем код (листинг 1.3).
Листинг 1.3. Код «пустой» миграции
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up() {
Schema::create('bbs', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
public function down() {
Schema::dropIfExists('bbs');
}
}

Этот код создает и возвращает объект анонимного класса, который и представляет
миграцию. Класс миграции содержит два метода: up(), выполняющийся в процессе
применения миграции, и down(), запускаемый при ее откате. Параметр --create
предписывает утилите artisan сразу же вставить в эти методы код, соответственно
создающий и удаляющий заданную в параметре таблицу.
В методе up() миграции выполняется создание таблицы. Для этого у фасада Schema,
за которым «прячется» подсистема, манипулирующая структурой базы данных, вызывается метод create(). В первом параметре методу передается имя создаваемой
таблицы, а во втором — анонимная функция, в качестве параметра принимающая
объект класса Blueprint, который представляет структуру создаваемой таблицы. Добавление полей в нее выполняется вызовом различных методов у этого объекта.
Параметр --create также предписывает утилите artisan вставить в код этой функции
вызовы методов id() и timestamps(). Первый метод добавляет в формируемую таблицу поле id, хранящее ключ (какое-либо уникальное значение, однозначно идентифицирующее запись, обычно — автоматически генерируемый уникальный номер).
Поле, хранящее ключ, называется ключевым). Второй метод добавляет поля для
хранения временны́х отметок создания записи (отметка создания) и ее последней
правки (отметка правки).
В методе down() производится удаление таблицы. Для этого у фасада Schema вызывается метод dropIfExists(), которому передается имя удаляемой таблицы.
3. Добавим в метод up() миграции код, создающий поля title, content и price:
public function up() {
Schema::create('bbs', function (Blueprint $table) {
$table->id();

38

Часть I. Основы Laravel на практическом примере
$table->string('title', 50);
$table->text('content');
$table->float('price');
$table->timestamps();
});
}

Метод string() класса Blueprint создает строковое поле типа VARCHAR с именем и
длиной, заданными в параметрах метода. Для создания поля memo типа TEXT и поля
вещественного типа FLOAT используются методы text() и float().
Мы будем выводить объявления в хронологическом порядке, отсортированными по
значению поля отметки создания записи. Это поле создается вызовом метода
timestamps() и по умолчанию имеет имя created_at. Для ускорения сортировки создадим по нему индекс.
4. Добавим код, создающий обычный индекс по полю created_at:
public function up() {
Schema::create('bbs', function (Blueprint $table) {
. . .
$table->timestamps();
$table->index('created_at');
});
}

Мы вызвали метод index() класса Blueprint, задав в параметре имя индексируемого
поля.
5. Применим только что созданную миграцию, набрав в командной строке команду:
php artisan migrate

В результате Laravel выполнит все еще не выполненные миграции, находящиеся
в папке database\migrations.
ПОЛЕЗНО ЗНАТЬ
Только что созданный проект Laravel изначально содержит четыре миграции, создающие служебные таблицы, и, в частности, таблицы со списками зарегистрированных
пользователей (подробности будут приведены в главе 13) и проваленных заданий
(см. главу 25). При первом выполнении миграций они также будут выполнены.

1.8. Модели
Модель — программный модуль, служащий для взаимодействия с обслуживаемой им
таблицей базы данных: выборки записей, извлечения значений полей, добавления,
правки и удаления записей. Модель реализуется в виде класса.
PHP-модули с моделями по умолчанию хранятся в папке app\Models.
Напишем модель Bb, предназначенную для работы с таблицей bbs базы данных.
1. В командной строке создадим модуль с классом модели:
php artisan make:model Bb

Глава 1. Простейший веб-сайт — доска объявлений

39

2. Откроем модуль app\Models\Bb.php, хранящий созданную модель, в текстовом редакторе и посмотрим на его содержимое (листинг 1.4).
Листинг 1.4. Код «пустой» модели Bb
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Bb extends Model {
use HasFactory;
}

Всю функциональность модели, необходимую для работы с базой данных, реализует
базовый класс Illuminate\Database\Eloquent\Model. Трейт Illuminate\Database\
Eloquent\Factories\HasFactory используется лишь при автоматизированном тестировании (которое в этой книге не описывается), так что его можно удалить.
3. Сделаем поля title, content и price доступными для массового присваивания
(о нем — чуть позже), добавив в класс модели выделенный полужирным шрифтом
код, и заодно удалим трейт HasFactory:
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Bb extends Model {
use HasFactory;
protected $fillable = ['title', 'content', 'price'];
}

Массив с именами полей, доступных для массового присваивания, заносится в защищенное свойство fillable.

1.9. Консоль Laravel
Консоль Laravel позволяет работать с классами фреймворка в интерактивном режиме.
В частности, с ее помощью удобно заносить в информационную базу какие-либо отладочные данные.
1. В командной строке запустим консоль Laravel:
php artisan tinker

Приглашение к вводу команды обозначается префиксом >>>. Вывод результатов
производится без всякого префикса.
2. Проверим консоль в работе, выведя полное имя класса модели Bb, для чего наберем
следующие выражения, завершая каждое из них нажатием клавиши :
>>> use App\Models\Bb;
>>> echo Bb::class;
App\Models\Bb

40

Часть I. Основы Laravel на практическом примере

Следует помнить, что префиксом >>> обозначается приглашение к вводу команды.
Результат выполнения команды выводится без префикса.
Консоль Laravel позволяет набирать выражения в несколько строк, разрывая их нажатием клавиши .
3. Введем последнее из набранных выражений в две строки:
>>> use
... App\Models\Bb;

Префиксом ... (три точки) обозначается приглашение к вводу следующей строки
многострочного выражения.
4. Завершим работу консоли Laravel, нажав комбинацию клавиш + или
+.
Также можно набрать в консоли команду exit.

1.10. Работа с базой данных
Добавим несколько записей в таблицу объявлений bbs, исправим какую-либо запись,
удалим другую и попробуем выполнить выборку записей с фильтрацией и сортировкой. Затем переделаем действие index() контроллера HomeController таким образом,
чтобы оно выводило перечень объявлений из базы данных.
1. Запустим консоль Laravel (как это сделать, было рассказано в разд. 1.9).
2. Добавим первое объявление, набрав код:
>>> use App\Models\Bb;
>>> $bb = new Bb();
=> App\Models\Bb {#3530}
>>> $bb->title = 'Шкаф';
=> "Шкаф"
>>> $bb->content = 'Совсем новый, полированный, двухстворчатый';
=> "Совсем новый, полированный, двухстворчатый"
>>> $bb->price = 2000;
=> 2000
>>> $bb->save();
=> true

Если выполненное выражение возвращает какой-либо результат, но не предполагает
его явного вывода, результат все равно выводится в следующей строке, предваренный префиксом =>.
ВНИМАНИЕ!
Далее результаты, выводящиеся в консоли неявно и не нужные для понимания изложенного в книге материала, для краткости показываться не будут.

Объект модели представляет одну запись таблицы. Следовательно, для добавления
записи мы можем создать новый объект модели, занести в его свойства, представляющие отдельные поля, нужные значения и вызвать метод save(), выполняющий
сохранение записи. Что мы и сделали.

Глава 1. Простейший веб-сайт — доска объявлений

41

Метод save() вернет значение true (см. приведенный ранее код) — это значит, что
запись была успешно сохранена.
3. Удостоверимся, что объявление действительно сохранилось в таблице, для чего выведем его ключ, хранящийся в поле id:
>>> echo $bb->id;
1

Как видим, запись № 1 действительно сохранилась.
4. Добавим другое объявление — другим способом:
>>> $bb = $bb->create(['title' => 'Пылесос',
...
'content' => 'Старый, ржавый, без шланга', 'price' => 1000]);
=> App\Models\Bb {#4476
title: "Пылесос",
content: "Старый, ржавый, без шланга",
price: 1000,
updated_at: "2022-04-25 11:27:25",
created_at: "2022-04-25 11:27:25",
id: 2,
}

Отметим, что содержимое созданного этим способом объекта записи будет выведено непосредственно в консоли, и мы сразу сможем проверить правильность ввода
данных.
Метод create() создает новую запись, заносит в ее поля значения из указанного
ассоциативного массива, сохраняет запись и возвращает ее в качестве результата.
Он использует массовое присваивание, при котором значения заносятся сразу в несколько полей создаваемой записи. Отметим, что таким образом можно занести значения только в поля, приведенные в списке доступных для массового присваивания
(задается свойством fillable класса модели — см. разд. 1.8).
Любопытно, что метод create(), хотя и вызывается у модели, но выполняется построителем запросов — подсистемой, которая на основании заданных нами параметров (значений, заносимых в создаваемую запись, условий фильтрации выбираемых записей, их сортировки, набора выводимых полей и др.) формирует готовый
SQL-запрос, отправляет его СУБД, получает результат и представляет его в удобном
для обработки виде. При попытке вызвать метод построителя запросов у модели ее
объект создает новый объект построителя запросов и «передает» ему вызов метода.
5. Добавим еще два объявления:
>>> $bb = Bb::create(['title' => 'Грузовик',
...
'content' => 'Грузоподъемность - 5 т', 'price' => 10000000]);
>>> $bb = Bb::create(['title' => 'Снег', 'content' => 'Прошлогодний',
...
'price' => 50]);

Методы построителя запроса можно вызывать не только у объекта модели, но и у ее
класса — как статические.
6. Извлечем запись № 2:
>>> $bb = Bb::find(2);

42

Часть I. Основы Laravel на практическом примере

Метод find(), опять же выполняемый построителем запросов, ищет и возвращает
объект модели, хранящий запись с заданным ключом.
7. Посмотрим, что это за объявление:
>>> echo $bb->title, ' | ', $bb->content, ' | ', $bb->price;
Пылесос | Старый, ржавый, без шланга | 1000.0

Получить значения, хранящиеся в полях записи, можно, обратившись к одноименным свойствам модели.
Тысяча рублей за старый пылесос без шланга — не многовато ли?.. Уценим его.
8. Изменим цену товара (значение поля price):
>>> $bb->price = 500;
>>> $bb->save();

Мы занесли новое значение в нужное свойство модели и вызвали у объекта записи
метод save(), чтобы сохранить исправленную запись.
9. Извлечем все объявления, отсортированные по увеличению цены:
>>> $bbs = Bb::orderBy('price')->get();

Метод orderBy() построителя запросов сортирует записи по указанному полю.
В качестве результата он возвращает тот же объект построителя запросов, что позволяет записывать «цепочки» методов.
Мы так и сделали, «сцепив» с методом orderBy() метод get(), который отправит
базе данных готовый SQL-запрос и вернет результат его выполнения в виде коллекции объектов модели Bb, хранящих выбранные записи.
10. Просмотрим отсортированные объявления:
>>> foreach ($bbs as $bb) {
...
echo $bb->title, ' | ', $bb->content, ' | ', $bb->price, "\r\n";
... }
Снег | Прошлогодний | 50.0
Пылесос | Старый, ржавый, без шланга | 500.0
Шкаф | Совсем новый, полированный, двухстворчатый | 2000.0
Грузовик | Грузоподъемность - 5 т | 10000000.0

Коллекцию записей, возвращенную методом get(), как и любую другую, можно
перебрать в цикле.
11. Извлечем объявления с ценами более 1000 рублей и выведем их в обратном хронологическом порядке:
>>> $bbs = Bb::where('price', '>', 1000)->latest()->get();
>>> foreach ($bbs as $bb) {
...
echo $bb->title, ' | ', $bb->created_at, "\r\n";
... }
Грузовик | 2020-04-13 12:11:59
Шкаф | 2020-04-13 10:27:12

Метод where() построителя запросов фильтрует записи по значению поля, указанного в первом параметре. Второй параметр задает SQL-оператор сравнения, а третий — сравниваемое значение.

Глава 1. Простейший веб-сайт — доска объявлений

43

Метод latest() сортирует записи по убыванию отметок их создания (т. е. в обратном хронологическом порядке). Знакомый нам метод get() выполнит запрос и вернет результат.
12. Удалим объявление о продаже прошлогоднего снега (вряд ли на него будет спрос):
>>> $bb = Bb::where('title', 'Снег')->first();
>>> $bb->delete();

Ищем объявление вызовом метода where() (поскольку оператор сравнения в нем не
указан, будет использован оператор равенства =). Метод first() возвращает первую запись из полученного результата. А метод delete() модели удаляет текущую
запись.
13. Добавим еще несколько объявлений о продаже каких-либо товаров с произвольными содержанием и ценами.
14. Откроем модуль app\Http\Controllers\BbsController.php, хранящий код контроллера
BbsController, в текстовом редакторе и переделаем действие index(), чтобы оно
выводило перечень объявлений, взятых из базы данных, в обратном хронологическом порядке:
use App\Models\Bb;
class BbsController extends Controller {
public function index() {
$bbs = Bb::latest()->get();
$s = "Объявления\r\n\r\n";
foreach ($bbs as $bb) {
$s .= $bb->title . "\r\n";
$s .= $bb->price . " руб.\r\n";
$s .= "\r\n";
}
return response('Здесь будет перечень объявлений.'$s)
->header('Content-Type', 'text/plain');
}
}

Запустив отладочный веб-сервер и открыв сайт, мы увидим перечень, показанный на
рис. 1.3.
Теперь сделаем так, чтобы при переходе по пути формата // наш
сайт выводил объявление с записанным в пути ключом.

1.11. URL-параметры. Внедрение зависимостей
Теория
URL-параметр — значение, присутствующее в пути, который был получен в составе
клиентского запроса, и предназначенное для программной обработки. Обозначение
URL-параметра записывается в шаблонном пути под уникальным именем.
Значение, передаваемое в URL-параметре, впоследствии отправляется связанному
с маршрутом действию контроллера через параметр этого действия с именем, совпадающим с именем самого URL-параметра.

44

Часть I. Основы Laravel на практическом примере

Рис. 1.3. Перечень объявлений, извлеченный из базы данных

Например, чтобы извлечь из пути формата // записанный там ключ,
мы можем создать в шаблонном пути маршрута URL-параметр с именем bb. Чтобы отправить его действию, связанному с этим маршрутом, мы объявим в действии параметр
с тем же именем — bb.
Совпадение имен URL-параметра и параметра действия служит фреймворку своего
рода «подсказкой» занести в параметр действия значение одноименного URLпараметра. Такого рода автоматическое занесение в параметры методов требуемых
значений, основанное на совпадении имен и (или) типов этих параметров, называется
внедрением зависимостей.

Практика
Реализуем вывод отдельного объявления, выбранного посетителем сайта. Для этого
добавим в контроллер BbsController действие detail(), которое будет выполняться при
получении запроса, произведенного HTTP-методом GET по пути формата //. Для извлечения из пути ключа объявим в шаблонном пути URLпараметр bb.
1. Откроем модуль routes\web.php, хранящий список веб-маршрутов, и добавим в него
маршрут, связанный с действием detail() контроллера HomeController:
Route::get('/', [BbsController::class, 'index']);
Route::get('/{bb}', [BbsController::class, 'detail']);

Конечный слеш в шаблонных путях не ставится. Обозначения URL-параметров
берутся в фигурные скобки (например, {bb} — это URL-параметр с именем bb).

Глава 1. Простейший веб-сайт — доска объявлений

45

2. Откроем модуль app\Http\Controllers\BbsController.php, хранящий код контроллера
BbsController, в текстовом редакторе и добавим действие detail():
class BbsController extends Controller {
. . .
public function detail($bb) {
$bb = Bb::find($bb);
$s = $bb->title . "\r\n\r\n";
$s .= $bb->content . "\r\n";
$s .= $bb->price . " руб.\r\n";
return response($s)->header('Content-Type', 'text/plain');
}
}

В объявлении метода detail() мы указали параметр с именем bb. Laravel сразу «сообразит», что в него нужно поместить значение одноименного URL-параметра.
3. Запустим отладочный сервер и выполним переход на объявление № 1, набрав интернет-адрес http://localhost:8000/1/. Результат показан на рис. 1.4.

Рис. 1.4. Объявление № 1

Попробуем вывести объявления с номерами 2, 3 и т. д., но только не объявление № 4,
которое мы удалили (если попытаемся вывести его, получим страницу с сообщением об ошибке 404).
Теперь немного сократим код действия detail(), предписав фреймворку помещать
в параметр bb действия detail() не ключ выводимой записи, а сразу объект этой
записи.
4. Внесем в код действия detail() контроллера BbsController следующую правку:
public function detail(Bb $bb) {
$bb = Bb::find($bb);
$s = $bb->title . "\r\n\r\n";
. . .
}

Мы указали у параметра bb действия класс модели Bb в качестве типа — тогда
«сообразительный» Laravel сам найдет запись по полученному ключу и подставит
содержащий ее объект модели в этот параметр. Выражение, выполняющее поиск
записи, станет ненужным и может быть удалено.
Снова протестируем сайт и убедимся, что он работает.

46

Часть I. Основы Laravel на практическом примере

ПОЛЕЗНО ЗНАТЬ
Не все веб-фреймворки реализуют внедрение зависимостей. Например, популярнейший фреймворк Django, написанный на языке Python, такого не умеет.

Настала пора сделать так, чтобы наш сайт выдавал результаты не обычным текстом, а
в виде полноценных веб-страниц.

1.12. Шаблоны
Теория
Шаблон — это образец для генерирования веб-страницы, отправляемой клиенту в составе ответа. Процесс генерирования страницы называется рендерингом, а подсистема
фреймворка, выполняющая рендеринг, — шаблонизатором.
Для рендеринга шаблонизатору, помимо шаблона, нужны данные, которые будут выводиться на генерируемой странице (в нашем случае это, в зависимости от страницы, перечень объявлений или содержание выбранного объявления). Эти данные оформляются
в виде особого набора, называемого контекстом шаблона. Контекст шаблона формируется в виде ассоциативного массива, который преобразуется шаблонизатором в набор
обычных переменных, доступных внутри шаблона.
В Laravel шаблоны сохраняются в файлах с расширением blade.php и помещаются
в папке resources\views или вложенных в нее папках.

Практика
Реализуем вывод перечня объявлений и содержимого выбранного объявления в виде
обычных веб-страниц, для чего напишем шаблоны index.blade.php и detail.blade.php соответственно. Для оформления страниц применим популярный CSS-фреймворк Bootstrap
наиболее актуальной на момент подготовки книги версии 5.1 (https://getbootstrap.com/).
1. Откроем модуль app\Http\Controllers\BbsController.php, хранящий код контроллера
BbsController, и перепишем действие index() таким образом, чтобы оно формировало страницу на основе шаблона index.blade.php:
public function index() {
$context = ['bbs' => Bb::latest()->get()];
return view('index', $context);
}

Мы создаем контекст шаблона в виде ассоциативного массива и помещаем в него
один элемент bbs — список объявлений, извлеченный из базы. При рендеринге этот
элемент будет преобразован в переменную bbs, доступную внутри шаблона.
Функция-хелпер view() готовит шаблон к рендерингу (сам рендеринг выполняется
позже, непосредственно перед отправкой ответа клиенту). В первом параметре она
принимает имя шаблона без расширения blade.php, а во втором — контекст шаблона.
Возвращенный ею результат — подготовленный к рендерингу шаблон — следует
вернуть из действия в качестве результата.
Кстати, с функцией view() мы уже знакомы — видели ее в коде контроллерафункции, выводящей страницу, показанную на рис. 1.1 (см. листинг 1.2). Эта стра-

Глава 1. Простейший веб-сайт — доска объявлений

47

ница формируется шаблоном resources\views\welcome.blade.php, который теперь можно удалить, поскольку он больше не нужен.
2. Создадим шаблон resources\views\index.blade.php и запишем в него «заготовку» шаблона, создающего страницу с перечнем объявлений, из листинга 1.5.
Листинг 1.5. Код «заготовки» шаблона resources\views\index.blade.php





Объявления



Объявления



Товар
Цена, руб.
 







Подробнее...








Для вывода перечня объявлений применим обычную таблицу из трех столбцов: названия товара, его цены и гиперссылки Подробнее…, ведущей на страницу объявления. К тегам привяжем специфические стилевые классы Bootstrap, задающие
оформление для элементов страницы.
3. Перейдем на страницу https://getbootstrap.com/docs/5.1/getting-started/introduction/2,
найдем под заголовком Quick start | CSS HTML-код, привязывающий таблицу
2

На эту страницу также можно попасть, открыв «домашний» сайт Bootstrap (https://getbootstrap.com/),
перейдя в раздел Docs | Getting started | Introduction и выбрав в раскрывающемся списке в правом верхнем
углу страницы пункт Bootstrap v5.1.

48

Часть I. Основы Laravel на практическом примере

стилей Bootstrap (он содержит тег ), и вставим его в секцию заголовка шаблона:

. . .
Объявления



4. Найдем на той же странице под заголовком Quick start | JS | Bundle HTML-код,
привязывающий файл сценариев Bootstrap (тег ), и вставим его перед закрывающим тегом :


. . .




В секции основного содержания таблицы (теге ) присутствует «заготовка»
строки, в которой будет выводиться очередное объявление (формирующий ее тег
здесь подчеркнут):





Подробнее...




5. Добавим в шаблон код, который выведет строку-«заготовку» столько раз, сколько
объявлений имеется в списке (как мы помним, он хранится в переменной bbs, доступной в шаблоне):

@foreach ($bbs as $bb)

. . .

@endforeach


Шаблонизатор Laravel предоставляет набор своих собственных команд, аналогичных языковым конструкциям PHP и называемых директивами. Так, парная директива @foreach ... @endforeach аналогична циклу по массиву foreach, т. е. выводит
помещенный в ней код столько раз, сколько элементов присутствует в заданном
массиве или коллекции, и помещает очередной элемент в заданную переменную
(у нас — bb), доступную в «теле» цикла.

Глава 1. Простейший веб-сайт — доска объявлений

49

6. Добавим код, выводящий название товара, цену из очередного объявления и формирующий интернет-адрес гиперссылки Подробнее...:

@foreach ($bbs as $bb)

{{ $bb->title }}
{{ $bb->price }}

Подробнее...


@endforeach


Для вывода какого-либо значения следует поместить его между двойными фигурными скобками.
Осталось сделать так, чтобы, если в списке нет объявлений, таблица вообще не
выводилась на странице.
7. Добавим код, выводящий таблицу лишь в том случае, если список объявлений не
пуст:
@if (count($bbs) > 0)

. . .

@endif

Парная директива @if ... @endif шаблонизатора аналогична по назначению условному выражению PHP.
Страница перечня объявлений готова. Приступим к странице, выводящей содержание выбранного объявления.
8. Перепишем действие detail() контроллера BbsController таким образом, чтобы оно
выводило страницу, основанную на шаблоне detail.blade.php:
public function detail(Bb $bb) {
return view('detail', ['bb' => $bb]);
}

9. Пересохраним шаблон index.blade.php под именем detail.blade.php в той же папке
resources\views.
10. Запишем в шаблон detail.blade.php код, выводящий содержание выбранного объявления:



{{ $bb->title }} :: Объявления
. . .


50

Часть I. Основы Laravel на практическом примере


Объявления
{{ $bb->title }}
{{ $bb->content }}
{{ $bb->price }} руб.
На перечень объявлений





Рис. 1.5. Главная веб-страница с перечнем объявлений

Рис. 1.6. Веб-страница с содержанием выбранного объявления

Глава 1. Простейший веб-сайт — доска объявлений

51

Запустим отладочный сервер и откроем сайт. Посмотрим, правильно ли выводится
главная страница с перечнем объявлений (рис. 1.5). Щелкнем на любой из гиперссылок
Подробнее... и проверим, как отображается выбранное объявление (рис. 1.6).
Наши шаблоны содержат много одинакового кода — в частности, объемистые теги
и , привязывающие к страницам фреймворк Bootstrap. Мало того, что
это увеличивает размер шаблонов и затрудняет сопровождение, но и характеризует
плохой стиль программирования. Решим эту проблему.

1.13. Наследование шаблонов
Теория
Подобно классам PHP шаблоны Laravel могут наследовать друг от друга содержание
(наследование шаблонов Laravel).
В базовом шаблоне (от которого выполняется наследование) записывается код, общий
для всех страниц сайта: структурирующие теги, метаданные, привязки таблиц стилей и
веб-сценариев, теги, формирующие разметку, шапку, поддон, панель навигации и др.
Производные шаблоны (наследующие базовый шаблон), напротив, определяют содержание, уникальное для каждой конкретной страницы.
Фрагменты содержания в производных шаблонах оформляются в виде так называемых
секций, имеющий уникальные имена. В базовом шаблоне помечаются места, куда будет
помещено содержание той или иной секции, идентифицируемой по ее имени.
По принятому в Laravel соглашению базовые шаблоны хранятся в папке layouts, вложенной в папку resources\views.

Практика
Создадим базовый шаблон resources\views\layouts\app.blade.php3, в который вынесем все
повторяющиеся элементы из шаблонов index.blade.php и detail.blade.php. Оба этих шаблона сделаем производными от layouts\app.blade.php.
1. Создадим в папке resources\views папку layouts для хранения базового шаблона.
2. Откроем шаблон resources\views\index.blade.php (или detail.blade.php из той же папки)
в текстовом редакторе и пересохраним его под именем resources\views\layouts\
app.blade.php.
3. Исправим код базового шаблона resources\views\layouts\app.blade.php следующим
образом:


. . .
@yield('title') :: Объявления
. . .


3

Почему именно app.blade.php, а не, например, base.blade.php, мы узнаем в главе 2.

52

Часть I. Основы Laravel на практическом примере


Объявления
@yield('content')





Директива @yield шаблонизатора выводит на страницу содержание секции с именем,
указанным в скобках. В коде шаблона мы указали места для вывода секций title и
content4, которые позже создадим в производных шаблонах и в которых запишем
соответственно подзаголовок и основное содержание страницы.
4. Откроем шаблон resources\views\index.blade.php и превратим его в производный от
только что написанного базового шаблона, внеся следующие правки:
@extends('layouts.app')
@section('title', 'Главная')
@section('content')
@if (count($bbs) > 0)

. . .

@endif
@endsection('content')

Директива @extends указывает базовый шаблон, от которого наследует текущий.
Для разделения имен папок и файлов в путях к шаблонам используются не слеши, а
точки.
Директива @section создает секцию, чье имя указано в первом параметре. Она может
быть записана в двух форматах:
• как одинарная — тогда содержание секции задается вторым параметром;
• как парная (@section ... @endsection) — тогда содержание помещается в тело
директивы.
5. Внесем аналогичные правки в шаблон resources\views\detail.blade.php:
@extends('layouts.app')
@section('title', $bb->title)
@section('content')
{{ $bb->title }}
. . .
На перечень объявлений
@endsection('content')

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

Почему именно content, а не, скажем, main, также будет объяснено в главе 2.

Глава 1. Простейший веб-сайт — доска объявлений

53

Наш сайт имеет недостаток: интернет-адреса в гиперссылках генерируются непосредственно в программном коде. Например, интернет-адреса страниц объявлений формата
// генерируются так (выводящий их код подчеркнут):
Подробнее...

Если мы решим поменять формат этих адресов, скажем, на /detail//,
то будем вынуждены вносить правки во все шаблоны, в которых присутствуют гиперссылки с такими адресами. Решим и эту проблему.

1.14. Именованные маршруты
Именованный маршрут — маршрут, которому дано уникальное имя. Laravel может
генерировать интернет-адреса формата, задаваемого именованным маршрутом, для
чего достаточно задать имя маршрута и значения URL-параметров (если таковые имеются в шаблонном пути).
Дадим имена маршрутам:
 ведущему на главную страницу — имя index;
 ведущему на страницу объявления — имя detail.

И сделаем так, чтобы интернет-адреса гиперссылок генерировались на основании имен
маршрутов.
1. Откроем модуль routes\web.php, хранящий список веб-маршрутов, и укажем имена
у маршрутов, добавив следующий код:
Route::get('/', [BbsController::class, 'index'])->name('index');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');

Метод get() маршрутизатора в качестве результата возвращает объект, представляющий маршрут. Метод name(), вызванный у этого объекта, дает маршруту заданное в параметре имя.
2. Откроем модуль resources\views\index.blade.php, где хранится шаблон перечня объявлений, и исправим код, выводящий гиперссылки на страницы объявлений:

...


Функция-хелпер route() генерирует интернет-адрес на основе именованного маршрута, имя которого задано в первом параметре. Во втором параметре может быть
указан ассоциативный массив со значениями URL-параметров.
3. Откроем модуль resources\views\detail.blade.php с шаблоном выбранного объявления
и исправим код гиперссылки на перечень объявлений:
На перечень объявлений

Проверим сайт в работе. И напоследок немного разукрасим его.

54

Часть I. Основы Laravel на практическом примере

1.15. Статические файлы
Статическими называются файлы, пересылаемые клиенту как есть, без какой бы то ни
было обработки: внешние таблицы стилей, веб-сценарии, изображения, аудио- и видеоролики, документы, архивы и пр.
Статические файлы Laravel-сайта располагаются в папке public, фактически являющейся корневой папкой этого сайта, и во вложенных в нее папках.
Выведем в заголовке сайта, слева и справа, две копии небольшого графического изображения. Само изображение сохраним в файле public\images\logo.jpg, а таблицу стилей,
задающую оформление, — в файле public\styles\main.css.
1. Создадим в папке public папки images и styles.
2. Найдем в Интернете подходящее изображение и сохраним его под именем logo.jpg
в папке public\images.
Если найденное изображение записано в графическом формате, отличном от JPEG,
следует дать файлу соответствующее расширение.
3. Создадим в папке public\styles файл main.css и запишем в него код таблицы стилей из
листинга 1.6.
Листинг 1.6. Код таблицы стилей public\styles\main.css
h1 {
background: url("/images/logo.jpg") left / auto 100% no-repeat,
url("/images/logo.jpg") right / auto 100% no-repeat;
}

Если файл с изображением имеет расширение, отличное от jpg, CSS-код следует соответственно исправить.
Абсолютный интернет-адрес файла с изображением указывается относительно папки public.
4. Откроем модуль resources\views\layouts\app.blade.php, содержащий код базового шаблона, и вставим в секцию заголовка тег , привязывающий нашу таблицу стилей:

. . .




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

Рис. 1.7. Заголовок веб-сайта после применения стилей

ГЛАВА

2

Доска объявлений 2.0:
разграничение доступа, работа
с объявлениями и локализация
В этой главе мы свяжем каждое объявление с определенным зарегистрированным пользователем, добавим инструменты для создания, правки и удаления объявлений, регистрации пользователей, защитим сайт от несанкционированного доступа и полностью
переведем его на русский язык.

2.1. Межтабличные связи.
Работа со связанными записями
Создание связи между таблицами выполняется в три этапа:
 формирование поля, хранящего ключ связанной записи первичной таблицы (поля

внешнего ключа), — во вторичной таблице;

 объявление «прямой» связи (между первичной и вторичной моделями) — в модели

первичной таблицы;
 объявление «обратной» связи (между вторичной и первичной моделями) — в моде-

ли вторичной таблицы.
Свяжем каждое объявление с определенным пользователем-автором, для чего установим связь «один-со-многими» между таблицами: users (она станет первичной) и bbs
(а она — вторичной). Далее добавим в список нового пользователя, создадим разными
способами три связанных с ним объявления и реализуем вывод на странице объявления
имени его автора.
Чтобы избежать проблем с заполнением поля вторичного ключа в таблице bbs, не
будем вносить правки в уже имеющуюся таблицу, а удалим ее и создадим заново. Для
удаления таблицы bbs достаточно откатить последнюю миграцию.
1. В командной строке выполним откат последней миграции:
php artisan migrate:rollback --step=1

Количество откатываемых миграций указывается в параметре --step команды
migrate:rollback.

56

Часть I. Основы Laravel на практическом примере

2. Откроем в текстовом редакторе модуль database\migrations\_create_bbs_table.php с нашей миграцией и добавим код, создающий поле
внешнего ключа:
public function up() {
Schema::create('bbs', function (Blueprint $table) {
. . .
$table->float('price');
$table->foreignId('user_id')->constrained()
->onDelete('cascade');
$table->timestamps();
. . .
});
}

Метод foreignId() объекта структуры таблицы создает поле внешнего ключа и возвращает представляющий его объект. Мы дали этому полю «говорящее» имя user_id
и поэтому для создания собственно связи можем вызвать у возвращенного объекта
связи метод constrained(), который извлечет из имени все необходимые ему сведения: имя связываемой первичной таблицы (users) и ее ключевое поле (id). Метод
onDelete() укажет операцию, выполняемую над связанными записями вторичной
таблицы при удалении записи первичной таблицы (у нас — cascade, т. е. каскадное
удаление).
3. В командной строке применим исправленную миграцию:
php artisan migrate

Исправленная таблица объявлений готова. Займемся моделями пользователей и объявлений.
4. Откроем в текстовом редакторе модуль app\Models\User.php с классом модели пользователя User и добавим код, объявляющий «прямую» связь между текущей, первичной, и заданной вторичной моделями:
use App\Models\Bb;
class User extends Authenticatable {
. . .
public function bbs() {
return $this->hasMany(Bb::class);
}
}

«Прямая» связь объявляется в виде обычного общедоступного метода (у нас —
bbs()). В нем вызывается метод hasMany() модели, принимающий имя класса связываемой вторичной модели и возвращающий объект созданной связи. Последний
следует вернуть из метода, объявляющего связь.
5. Откроем в текстовом редакторе модуль app\Models\Bb.php с классом модели объявления Bb и добавим код, объявляющий «обратную» связь между текущей, вторичной, и заданной первичной моделями:
use App\Models\User;
class Bb extends Model {
. . .

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

57

public function user() {
return $this->belongsTo(User::class);
}
}

«Обратная» связь также объявляется в виде общедоступного метода (у нас —
user()). Метод belongsTo() класса модели принимает имя класса связываемой первичной модели и возвращает объект созданной связи, который следует вернуть из
метода, объявляющего связь.
6. Запустим консоль Laravel (см. разд. 1.9) и добавим нового пользователя с именем
admin, адресом электронной почты admin@bboard.ru (адрес можно указать произвольный, поскольку Laravel по умолчанию не проверяет его существование) и паролем admin (задается в виде хеша, вычисленного вызовом метода make() у подсистемы
хеширования, представляемой фасадом Hash):
>>> use Illuminate\Support\Facades\Hash;
>>> use App\Models\User;
>>> $user = User::create(['name' => 'admin',
...
'email' => 'admin@bboard.ru',
...
'password' => Hash::make('admin')]);

7. Добавим объявление от имени этого пользователя:
>>>
>>>
>>>
>>>
>>>
>>>

use App\Models\Bb;
$bb = new Bb();
$bb->title = 'Пылесос';
$bb->content = 'Старый, ржавый, без шланга';
$bb->price = 500;
$user->bbs()->save($bb);

Метод первичной модели, объявляющий «прямую» связь (у нас — bbs()), возвращает объект «прямой» связи. Последний поддерживает метод save(), связывающий
переданную в параметре запись вторичной модели с текущей записью первичной
модели и одновременно сохраняющий переданную запись.
8. Создадим еще одно объявление другим способом:
>>> $user->bbs()->create(['title' => 'Грузовик',
...
'content' => 'Грузоподъемность - 5 т',
...
'price' => 10000000]);

А еще объект «прямой» связи поддерживает метод create(), знакомый нам по
разд. 1.10.
9. Добавим третье объявление — третьим способом:
>>> $bb = new Bb(['title' => 'Шкаф',
...
'content' => 'Совсем новый, полированный, двухстворчатый',
...
'price' => 1000]);
>>> $bb->user()->associate($user);
>>> $bb->save();

Конструктору модели можно передать ассоциативный массив со значениями полей
(как и методу create()).

58

Часть I. Основы Laravel на практическом примере

Метод вторичной модели, объявляющий «обратную» связь (у нас — user()), возвращает объект «обратной» связи. Последний поддерживает метод associate(),
связывающий переданную в параметре запись первичной модели с текущей
записью вторичной модели. Однако этот метод не сохраняет текущую запись,
и нам придется сделать это самостоятельно, вызвав метод save().
10. Переберем все объявления и для каждого выведем название товара, имя пользователя-автора и цену:
>>> foreach (Bb::all() as $bb) {
...
$user = $bb->user;
...
echo $bb->title, ' | ', $user->name, ' | ', $bb->price, "\r\n";
... }
Пылесос | admin | 500.0
Грузовик | admin | 10000000.0
Шкаф | admin | 1000.0

Метод all(), вызываемый у модели (но выполняемый построителем запросов), возвращает все записи таблицы.Свойство user объявления (одноименное с ранее объявленным в модели Bb методом) хранит связанного с объявлением пользователя.
11. Переберем все объявления, оставленные пользователем admin, и выведем названия
хранящихся в них товаров:
>>> $user = User::where('name' ,'admin')->first();
>>> foreach ($user->bbs as $bb) { echo $bb->title, ' '; }
Пылесос Грузовик Шкаф

Свойство bbs пользователя (одноименное с ранее объявленным в модели User методом) хранит список связанных объявлений.
12. Откроем модуль resources\views\detail.blade.php, хранящий код шаблона объявления,
и добавим вывод имени пользователя, оставившего объявление:
{{ $bb->price }} руб.
Автор: {{ $bb->user->name }}
На перечень объявлений

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

2.2. Вход и выход. Раздел пользователя
Теория
К работе с внутренними данными сайта (в нашем случае — со списком объявлений)
следует допускать только посетителей, указанных в особом списке, — зарегистрированных пользователей, или просто пользователей.
Список пользователей практически всегда хранится в одной из таблиц базы данных.
Каждая позиция списка содержит внутреннее имя пользователя («логин»), адрес его
электронной почты, пароль (в закодированном виде) и, возможно, дополнительные

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

59

сведения: настоящие имя и фамилию пользователя, наименования операций, которые
пользователь может выполнять с данными (привилегии, или права), и др.
Посетитель, желающий получить доступ к данным сайта, должен выполнить процедуру
входа на сайт (или аутентификации). Для этого он переходит на веб-страницу входа и
вводит в веб-форму свои адрес электронной почты и пароль. Laravel находит в списке
пользователя с заданными адресом и паролем и помечает его как выполнившего
вход — текущего пользователя (записывая в серверную сессию особый признак).
При попытке перейти на какую-либо страницу Laravel проверяет, кому должна быть
доступна эта страница: всем, только зарегистрированным пользователям, выполнившим вход, только зарегистрированным пользователям с особыми привилегиями или
только посетителям, не выполнившим вход (гостям). Если целевая страница не должна
быть доступна текущему пользователю, выполняется перенаправление на страницу
входа (если вход на сайт не был выполнен) или выдается сообщение об ошибке 403
(пользователь не имеет необходимых прав) — если вход на сайт был выполнен. Такого
рода проверки называются разграничением доступа (или авторизацией).
Раздел пользователя — это страница, выводящая какие-либо данные, которые принадлежат текущему пользователю (например, перечень принадлежащих ему объявлений).
Обычно именно в этот раздел производится перенаправление после успешного входа на
сайт.
Закончив работу, пользователь выполняет выход с сайта. При этом фреймворк «забывает», что пользователь ранее выполнил вход, и начинает считать его гостем.
Библиотека laravel/ui, установленная в разд. 1.2, позволяет сформировать в разрабатываемом сайте базовые средства для разграничения доступа: контроллеры, реализующие
вход, раздел пользователя и выход, а также необходимые маршруты и шаблоны страниц.
Любой Laravel-проект изначально содержит миграцию, создающую таблицу users, которая хранит список зарегистрированных пользователей. Соответственно, эта таблица
создается при первом выполнении миграций (см. разд. 1.7) — нам самим формировать
ее не придется.

Практика
Создадим «костяк» подсистемы разграничения доступа и раздел пользователя, выводящий объявления, чьим автором является текущий пользователь.
1. В командной строке создадим базовые средства разграничения доступа:
php artisan ui:auth

В консоли появится сообщение:
The [layouts/app.blade.php] view already exists. Do you want to
replace it? (yes/no) [no]:

Перевод:
Шаблон layouts\abb.blade.php уже существует. Вы хотите перезаписать
его? (да/нет) [Нет]:

Нам не нужно, чтобы наш базовый шаблон был перезаписан.

60

Часть I. Основы Laravel на практическом примере

2. Чтобы отменить перезапись базового шаблона — введем строку no, букву n или просто нажмем клавишу .
После выполнения команды ui:auth будут созданы, в частности, следующие модули:
• контроллеры

(имена

классов

указаны

относительно

пространства

имен

App\Http\Controllers):

 HomeController — выводит раздел пользователя;
 Auth\RegisterController — регистрирует нового пользователя;
 Auth\LoginController — выполняет вход на сайт и выход с него;
• шаблоны (пути указаны относительно папки resources\views):
 home.blade.php — шаблон страницы с разделом пользователя;
 auth\register.blade.php — шаблон страницы регистрации нового пользователя;
 auth\login.blade.php — шаблон страницы входа.
Также будут созданы еще несколько контроллеров (и соответствующих им шаблонов), выполняющих проверку, сброс пароля и активацию нового пользователя по
электронной почте. Мы рассмотрим их в главе 13.
В список веб-маршрутов будут добавлены маршруты, ведущие на действия вновь
созданных контроллеров.
3. Откроем модуль routes\web.php со списком веб-маршрутов и посмотрим, какие
выражения были добавлены в него (здесь они подчеркнуты):
Route::get('/', [BbsController::class, 'index'])->name('index');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])
->name('home');

Метод routes() фасада Auth (за ним «прячется» подсистема безопасности) создает
маршруты на действия контроллеров, созданных командой ui:auth утилиты artisan.
Из второго добавленного выражения видно, что раздел пользователя выводится действием index() контроллера HomeController при запросе по пути /home/ методом
GET, а соответствующий маршрут имеет имя home — запомним его.
4. В командной строке выведем список маршрутов, созданных методом routes() фасада Auth:
php artisan route:list

Из всех представленных в выведенном списке маршрутов нас интересуют лишь следующие (приведены в формате: «допустимый HTTP-метод — действие — описание»):
• GET — register — вывод страницы регистрации;
• GET — login — вывод страницы входа;
• POST — logout — выполнение выхода.

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

61

Полученных сведений достаточно для создания гиперссылок. Затруднения возникнут лишь с маршрутом logout, поскольку в нем указан допустимый метод POST. Но
мы избежим их, создав веб-форму с кнопкой, отправляющую данные по этому маршруту методом POST.
5. Откроем модуль resources\views\layouts\app.blade.php с базовым шаблоном и добавим
в него горизонтальную панель навигации:



Главная
Регистрация
Вход
Мои объявления

@csrf




Объявления
@yield('content')


Директива @csrf шаблонизатора вставляет в форму скрытое поле с электронным
маркером безопасности (подробности — в главе 11). Если мы не вставим этот маркер, то получим сообщение об ошибке 419 (страница устарела).
В разд. 1.13, создавая базовый шаблон, мы дали ему имя layouts\app.blade.php, а для
размещения основного содержания предусмотрели в шаблоне секцию с именем
content. Сделано это было не просто так. Базовый шаблон, создаваемый командой
ui:auth, также имеет имя layouts\app.blade.php, а основное содержание в нем также
размещается в секции content. Так что нам придется внести в производные шаблоны
совсем небольшие правки.
6. Откроем модуль resources\views\auth\login.blade.php, хранящий шаблон страницы входа, и внесем следующую правку:
@extends('layouts.app')
@section('title', 'Вход')
. . .

Мы лишь добавили секцию title с названием подраздела сайта.
7. Откроем модуль resources\views\auth\register.blade.php, хранящий шаблон страницы
регистрации, и внесем аналогичную правку.

62

Часть I. Основы Laravel на практическом примере

Займемся разделом пользователя, который будет выводить перечень объявлений,
оставленных текущим пользователем, в обратном хронологическом порядке.
8. Откроем

модуль

app\Http\Controllers\HomeController.php

HomeController и внесем

с

кодом

контроллера

следующие правки:

use Illuminate\Support\Facades\Auth;
class HomeController extends Controller {
. . .
public function index() {
return view('home',
['bbs' => Auth::user()->bbs()->latest()->get()]);
}
}

Метод user() фасада Auth возвращает объект модели User, представляющий текущего пользователя. Вызвав у пользователя метод bbs(), получим объект «прямой» связи. Этот объект имеет функциональность построителя запросов, поддерживает все
его методы (latest(), where(), get() и др., подробности — в разд. 1.10) и настроен на
обработку только связанных записей.
9. Откроем модуль resources\views\home.blade.php, где записан шаблон страницы с разделом пользователя, удалим весь имеющийся там код и запишем в него код, показанный в листинге 2.1.
Листинг 2.1. Код шаблона resources\views\home.blade.php
@extends('layouts.app')
@section('title', 'Мои объявления')
@section('content')
Добавить объявление
@if (count($bbs) > 0)



Товар
Цена, руб.
 



@foreach ($bbs as $bb)

{{ $bb->title }}
{{ $bb->price }}

Изменить


Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

63


Удалить


@endforeach


@endif
@endsection('content')

Мы сразу создали гиперссылки для добавления, правки и удаления объявлений.
Соответствующие интернет-адреса занесем в них позже.
10. Запустим отладочный сервер, откроем сайт и попытаемся перейти на страницу входа, щелкнув на гиперссылке Вход.
Результатом станет стандартная страница с сообщением об ошибке 404, выводимая
Laravel. Мы где-то допустили ошибку...
Вернемся к списку маршрутов:
Route::get('/', [BbsController::class, 'index'])->name('index');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class,
'index'])
->name('home');

Маршрутизатор Laravel при просмотре списка маршрутов выбирает самый первый
маршрут, имеющий совпадающие шаблонный путь и допустимый HTTP-метод.
Остальные маршруты при этом не просматриваются.
У нас страница входа располагается по пути /login/. Просматривая список маршрутов, маршрутизатор обнаружит, что этот путь совпадает с шаблонным путем из
второго по счету маршрута, ведущего на действие detail() контроллера
BbsController (оно выводит страницу объявления). Попытка извлечь объявление
с ключом login увенчается неудачей и генерированием исключения, выводящего
сообщение об ошибке 404.
Чтобы устранить проблему, достаточно передвинуть маршрут, ведущий на действие detail() контроллера BbsController, в самый конец списка.
11. Откроем модуль routes\web.php со списком веб-маршрутов и внесем в него нужные
правки:
Route::get('/', [BbsController::class, 'index'])->name('index');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class,
'index'])
->name('home');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');

Теперь все будет работать. Откроем сайт, перейдем на страницу входа (рис. 2.1), укажем адрес электронной почты admin@bboard.ru, пароль admin и нажмем кнопку

64

Часть I. Основы Laravel на практическом примере

Login. Если мы не допустили ошибок при вводе, окажемся на странице раздела пользователя (рис. 2.2). Напоследок выйдем с сайта, нажав кнопку Выход.
ПОЛЕЗНО ЗНАТЬ
По умолчанию Laravel идентифицирует пользователя по адресу его электронной почты. Подавляющее большинство других фреймворков используют для этого регистрационное имя пользователя («логин»).

Рис. 2.1. Веб-страница входа

Рис. 2.2. Веб-страница раздела пользователя

Пока еще все надписи на страницах регистрации и входа выводятся по-английски.
В конце этой главы мы выполним их локализацию на русский язык.

2.3. Добавление, правка и удаление записей
Наделим наш сайт средствами для добавления новых объявлений. Автором добавляемых объявлений станет текущий пользователь. Позже реализуем правку и удаление
объявлений. Всю необходимую логику запишем в контроллер HomeController.

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

65

1. Откроем список веб-маршрутов routes\web.php и добавим два маршрута, необходимых для реализации добавления объявлений:
use App\Http\Controllers\HomeController;
. . .
Route::get('/home', [HomeController::class, 'index'])->name('home');
Route::get('/home/create', [HomeController::class, 'create'])
->name('bb.create');
Route::post('/home', [HomeController::class, 'store'])
->name('bb.store');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');

Первый из добавленных маршрутов (с шаблонным путем /home/create/ и допустимым методом GET) связан с действием create() контроллера HomeController и выведет страницу с веб-формой для занесения нового объявления. Второй маршрут
(шаблонный путь — /home/, допустимый HTTP-метод — POST, создан вызовом метода post()) связан с действием store() того же контроллера, добавляющим введенное объявление в базу.
2. Откроем контроллер app\Http\Controllers\HomeController.php и добавим в него действие
create(), выводящее страницу добавления объявления:
class HomeController extends Controller {
. . .
public function create() {
return view('bb-create');
}
}

Шаблон bb-create.blade.php, формирующий страницу для ввода объявления, мы создадим позже. На этой странице предусмотрим поле ввода с наименованием title,
область редактирования content и поле ввода price.
3. Добавим в контроллер HomeController действие store(), сохраняющее новое объявление и выполняющее перенаправление на раздел пользователя:
class HomeController extends Controller {
. . .
public function store(Request $request) {
Auth::user()->bbs()->create(['title' => $request->title,
'content' => $request->content,
'price' => $request->price]);
return redirect()->route('home');
}
}

Мы задали у действия store() параметр типа Request, тем самым «намекнув» подсистеме внедрения зависимостей Laravel, что хотим получить в этом параметре объект класса Request, представляющий запрос. Из его свойств, чьи имена совпадают
с наименованиями элементов управления, извлекаем занесенные в веб-форму значения для сохранения в записи.
Далее, вызвав функцию-хелпер redirect(), получаем «пустой» объект перенаправления и, вызвав у этого объекта метод route(), заносим в него целевой интернет-

66

Часть I. Основы Laravel на практическом примере

адрес, сгенерированный на основе именованного маршрута home. И не забываем вернуть из действия готовый объект перенаправления.
4. Создадим модуль resources\views\bb-create.blade.php и запишем в него код шаблона
страницы для ввода нового объявления из листинга 2.2.
Листинг 2.2. Код шаблона resources\views\bb-create.blade.php
@extends('layouts.app')
@section('title', 'Добавление объявления :: Мои объявления')
@section('content')

@csrf

Товар



Описание



Цена




@endsection('content')

Не забываем поместить в форму электронный маркер безопасности, воспользовавшись директивой @csrf.
5. Откроем шаблон раздела пользователя resources\views\home.blade.php и запишем
интернет-адрес в гиперссылку Добавить объявление:
Добавить
объявление

6. Запустим отладочный сервер, выполним вход на сайт от имени пользователя
admin@bboard.ru, перейдем на страницу добавления объявления (рис. 2.3) и создадим объявление с произвольным содержанием. Затем выйдем с сайта, перейдем на
страницу регистрации и создадим еще одного пользователя с именем editor, адресом editor@bboard.ru и паролем supereditor. После создания пользователя Laravel
автоматически выполнит вход на сайт от его имени. Добавим еще пару произвольных объявлений от имени нового пользователя и выйдем с сайта.
Наконец, дадим пользователям возможность править и удалять объявления.
7. Откроем список веб-маршрутов routes\web.php и добавим еще четыре маршрута:

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

67

Route::post('/home', [HomeController::class, 'store'])
->name('bb.store');
Route::get('/home/{bb}/edit', [HomeController::class, 'edit'])
->name('bb.edit');
Route::patch('/home/{bb}', [HomeController::class, 'update'])
->name('bb.update');
Route::get('/home/{bb}/delete', [HomeController::class, 'delete'])
->name('bb.delete');
Route::delete('/home/{bb}', [HomeController::class, 'destroy'])
->name('bb.destroy');
Route::get('/{bb}', [BbsController::class, 'detail'])->name('detail');

Первый добавленный маршрут выведет страницу с веб-формой для правки объявления, второй — сохранит исправленное объявление, третий — выведет страницу удаления объявления, четвертый — удалит объявление. У второго маршрута в качестве
допустимого HTTP-метода указан PATCH (вызовом метода patch() у фасада Route),
а у четвертого — DELETE (вызовом метода delete()).

Рис. 2.3. Веб-страница добавления объявления

8. Откроем контроллер app\Http\Controllers\HomeController.php и добавим в него действия: edit() (вывод страницы правки объявления) и update() (сохранение исправленного объявления):
use App\Models\Bb;
class HomeController extends Controller {
. . .
public function edit(Bb $bb) {
return view('bb-edit', ['bb' => $bb]);
}

68

Часть I. Основы Laravel на практическом примере
public function update(Request $request, Bb $bb) {
$bb->fill(['title' => $request->title,
'content' => $request->content,
'price' => $request->price]);
$bb->save();
return redirect()->route('home');
}
}

В действии edit() не забываем занести в контекст шаблона выбранную запись —
чтобы подставить значения ее полей в поля ввода веб-формы.
В действии update() мы указали два параметра: типа Request — для объекта запроса, и типа Bb — для объекта модели, представляющего выбранное объявление. Подсистема внедрения зависимостей Laravel сама занесет в них требуемые значения.
Для массового присваивания исправленных значений полям объявления применяем
метод fill() объекта модели. Сохраняем запись вызовом метода save().
9. Добавим в контроллер HomeController действия: delete() (вывод страницы удаления объявления) и destroy() (собственно удаление):
class HomeController extends Controller {
. . .
public function delete(Bb $bb) {
return view('bb-delete', ['bb' => $bb]);
}
public function destroy(Bb $bb) {
$bb->delete();
return redirect()->route('home');
}
}

В действии delete() заносим в контекст шаблона выбранную запись — чтобы вывести ее на странице.
10. Пересохраним модуль resources\views\bb-create.blade.php под именем bb-edit.blade.php,
тем самым создав шаблон страницы для правки объявления, и исправим его код:
@section('title', 'Правка объявления :: Мои объявления')
@section('content')

@csrf
@method('PATCH')

. . .



. . .

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

69

{{ $bb->content }}


. . .




@endsection('content')

В маршруте, сохраняющем исправленное объявление, мы указали допустимый
HTTP-метод PATCH. Проблема в том, что он не поддерживается веб-обозревателями, — мы не можем записать его в атрибуте method тега . Однако
можно поместить в форму скрытое поле с наименованием нужного HTTP-метода.
Это выполняется директивой @method шаблонизатора.
В поля ввода и область редактирования следует подставить значения полей исправляемой записи.
11. Пересохраним модуль resources\views\detail.blade.php под именем bb-delete.blade.php,
создав шаблон страницы для удаления объявления, и исправим его код:
@section('title', 'Удаление объявления :: Мои объявления')
@section('content')
. . .
Автор: {{ $bb->user->name }}

@csrf
@method('DELETE')


@endsection('content')

Чтобы отправить запрос на удаление объявления HTTP-методом DELETE (который
также не поддерживается веб-обозревателями), мы создали на странице веб-форму
с кнопкой отправки данных и с помощью директивы @method поместили в форму
скрытое поле с наименованием нужного HTTP-метода.
12. Откроем шаблон раздела пользователя resources\views\home.blade.php и вставим
интернет-адреса в гиперссылки Изменить и Удалить:
Изменить
. . .
Удалить

Войдем на сайт от имени любого из зарегистрированных пользователей и попробуем
исправить какое-либо объявление. Добавим произвольное объявление и попытаемся
удалить его.
На этом этапе сайт еще не проверяет корректность заносимых данных. Например, если
в поле ввода Цена вместо числа ввести строку, она будет успешно сохранена в базе
(формат базы данных SQLite позволяет хранить в поле значения любого типа, даже не

70

Часть I. Основы Laravel на практическом примере

совпадающего с типом, указанным при объявлении поля). А если вообще не заносить
значение в какое-либо поле, мы получим страницу с системным сообщением об ошибке, которое ничего не скажет конечному пользователю сайта (зато многое скажет потенциальному взломщику).
Поэтому самое время заняться валидацией.

2.4. Валидация данных
Валидация — это проверка данных на корректность на основе заданных правил.
Реализуем валидацию добавляемых и исправляемых объявлений согласно следующим
правилам:
 поле title — обязательно к заполнению, максимальная длина значения 50 симво-

лов;
 поле content — обязательно к заполнению;
 поле price — обязательно к заполнению, значение должно быть числом.

1. Откроем модуль app\Http\Controllers\HomeController.php и объявим в классе контроллера HomeController константу BB_VALIDATOR с перечнем правил валидации:
class HomeController extends Controller {
private const BB_VALIDATOR = [
'title' => 'required|max:50',
'content' => 'required',
'price' => 'required|numeric'
];
. . .
}

Набор правил валидации записывается в виде ассоциативного массива, каждый элемент которого задает набор правил для отдельного элемента управления. Отдельные
правила в наборе разделяются символом вертикальной черты. У поля ввода title мы
указали правила required (обязательно к заполнению) и max:50 (длина значения —
не более 50 символов), у области редактирования content — required, у поля ввода
price — required и numeric (значение должно представлять собой число).
2. Добавим в действия store() и update() того же контроллера код, выполняющий
валидацию согласно записанным ранее правилам:
public function store(Request $request) {
$validated = $request->validate(self::BB_VALIDATOR);
Auth::user()->bbs()->create(['title' => $validated['title'],
'content' => $validated['content'],
'price' => $validated['price']]);
return redirect()->route('home');
}
. . .
public function update(Request $request, Bb $bb) {
$validated = $request->validate(self::BB_VALIDATOR);

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

71

$bb->fill(['title' => $validated['title'],
'content' => $validated['content'],
'price' => $validated['price']]);
$bb->save();
. . .
}

Валидация запускается вызовом метода validate() объекта запроса, в котором и содержатся подлежащие валидации данные из веб-формы. В качестве параметра этому
методу передаются перечень правил валидации.
Если валидация прошла успешно, метод validate() вернет ассоциативный массив
с данными из веб-формы, очищенными от лишних символов (начальных и конечных
пробелов, букв, поставленных после цифр в числах, и др.). Данные из этого массива
мы и сохраняем в базе.
Если валидация не увенчалась успехом, Laravel сохранит в серверной сессии все
данные из веб-формы и все сообщения об ошибках ввода, после чего выполнит
перенаправление на предыдущую страницу — ту самую, на которой находится вебформа. В результате посетитель сможет исправить некорректные данные.
Теперь нужно сделать так, чтобы на страницах с веб-формами добавления и правки
объявления выводились сообщения об ошибках ввода и ранее введенные данные.
3. Откроем шаблон страницы правки объявления resources\views\bb-edit.blade.php и добавим код, выводящий сообщения об ошибках ввода в поле title:

. . .

@error('title')
{{ $message }}
@enderror


Парная директива @error ... @enderror шаблонизатора выводит находящийся в ее
теле фрагмент содержания только в том случае, если в серверной сессии хранится
сообщение об ошибке ввода в элемент управления с указанным именем. Внутри
тела директивы можно использовать переменную message, хранящую сообщение об
ошибке в виде текста.
Мы используем эту директиву, чтобы, во-первых, вывести сообщение об ошибке
под полем ввода и, во-вторых, привязать к полю ввода стилевой класс is-invalid
фреймворка Bootstrap, помечающий элемент управления как содержащий некорректное значение.
4. Добавим туда же код, помещающий в поле ввода ранее занесенное туда значение:


Функция-хелпер old() извлекает из серверной сессии значение, занесенное в элемент управления, чье наименование указано в первом параметре.

72

Часть I. Основы Laravel на практическом примере

При первом выводе страницы на экран значение title в сессии отсутствует, и функция old() вернет значение из второго параметра — изначальное название товара,
полученное контроллером из базы данных. Если валидация не увенчалась успехом,
страница будет выведена повторно, в этом случае в сессии будет храниться ранее
введенное значение title, которое и занесется в поле ввода.
5. Внесем аналогичные исправления в код, создающий элементы управления content
и price.
6. Откроем шаблон страницы добавления объявления resources\views\bb-create.blade.php
и добавим аналогичный код, выводящий сообщения об ошибках ввода.
7. Добавим в тот же шаблон код, помещающий в элементы управления ранее занесенные туда значения (показаны исправления в коде поля ввода title — у остальных
элементов правки будут аналогичными):


Указывать второй параметр у функции old() здесь не нужно — тогда в случае отсутствия в серверной сессии заданного значения функция вернет null, и поле ввода
будет выведено пустым.
Войдем на сайт от имени любого пользователя, перейдем на страницу добавления объявления, введем все сведения об объявлении, кроме какого-либо одного (например, названия товара), нажмем кнопку Добавить и проверим, выводится ли сообщение об
ошибке и заполняются ли остальные элементы управления ранее занесенными туда
данными. После этого попробуем ввести название товара длиной более 50 символов и
нечисловое значение в качестве цены и посмотрим, что получится.
Пока еще сообщения об ошибках выводятся по-английски. Но мы это обязательно исправим.
По идее, пользователь должен иметь возможность править и удалять лишь «свои» объявления. Однако если мы выполним переход по интернет-адресу формата /home//edit|delete/, то сможем исправить или удалить объявление с произвольным ключом вне зависимости от того, какой пользователь является его автором. Это
серьезная брешь в безопасности, и ее следует «заткнуть».

2.5. Разграничение доступа.
Посредники, политики и провайдеры
Теория
Разграничение доступа к данным сайта, написанного с применением Laravel, реализуется посредниками и политиками.
 Посредник (middleware) — программный модуль, выполняющий предварительную

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

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

73

и, если это не так, выполняет перенаправление на страницу входа. А посредник
guest, напротив, проверяет, отправлен ли запрос гостем, в противном случае производя перенаправление на раздел пользователя.
Большинство доступных посредников принадлежат самому фреймворку, но часть
непосредственно входит в состав сайта. Они генерируются утилитой artisan при создании проекта и хранятся в папке app\Middleware, так что программист при необходимости вмешаться в обработку запросов и ответов может внести в их код нужные
правки.
 Политика (policy) — программный модуль, реализующий разграничение доступа

к определенной модели согласно заданным правилам.
В частности, политика может проверять, является ли текущий пользователь автором
извлеченного из базы объявления. Если же это не так, будет выведена страница
с сообщением об ошибке 403.
Все политики, входящие в состав сайта, хранятся в папке app\Policies (изначально
отсутствующей) и регистрируются в провайдере AuthServiceProvider.
 Провайдер (provider) — программный модуль, задающий режим работы и некото-

рые параметры какой-либо из подсистем фреймворка.
Например, упоминавшийся ранее провайдер AuthServiceProvider инициализирует
подсистему разграничения доступа и передает ей нужные для работы сведения —
в частности, перечень политик.
Бо́льшая часть доступных провайдеров принадлежит самому Laravel. Остальные,
в том числе и AuthServiceProvider, входят в состав самого сайта, хранятся в папке
app\Providers и могут быть исправлены программистом, если он захочет изменить
режим работы какой-либо подсистемы фреймворка.
Посредники, политики и провайдеры реализуются в виде классов.

Практика
Сначала удостоверимся, что раздел пользователя, страницы добавления, правки и удаления объявления защищены посредником auth, «пускающим» к страницам только
пользователей, выполнивших вход. После чего создадим политику BbPolicy, которая
позволит править и удалять объявления только их автору.
1. Откроем контроллер app\Http\Controllers\HomeController.php и посмотрим на его конструктор:
public function __construct() {
$this->middleware('auth');
}

Метод middleware() указывает «пропустить» все запросы, приходящие на действия
текущего контроллера, через указанный посредник. Отметим, что вызов этого метода в конструктор класса вставила сама утилита artisan при создании базовых средств
разграничения доступа (см. разд. 2.2).
Как видим, все действия контроллера уже защищены от гостей посредником auth.
Займемся политикой.

74

Часть I. Основы Laravel на практическом примере

2. В командной строке создадим политику BbPolicy:
php artisan make:policy BbPolicy

3. Откроем только что созданную политику app\Policies\BbPolicy.php и посмотрим на ее
код (листинг 2.3).
Листинг 2.3. Код «пустой» политики BbPolicy
namespace App\Policies;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class BbPolicy {
use HandlesAuthorization;
public function __construct() {
}
}

Политика в Laravel — это класс, находящийся в пространстве имен App\Policies и
использующий трейт HandlesAuthorization, содержащий логику, которая допускает
пользователя к защищаемой модели лишь после выполнения им входа. Изначально
политика содержит только «пустой» конструктор, в принципе ненужный.
4. Добавим в политику BbPolicy код, реализующий разграничение доступа:
use App\Models\Bb;
class BbPolicy {
. . .
public function update(User $user, Bb $bb) {
return $bb->user->id === $user->id;
}
public function destroy(User $user, Bb $bb) {
return $this->update($user, $bb);
}
}

Логика, реализующая разграничение доступа, записывается в виде набора общедоступных методов класса политики, каждый из которых вызывается при попытке выполнить над записями защищаемой политикой модели определенную операцию
(update() — правку, destroy() — удаление и т. п.). Первым параметром эти методы
принимают объект текущего пользователя. Остальные параметры могут быть произвольными — как правило, это объекты моделей, представляющие проверяемые
записи. Каждый метод должен возвращать в качестве результата логическую величину: true — операция разрешена, false — запрещена.
Наши методы получают вторым параметром объект объявления. Метод update()
сравнивает ключ текущего пользователя с ключом автора объявления, и если они
равны (т. е. текущий пользователь является автором объявления), операция правки

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

75

разрешается. Метод destroy() для выполнения аналогичной проверки просто вызывает метод update().
5. Откроем модуль app\Providers\AuthServiceProvider.php с кодом провайдера
AuthServiceProvider и добавим код, связывающий модель Bb с политикой BbPolicy:
class AuthServiceProvider extends ServiceProvider {
. . .
protected $policies = [
'App\Models\Bb' => 'App\Policies\BbPolicy',
];
. . .
}

Такие связи записываются в ассоциативном массиве, присвоенном защищенному
свойству policies класса провайдера. Один элемент массива описывает одну связь
между моделью (ее полное имя указывается в качестве ключа элемента) и политикой (полное имя которой станет значением элемента).
6. Откроем список веб-маршрутов routes\web.php и добавим код, указывающий применять политику BbPolicy при операциях правки и удаления объявления:
Route::get('/home/{bb}/edit', ... )
->name('bb.edit')->middleware('can:update,bb');
Route::patch('/home/{bb}', ... )
->name('bb.update')->middleware('can:update,bb');
Route::get('/home/{bb}/delete', ... )
->name('bb.delete')->middleware('can:destroy,bb');
Route::delete('/home/{bb}', ... )
->name('bb.destroy')->middleware('can:destroy,bb');

Объект маршрута, возвращаемый методами get(), post(), patch() и delete(), поддерживает знакомый нам метод middleware(), задающий посредник, который станет
обрабатывать все запросы по текущему маршруту. Мы указали «пропускать» запросы по этим четырем маршрутам через посредник can, реализующий разграничение
доступа к моделям посредством связанных с ними политик.
Посредник can требует указать два параметра, записываемых после двоеточия через
запятую:
• название выполняемой операции, которое должно совпадать с именем одного из
методов, объявленных в политике;
• имя URL-параметра, содержащего ключ записи. Подсистема внедрения зависимости сама найдет запись по ее ключу и передаст представляющий ее объект
указанному методу политики, которая связана с моделью.
В нашем случае при попытке перейти на страницу правки записи Laravel определит,
что с моделью Bb связана политика BbPolicy, вызовет метод update() этой политики
и передаст ему объект исправляемого объявления. Метод update() проверит, является ли текущий пользователь автором объявления, и разрешит переход на страницу
правки или, напротив, выведет сообщение об ошибке 403.
Войдем на сайт от имени любого пользователя и попробуем исправить какое-либо объявление. После чего, набрав интернет-адрес формата /home//edit/,

76

Часть I. Основы Laravel на практическом примере

попытаемся исправить «чужое» объявление и удостоверимся, что сайт нас к нему не
«пускает».

2.6. Получение сведений
о текущем пользователе
Осталось сделать так, чтобы гиперссылки на страницы, доступные лишь зарегистрированным пользователям, не показывались гостям, и наоборот. Также неплохо было бы
вывести в разделе пользователя его имя — с этого и начнем.
1. Откроем шаблон раздела пользователя resources\views\home.blade.php и вставим код,
выводящий заголовок с «адресным» приветствием:
@section('content')
Добро пожаловать, {{ Auth::user()->name }}!
Добавить объявление

Здесь мы, вызвав метод user() фасада Auth, получаем объект текущего пользователя
и обращаемся к свойству name этого объекта, чтобы извлечь имя пользователя.
2. Откроем базовый шаблон resources\views\layouts\app.blade.php и добавим код, выводящий гиперссылки Регистрация и Вход только гостям, а гиперссылку Мои объявления и веб-форму с кнопкой Выход — только зарегистрированным пользователям:
Главная
@guest
Регистрация
Вход
@endguest
@auth
Мои объявления

. . .

@endauth

Парная директива @quest ... @endguest шаблонизатора выводит свое содержимое,
если вход на сайт не был выполнен, а парная директива @auth ... @endauth — если
вход, напротив, был выполнен.
Проверим, как все работает.
Страницы регистрации и входа, а также сообщения об ошибках ввода у нас выводятся
по-английски. К тому же сообщения об ошибках не очень информативны. Займемся
этим.

2.7. Локализация веб-сайта
К счастью, все шаблоны, создаваемые командой ui:auth, изначально поддерживают
локализацию. Поэтому, чтобы выполнить русскую локализацию этих шаблонов, доста-

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

77

точно поместить в состав проекта русские языковые модули и указать в настройках
проекта русский в качестве изначального языка сайта.
Локализация — это адаптация сайта, написанного на одном языке (изначальном), к другому (целевому). Локализация сводится к переводу на целевой язык надписей, выводимых на страницах.
Языковый модуль (или модуль локализации) — это программный модуль, который хранит набор выводимых на страницах надписей, переведенных на целевой язык. Laravel
позволяет создавать для каждого целевого языка произвольное количество языковых
модулей, написанных на языках PHP или JSON.
Чтобы выполнить локализацию сайта, нам понадобится установить в проект две дополнительные библиотеки:
 Laravel Lang — содержащую набор языковых модулей для разных языков (включая

русский);
 LaravelLang1 — добавляющую утилите artisan поддержку новой команды, которая

копирует языковые модули для заданного языка из библиотеки Laravel Lang в состав
сайта.
Перед установкой новых библиотек лучше остановить отладочный веб-сервер.
1. Установим дополнительную библиотеку Laravel Lang:
composer require laravel-lang/lang --dev

Ключ --dev предписывает Composer пометить устанавливаемую библиотеку как необходимую только на этапе разработки проекта и не требующуюся при его эксплуатации.
2. Установим дополнительную библиотеку LaravelLang:
composer require arcanedev/laravel-lang --dev

Эта библиотека также требуется только на этапе разработки.
3. Выполним копирование русских языковых модулей из библиотеки Laravel Lang
в состав сайта:
php artisan trans:publish ru --json

После выполнения этой команды в папке lang проекта будет создана папка ru, содержащая набор языковых PHP-модулей. В частности, языковый модуль validation.php,
находящийся в этой папке, хранит сообщения об ошибках ввода. Кроме того, непосредственно в папке lang появится языковый JSON-модуль ru.json, содержащий все
надписи, которые используются в шаблонах, сгенерированных командой ui:auth.
Обязательно следует указать в настройках проекта русский язык.
4. Откроем модуль config\app.php, содержащий общие настройки проекта, и внесем
в него соответствующую правку:
return [
. . .

1

Несмотря на похожие названия, это две совершенно разные библиотеки.

78

Часть I. Основы Laravel на практическом примере
'locale' => 'ru',
. . .
];

Запустим отладочный сервер, перейдем на страницу входа и удостоверимся, что все
надписи на ней теперь выводятся по-русски (рис. 2.4).

Рис. 2.4. Веб-страница входа после русской локализации

Выполним вход на сайт и попробуем добавить объявление, не указав название товара. Под полем ввода название появится сообщение Поле title обязательно для
заполнения. title — это наименование поля ввода, в которое заносится название
товара, и в сообщении об ошибке оно выглядит совершенно не информативно.
Укажем подсистеме локализации Laravel выводить вместо title строку Товар, вместо content (наименование области редактирования, в которое вводится само объявление) — Содержание объявления, а вместо price (наименование поля для ввода
цены) — Цена.
5. Откроем русский языковый модуль lang\ru\validation.php, содержащий сообщения об
ошибках ввода, и добавим в него код, содержащий эти указания:
return [
. . .
'attributes' => [
'title'
=> 'Товар',
'content' => 'Содержание объявления',
'price'
=> 'Цена'
]
];

И, наконец, сделаем так, чтобы в отсутствии цены выводилось сообщение о недопустимости раздачи товаров даром.
6. Вставим в модуль lang\ru\validation.php следующий код:
return [
. . .

Глава 2. Доска объявлений 2.0: разграничение доступа, работа с объявлениями и локализация

79

'custom'
=> [
'price' => [
'required' => 'Раздача товаров даром не допускается',
],
],
. . .
}

Добавленный код указывает выводить заданное сообщение об ошибке при нарушении правила валидации required (обязательно к заполнению) у поля ввода с наименованием price (цена товара).
Введем название товара, удалим цену, вновь попытаемся добавить объявление и посмотрим на указанное нами ранее сообщение об ошибке, выведенное на странице.
На этом разработка учебного сайта доски объявлений в основном закончена. Вы можете доработать его самостоятельно в процессе изучения остального материала книги.

ЧАСТЬ

II

Базовые инструменты
Глава 3.

Создание, настройка и отладка проекта

Глава 4.

Миграции и сидеры

Глава 5.

Модели: базовые инструменты

Глава 6.

Запись данных

Глава 7.

Выборка данных

Глава 8.

Маршрутизация

Глава 9.

Контроллеры и действия.
Обработка запросов и генерирование ответов

Глава 10.

Обработка введенных данных. Валидация

Глава 11.

Шаблоны: базовые инструменты

Глава 12.

Пагинация

Глава 13.

Разграничение доступа: базовые инструменты

Глава 14.

Обработка строк, массивов и функции-хелперы

Глава 15.

Коллекции Laravel

ГЛАВА

3

Создание, настройка
и отладка проекта
3.1. Подготовка к установке
Laravel 9 для работы требует наличия программных платформ следующих (или более
новых) версий:
 PHP — 8.0 с расширениями BCMath, Ctype, cURL, DOM, Fileinfo, JSON, Mbstring,

OpenSSL, PCRE, PDO, Tokenizer и XML;
 SQLite — 3.8.8;
 MySQL — 5.7;
 MariaDB — 10.2;
 PostgreSQL — 10.0;
 Microsoft SQL Server — 2017.

Отдельный веб-сервер для отладки необязателен — можно использовать отладочный
веб-сервер, встроенный в PHP.
Для подготовки программной платформы к разработке сайта на Laravel следует выполнить следующие шаги:
1. Установить платформу PHP (дистрибутив находится на сайте https://www.php.net/).
2. Установить программу Composer (https://getcomposer.org/).
В процессе установки потребуется указать путь к файлу php.exe (консольной редакции исполняющей среды PHP) и предписать добавить этот путь в список путей системной переменной PATH, установив соответствующий флажок.
3. Установить клиентскую часть используемой серверной СУБД — при необходимости.

3.2. Создание проекта
3.2.1. Создание проекта с помощью Composer
Чтобы создать новый проект, основанный на Laravel 9, следует использовать команду
create-project программы Composer. Для этого необходимо в командной строке вы-

84

Часть II. Базовые инструменты

полнить переход в папку, в которой должна находиться папка создаваемого проекта,
и набрать команду следующего формата:
composer create-project laravel/laravel "9.1.*"

Папка проекта с указанным именем создается в той папке, в которой была отдана команда.
Команда устанавливает библиотеку laravel/laravel, представляющую собой комплект из
самого фреймворка Laravel и некоторых дополнительных библиотек (в частности, библиотеки laravel/tinker, реализующей консоль Laravel), версии 9.1, которая описывается
в этой книге.
Использование команды create-project программы Composer — единственный способ
создать проект, основанный на Laravel строго указанной версии.

3.2.2. Создание проекта с помощью Laravel Installer
Создать Laravel-проект также можно с помощью утилиты Laravel Installer. Эта утилита
предоставляет дополнительные возможности (в частности, может создать для проекта
Git-репозитории — как локальный, так и удаленный).
ВНИМАНИЕ!
К сожалению, посредством утилиты Laravel Installer нельзя создать проект, основанный на строго указанной версии Laravel. Эта утилита всегда устанавливает фреймворк
наиболее актуальной на текущий момент версии.

Сначала необходимо установить утилиту Laravel Installer, набрав в командной строке
команду:
composer global require laravel/installer

Утилита будет установлена на уровне системы (подробности — в разд. 1.2).
Для создания нового Laravel-проекта следует использовать команду формата:
laravel new [--git [--branch=]] | 
[--github[=] 
[--organization=]] [--dev] [--force]

Поддерживаются следующие полезные ключи:
 --git — создать для проекта локальный репозиторий Git1;
 --branch — создать в формируемом локальном репозитории Git изначальную ветвь

с заданным именем;
 --github — создать локальный репозиторий Git и закрытый (private) удаленный

репозиторий GitHub2. Можно указать командные ключи, которые будут переданы
утилите GitHub CLI;

 --organization — создать удаленный репозиторий GitHub от имени организации

с заданным названием;
1
2

Требуется предварительно установить пакет Git (https://git-scm.com/).

Требуется предварительно установить утилиту GitHub CLI (https://cli.github.com/) и выполнить вход
в службу GitHub.

Глава 3. Создание, настройка и отладка проекта

85

 --dev — использовать для проекта самую последнюю версию Laravel, даже если она

не является стабильной (релизом);
 --force — создать проект, даже если существует папка с именем, совпадающим

с указанным именем проекта.

3.3.Папки и файлы проекта
В этом разделе описаны папки и файлы, составляющие проект и присутствующие в его
папке. Вложенность папок и файлов показана отступами. Имена папок набраны прописными буквами, имена файлов — строчными.
 APP — все программные PHP-модули, хранящие код сайта. Распределены по разным папкам, которые мы рассмотрим в последующих главах;
 BOOTSTRAP — модули с инициализационным кодом:
• CACHE — инициализационные модули, сгенерированные фреймворком и предназначенные для ускорения загрузки библиотечных модулей;
• app.php — основной инициализационный модуль. В частности, создает объект,
представляющий Laravel-сайт;
 CONFIG — все модули с рабочими настройками проекта (будут рассмотрены далее
в этой и последующих главах);
 DATABASE — служебные модули, имеющие отношение к базам данных. В этой папке можно сохранить базы данных формата SQLite, используемые сайтом;
• FACTORIES — фабрики записей (используются при автоматизированном тестировании, которое в этой книге не рассматривается);
• MIGRATIONS — миграции;
• SEEDERS — сидеры;
 LANG — языковые файлы, разнесенные по папкам, каждая из которых соответствует
одному языку (подробности — в главе 28);
 PUBLIC — корневая папка сайта. В нее можно поместить необходимые статические
файлы (изображения, таблицы стилей, веб-сценарии и др.):
• .htaccess — файл конфигурации веб-сервера Apache HTTP Server;
• favicon.ico — значок сайта;
• index.php — единая точка входа (или стартовый модуль). Выполняется при
получении любого клиентского запроса, создает объект, представляющий сайт
(запуская для этого модуль bootstrap\app.php), запускает обработку запроса,
отправляет клиенту сгенерированный ответ и завершает работу сайта;
• robots.txt — список исключений для поисковых служб;
 RESOURCES — файлы с кодом сайта, написанные на языках, отличных от PHP:
• CSS — внешние таблицы стилей, написанные на языке CSS;
• JS — внешние веб-сценарии, подлежащие преобразованию посредством Laravel
Mix (будет описан в главе 17);
• VIEWS — шаблоны;

86

Часть II. Базовые инструменты

 ROUTES — модули со списками маршрутов;
 STORAGE — файлы, выгруженные на сайт посетителями (изображения, аудио-, ви-

деофайлы, архивы и др.) или созданные программно (например, аватары, сгенерированные на основе выгруженных посетителями изображений), и служебные файлы:
• APP — файлы, выгруженные на сайт посетителями или созданные программно и
не предназначенные для вывода на страницах, — сохраняются непосредственно
в этой папке:
 PUBLIC — файлы, выгруженные на сайт или созданные программно, напротив, выводящиеся на страницах. Обычно в корневой папке сайта (public) создается символическая ссылка storage, указывающая на папку storage\app\public
(как это сделать, будет описано в главе 18);
• FRAMEWORK — служебные файлы, сгенерированные фреймворком:
 CACHE\DATA — файлы с кешированными данными (если используется файловый кеш). Подробнее о кешировании данных будет рассказано в главе 29;
 SESSIONS — файлы с серверными сессиями, если в настройках указано хранение сессий в файлах (подробности — в главе 26);
 TESTING — файлы, выгруженные посетителями (сохраняются здесь при работе в тестовом режиме);
 VIEWS — откомпилированные шаблоны;
• LOGS — файлы журналов;
 TESTS — тестовые модули.
АВТОР НЕ ОПИСЫВАЕТ В ЭТОЙ КНИГЕ АВТОМАТИЗИРОВАННОЕ ТЕСТИРОВАНИЕ...
...поскольку не считает его сколь-нибудь полезным.

 VENDOR — сам фреймворк Laravel и его зависимости — другие библиотеки, ис-

пользуемые им в работе;
 .editorconfig — специфические настройки для текстовых редакторов;
 .env — локальные настройки;
 .env.example — шаблон для генерирования файла .env. Отличается от последнего

лишь тем, что не содержит секретного ключа (о нем поговорим позже);
 .gitattributes — конфигурация Git;
 .styleci.yml — конфигурация StyleCI, службы, преобразующей исходный код к задан-

ному стандарту написания;
 artisan — одноименная утилита, служащая для выполнения различных действий над

проектом;
 composer.json — конфигурация проекта в формате утилиты Composer;
 composer.lock — список установленных PHP-библиотек с указанием их версий;
 package.json — конфигурация проекта в формате утилиты npm;
 phpuint.xml — конфигурация тестовой подсистемы Laravel;

Глава 3. Создание, настройка и отладка проекта

87

 readme.md — краткое описание проекта в формате Markdown;
 webpack.mix.js — конфигурация Laravel Mix.

3.4. Настройки проекта
3.4.1. Две разновидности настроек проекта
3.4.1.1. Локальные настройки
Локальные настройки (или настройки окружения) описывают некоторые аспекты
конфигурации текущей программной платформы: параметры подключения к базе данных, почтовому серверу, параметры кеша, серверных сессий, службы рассылки сообщений и др. Они хранятся в файле .env.
Локальные настройки не сохраняются в коммитах Git. Благодаря этому каждый член
группы разработчиков, работающих над проектом, может описать в локальных настройках специфические параметры своей платформы. Например, один разработчик
может указать в локальных настройках использовать какую-либо систему кеширования
(скажем, с целью отладки), а другой — вообще не использовать кеш.
Настройки в файле .env записываются в виде строк формата:
=

Имена настроек традиционно набираются в верхнем регистре.
В качестве значения настройки может быть задана:
 строка:
APP_NAME=Объявления

Если строка содержит пробелы, ее следует заключить в одинарные или двойные
кавычки:
APP_NAME="Доска объявлений"

 логическая величина, записанная в виде true, (true), false или (false):
APP_DEBUG=true
SEND_MAIL=(false)

 значение null, записанное в виде null или (null):
MAIL_ENCRYPTION=null

 «пустая» строка, записанная в виде empty или (empty):
DB_PASSWORD=empty

 значение другой настройки с указанным именем, записанное в формате:
"${}"

Например, настройка MAIL_FROM_NAME получит значение, указанное у настройки
APP_NAME:
MAIL_FROM_NAME="${APP_NAME}"

88

Часть II. Базовые инструменты

 Если вообще не указать значение у настройки, она в качестве значения получит

«пустую» строку:
DB_PASSWORD=

Пример локальных настроек, задающих параметры доступа к базе данных MySQL:
DB_CONNECTION=mysql
DB_HOST=data-server.local
DB_DATABASE=bboard
DB_USERNAME=bboard
DB_PASSWORD=123456789

Любую настройку, записанную в файле .env, можно перекрыть, создав переменную
среды пользователя или системную переменную с тем же именем (например, если создать переменную DB_DATABASE со значением bboard_new, Laravel будет использовать базу
данных bboard_new, а не bboard, как записано в файле .env). При этом системные переменные имеют приоритет перед переменными уровня пользователя.

3.4.1.2. Рабочие настройки
Рабочие настройки затрагивают все аспекты функционирования проекта. Именно из
рабочих настроек Laravel получает все необходимые ему сведения о сайте.
Рабочие настройки хранятся в 15 модулях, находящихся в папке config. Каждый модуль
содержит настройки одной из подсистем фреймворка. Так, модуль database.php хранит
настройки подсистемы, обеспечивающей работу с базами данных, модуль session.php —
настройки подсистемы серверных сессий, модуль view.php — шаблонизатора и пр.
Особняком стоит модуль app.php, содержащий настройки сайта как такового: название,
режим работы, язык по умолчанию и др.
Настройки в каждом таком модуле организованы в виде ассоциативного массива, который возвращается из модуля в качестве результата. Отдельный элемент такого массива
задает одну из настроек, которая может быть как элементарным значением, так и массивом.
Ряд рабочих настроек получают свои значения из файла .env, в котором хранятся
локальные настройки. Таким образом, Laravel при инициализации выполняет объединение локальных и рабочих настроек для удобства программирования.
В качестве примера рассмотрим фрагмент модуля config\database.php:
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => env('DB_DATABASE',
database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],

Глава 3. Создание, настройка и отладка проекта

89

. . .
],
. . .
];

Элемент connections возвращаемого массива содержит список баз данных (более подробно о них мы поговорим очень скоро). А элемент default задает базу данных по
умолчанию, используемую, если база не была задана явно.
Элемент default получает свое значение из локальной настройки DB_CONNECTION, записанной в файле .env. Для извлечения оттуда настройки с заданным именем используется
функция-хелпер env(), вызываемая в формате:
env([, =null])
Значение по умолчанию возвращается, если настройка с заданным именем в файле .env не
найдена.
Также из локальных настроек получают свои значения рабочие настройки url, database
и foreign_key_constraints, записанные в массиве connections.sqlite.

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

3.4.2.1. Базовые настройки проекта
Базовые настройки проекта записаны в модуле config\app.php. Они включают название
проекта, язык по умолчанию, интернет-адрес, по которому опубликован сайт, и пр.:
 name — название проекта. Значение берется из локальной настройки APP_NAME. По

умолчанию: "Laravel";
 url — интернет-адрес хоста, на котором работает сайт. Используется утилитой

artisan при генерировании модулей. Значение берется из локальной настройки
APP_URL. По умолчанию: "http://localhost";
 asset_url — интернет-адрес хоста, на котором находятся статические файлы сайта,
или путь к содержащей их папке без конечного слеша. Используется функцией
asset() (см. главу 11) для формирования интернет-адресов статических файлов.
Значение настройки берется из локальной настройки ASSET_URL, изначально отсутствующей в файле .env. По умолчанию: null (указывает, что статические файлы находятся непосредственно в папке public того же хоста, на котором развернут сайт).
Пример:
// Файл .env
ASSET_URL=/assets
// Шаблон


-->

90

Часть II. Базовые инструменты

 timezone — обозначение временно́й зоны по умолчанию в виде строки (по умолча-

нию: "UTF", т. е. всемирное координированное время):
return [
. . .
'timezone' => 'Europe/Moscow',
. . .
];

 locale — обозначение языка, используемого по умолчанию, если иной язык не за-

дан, в виде строки (по умолчанию "en", т. е. английский). Пример установки русского языка:
return [
. . .
'locale' => 'ru',
. . .
];

 fallback_locale — обозначение языка, используемого, если выбранный посетителем

язык сайтом не поддерживается, в виде строки (по умолчанию: "en");
 faker_locale — обозначение языка, используемого фабриками записей (применяют-

ся при автоматизированном тестировании, которое в этой книге не рассматривается). По умолчанию: "en_US" (американский английский).

3.4.2.2. Настройки режима работы веб-сайта
Эти настройки затрагивают особенности функционирования сайта и хранятся в модуле
config\app.php.
 env — обозначение режима работы сайта в виде строки. Может быть произвольным.

Разработчики Laravel рекомендуют указывать следующие режимы:
• "local" — отладочный;
• "production" — эксплуатационный.
Значение настройки берется из локальной настройки APP_ENV. По умолчанию:
"production", однако в настройке APP_ENV изначально указано "local";
 debug — если true, при возникновении ошибки будет выводиться страница с под-

робным описанием проблемы, если false — будет выводиться стандартная страница
с сообщением об ошибке 503 (внутренняя ошибка сайта). Значение берется из локальной настройки APP_DEBUG. По умолчанию: false, однако в настройке APP_DEBUG
изначально указано true.

3.4.2.3. Настройки шифрования
Настройки шифрования также хранятся в модуле config\app.php.
 key — секретный ключ, используемый в операциях шифрования, хеширования и

подписывания данных, в виде строки. Значение берется из локальной настройки
APP_KEY.

Глава 3. Создание, настройка и отладка проекта

91

Секретный ключ генерируется и записывается в файл .env утилитой artisan при создании нового проекта. При необходимости его можно сгенерировать повторно, отдав команду формата:
php artisan key:generate [--force]

Если сайт работает в эксплуатационном режиме (настройке env из модуля
config\app.php дано значение "production"), утилита artisan спросит, перезаписывать
ли старый секретный ключ. Чтобы перезаписать его принудительно, без выдачи запроса, следует указать ключ --force;
 cipher — обозначение алгоритма, применяемого для генерирования секретного

ключа, в виде строки. Поддерживаются алгоритмы "AES-128-CBC", "AES-256-CBC" (используется по умолчанию) и "AES-128-GCM" и "AES-256-GCM".

3.4.2.4. Настройки баз данных
Настройки подключения к базам данных, используемым сайтом, хранятся в модуле
config\database.php.
 connections — список используемых баз данных (в терминологии Laravel — «под-

ключений»). Их может быть произвольное количество, они могут быть разных форматов, располагаться в разных файлах и на разных хостах. Указывается в виде ассоциативного массива, каждый элемент которого описывает одну базу данных. Ключ
элемента этого массива задаст имя базы данных, используемое Laravel.
Изначально список содержит базы с именами sqlite, mysql, pgsql и sqlsrv форматов
соответственно SQLite, MySQL, PostgreSQL и Microsoft SQL Server. Вы можете удалить ненужные базы данных и добавить требуемые.
Настройки подключения к каждой базе данных также записываются в виде ассоциативного массива (пример которого можно увидеть в разд. 3.4.1.2). Эти настройки мы
рассмотрим позже;
 default — имя используемой по умолчанию базы данных из указанных в списке
connections,

если в выражении, обращающемся к данным, база не задана явно. Значение берется из локальной настройки DB_CONNECTION (по умолчанию: "mysql");

 migrations — имя таблицы, создаваемой в базе данных для хранения журнала ми-

граций (подробности будут в разд. 4.1). Значение по умолчанию: "migrations", и менять его следует лишь в случае, если в базе уже есть или будет таблица с таким именем.

Настройки самих баз данных, указываемые в элементах массива connections:
 driver — обозначение драйвера PDO, используемого для доступа к базе данных оп-

ределенного формата, в виде строки: "sqlite" (SQLite), "mysql" (MySQL), "pgsql"
(PostgreSQL) и "sqlsrv" (Microsoft SQL Server);
 database — абсолютный путь к файлу базы данных (формата SQLite) или имя базы

данных (остальных форматов) в виде строки. Значение берется из локальной настройки DB_DATABASE. По умолчанию:
• у базы данных sqlite — абсолютный путь к файлу database\database.sqlite, изначально несуществующему;
• у остальных баз данных — "forge";

92

Часть II. Базовые инструменты

 prefix — префикс, добавляемый в начале имен всех таблиц, в виде строки. Может

пригодиться, если база уже содержит таблицы, чьи имена могут совпасть с именами
таблиц с данными сайта. По умолчанию: «пустая» строка.
Следующие настройки указываются лишь у серверных СУБД:
 host — интернет-адрес хоста, на котором работает серверная СУБД, в виде строки.

Значение берется из локальной настройки DB_HOST. По умолчанию: "127.0.0.1" или
"localhost" (локальный хост);
 port — номер TCP-порта, через который работает серверная СУБД, в виде строки.

Значение берется из локальной настройки DB_PORT. По умолчанию:
• у базы данных mysql — "3306";
• у базы данных pgsql — "5432";
• у базы данных sqlsrv — "1433";
 username — имя пользователя для подключения к серверной СУБД в виде строки.

Значение берется из локальной настройки DB_USERNAME. По умолчанию: "forge";
 password — пароль для подключения к серверной СУБД в виде строки. Значение

берется из локальной настройки DB_PASSWORD. По умолчанию: «пустая» строка;
 charset — обозначение кодировки баз данных в виде строки. По умолчанию:
"utf8mb4" (MySQL)

или "utf8" (остальные);

 url — интернет-адрес базы данных, записанный в формате:
://:@
[:]/[?]

указывается в том случае, если серверная СУБД работает через нестандартный порт. Примеры:

TCP-порт

mysql://bboard:123456789@data-server.local/bboard?charset=UTF-8

Значение берется из локальной настройки DATABASE_URL, изначально несуществующей;
 prefix_indexes — если true, префикс, заданный настройкой prefix, будет добавлять-

ся в начало имен всех создаваемых таблиц, если false — не будет (по умолчанию:
true).

Далее приведены настройки, специфические для отдельных СУБД:
 foreign_key_constraints (только SQLite) — если true, ссылочная целостность будет

поддерживаться непосредственно на уровне СУБД, если false — не будет поддерживаться. Значение берется из локальной настройки DB_FOREIGN_KEYS, изначально
несуществующей. По умолчанию: true;
 unix_socket (только MySQL) — обозначение сокета, через который выполняется

подключение к серверной СУБД, в виде строки. Значение берется из локальной
настройки DB_SOCKET. По умолчанию: «пустая» строка;
 collation (только MySQL) — обозначение последовательности сортировки записей

в виде строки (по умолчанию: "utf8mb4_unicode_ci");

Глава 3. Создание, настройка и отладка проекта

93

 strict (только MySQL) — если true, включится «строгий» (strict) режим, если
false —

СУБД будет работать в обычном режиме (по умолчанию: true);

 engine (только MySQL) — обозначение программного ядра, используемого для

работы с базой, в виде строки. По умолчанию: null (ядро InnoDB);
 options (только MySQL) — ассоциативный массив с дополнительными параметрами

подключения. По умолчанию содержит один элемент с ключом PDO::MYSQL_ATTR_
и значением, которое представляет собой путь к файлу сертификата, извлеченный из локальной настройки MYSQL_ATTR_SSL_CA;
SSL_CA

 search_path (только PostgreSQL) — имя схемы базы данных, с которой будет осуще-

ствляться работа, в виде строки (по умолчанию: "public").
ВНИМАНИЕ!
В предыдущих версиях Laravel эта настройка носила имя schema. При переносе старого кода на новую версию фреймворка настройку необходимо переименовать.

 sslmode (только PostgreSQL) — обозначение режима защищенного подключения

в виде строки (по умолчанию: "prefer");
 encrypt (только Microsoft SQL Server) — если "yes", обмен данными с СУБД будет

производиться по защищенному каналу, если "no" — по обычному. Значение берется из локальной настройки DB_ENCRYPT, изначально несуществующей. По умолчанию:
"yes". Настройка изначально закомментирована;
 trust_server_sertificate (только Microsoft SQL Server) — если true, сертификат,

установленный на сервере, будет считаться доверенным и не станет проверяться,
если false — не будет считаться доверенным и подвергнется соответствующей проверке. Значение берется из локальной настройки DB_TRUST_SERVER_CERTIFICATE, изначально несуществующей. По умолчанию: false. Настройка изначально закомментирована.
Если для операций чтения и записи используются разные подключения, специфичные
для них параметры записываются в настройках соответственно: read и write. В рассмотренном далее примере для чтения из базы данных bboard используется подключение к хосту read.data.local от имени пользователя r_bboard с паролем 123456789, а для
записи в ту же базу — подключение к хосту write.data.local через нестандартный
TСP-порт 6603 от имени пользователя w_bboard с паролем 987654321:
'connections' => [
'mysql' => [
'driver' => 'mysql',
'read' => [
'host' => 'read.data.local',
'port' => '3306',
'username' => 'r_bboard',
'password' => '123456789',
],
'write' => [
'host' => 'write.data.local',
'port' => '6603',

94

Часть II. Базовые инструменты
'username' => 'w_bboard',
'password' => '987654321',
],
'database' => 'bboard',
. . .
],

],

Если параметру sticky дать значение true, после записи данных через подключение
«для записи» чтение также будет выполнено через это же подключение. Это может
повысить производительность (разумеется, если пользователь, соединившийся через
это подключение, имеет привилегии на чтение данных):
'connections' => [
'mysql' => [
. . .
'read' => [ ... ],
'write' => [ ... ],
. . .
'sticky' => true,
],
],

Если через подключение «для записи» невозможно чтение данных, параметру sticky
следует дать значение false или вообще удалить его.
ПОЛЕЗНО ЗНАТЬ
Laravel позволяет использовать несколько баз данных, записанных в настройках проекта. Во фреймворке Django, напротив, для этого требуется дополнительное программирование.

3.4.3. Доступ к настройкам из программного кода
Для извлечения значения рабочей настройки с указанным путем применяется функцияхелпер config():
config([, =null])
Путь записывается

в формате:

.

Если настройка с заданным путем отсутствует, возвращается значение по умолчанию.
Примеры:
// Получаем значение настройки name из модуля config\app.php
$project_name = config('app.name');
// Получаем значение настройки connections.sqlite.database
// из модуля config\database.php
$sqlite_database_path = config('database.connections.sqlite.database');

Для программного указания новых значений настроек применяется та же функция
config(), но в другом формате вызова:
config()

Глава 3. Создание, настройка и отладка проекта

95

Ключ элемента заданного массива укажет путь к нужной настройке, а значение элемента станет новым значением этой настройки. Пример:
// Задаем новое название сайта
config(['app.name' => 'ДО: Доска объявлений']);

Выяснить, в каком режиме работает сайт, позволят два следующих метода фасада
Illuminate\Support\Facades\App (управляющего подсистемой, представляющей сайт как
таковой):
 isLocal() — возвращает true, если сайт работает в отладочном режиме (local),

и false — в противном случае:
@if (App::isLocal())
Сайт работает в отладочном режиме
@endif

 isProduction() — возвращает true, если сайт работает в эксплуатационном режиме

(production), и false — в противном случае.
Также можно использовать метод environment() того же фасада, который поддерживает
четыре формата вызова:
 environment() (без параметров) — возвращает строку с наименованием режима ра-

боты:
Сайт работает в режиме: {{ App::environment() }}

 environment() — возвращает true, если сайт работает в заданном режиме,

и false — в противном случае:
@if (App::environment('local'))
Сайт работает в отладочном режиме (local)
@endif

 environment(, , ... ) — возвращает true, если сайт ра-

ботает в одном из указанных режимов, и false — в противном случае:
@if (App::environment('local', 'testing', 'staging'))
Сайт работает в отладочном или одном из тестовых режимов
@endif

 environment() — то же самое, что и предыдущий формат вызова:
@if (App::environment(['local', 'testing', 'staging']))
Сайт работает в отладочном или одном из тестовых режимов
@endif

3.4.4. Создание своих настроек
Ничто не мешает нам создать свои рабочие настройки, добавив их в один из модулей,
хранящихся в папке config. Например, так можно создать в модуле config\app.php
настройку description, содержащую описание сайта:
return [
. . .
'description' => 'Электронная доска объявлений',
];

96

Часть II. Базовые инструменты

А потом — извлечь значение этой настройки:
{{ config('app.description') }}

Созданная таким образом рабочая настройка может брать значение из локальных настроек (файла .env):
// Файл .env
APP_DESC="Электронная доска объявлений"
// Модуль config\app.php
return [
. . .
'description' => env('APP_DESC'),
];

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