Структура каталогов, artisan, .env и конфиги в Laravel
Структура каталогов — это соглашение о том, какой код где лежит в Laravel-проекте; artisan — консольный инструмент фреймворка, через который генерируют код, запускают миграции и управляют приложением; а .env и конфиги — два слоя настроек, между которыми новички чаще всего путаются. Тема выглядит скучной, но именно на ней ломаются проекты: конфиги зашивают в код, файлы пишут не туда, а окружение правят в проде руками.
Зачем это нужно
- Ориентация в чужом коде. Первый день в проекте — и вы знаете, где живут контроллеры, где модели, где тесты. Без понимания структуры каждый файл ищется по всему репозиторию.
- Правильные настройки. Ошибка «работает у меня, падает на проде» почти всегда живёт в разнице
.envи конфигов. Понимание двух слоёв снимает её навсегда. - Экономия времени. Artisan генерирует скелеты классов, сбрасывает кеш, смотрит список роутов — то, что руками заняло бы час, делается одной командой.
Как это работает
Структура каталогов
Ключевые директории и что в них живёт:
| Каталог | Что там | Заметка |
|---|---|---|
app/Http/Controllers | Контроллеры | Основная «прикладная» логика запросов |
app/Models | Eloquent-модели | По умолчанию User; свои кладём рядом |
app/Http/Middleware | Middleware | Свои фильтры запросов |
app/Providers | Сервис-провайдеры | Регистрация привязок, событий |
app/Console, app/Jobs, app/Events, app/Listeners, app/Policies | Команды, очереди, события, политики | Появляются по мере использования artisan make:... |
app/Services (сами создаём) | Бизнес-логика вне контроллеров | Не запрет фреймворка, а хорошее место по конвенции |
bootstrap | Сборка приложения | app.php — точка сборки контейнера; трогать редко |
config | Все конфиги | Единственный источник настроек (см. ниже) |
database | Миграции, фабрики, сиды | Схема и тестовые данные |
public | Единственная публичная папка | index.php, стили, скрипты; сюда смотрит веб-сервер |
resources/views | Blade-шаблоны | Представления |
routes | Роуты | web.php, api.php, console.php |
storage | Логи, скомпилированные шаблоны, сессии, файлы пользователей | Запись идёт сюда, а не куда попало |
tests | PHPUnit-тесты | Feature/ и Unit/ |
vendor | Пакеты Composer | Не правим руками, в git не кладём |
Два практических следствия. Первое: веб-сервер в проде направляем только на public — иначе наружу торчат .env и storage. Второе: app/ — не священная коробка «всё подряд». Классы вроде репозиториев и сервисов фреймворк разрешает класть куда угодно внутри app/, автозагрузка (PSR-4, префикс App\) подхватит.
Artisan
Artisan — это artisan в корне проекта, консольная утилита Laravel. Команды делятся на несколько групп.
Генерация кода (создают файлы со скелетом):
bashphp artisan make:model Post -mf # модель + миграция + фабрика
php artisan make:controller PostController --resource
php artisan make:middleware CheckAge
php artisan make:request StorePostRequest
php artisan make:job SendEmail
php artisan make:seeder PostSeeder
Работа с базой:
bashphp artisan migrate # накатить миграции
php artisan migrate:fresh --seed # пересоздать базу и залить сиды
php artisan db:seed # только сиды
Инспекция и обслуживание:
bashphp artisan route:list # все роуты с middleware
php artisan tinker # REPL: живьём дергать Eloquent
php artisan config:clear # сброс кеша конфигов
php artisan optimize:clear # сброс всех кешей разом
tinker — недооценённая вещь: внутри него можно гонять любой PHP-код с загруженным приложением. Проверить связь, создать модель, посмотреть запрос — не пишуя тест.
.env и конфиги: два слоя
Схема простая, но её важно держать в голове:
.env— значения, которые меняются от окружения к окружению: пароль базы, ключ приложения, адрес почтового сервера. Файл не кладут в git.config/*.php— то, как приложение пользуется этими значениями: структура настроек, значения по умолчанию, вся логика. Кладут в git.
.env читается только через функцию env(), и только внутри config/:
php// config/database.php
'mysql' => [
'host' => env('DB_HOST', '127.0.0.1'), // вторая строка — значение по умолчанию
'database' => env('DB_DATABASE', 'forge'),
// ...
],
В коде приложения — только через config():
php// Плохо
$db = env('DB_DATABASE'); // работает случайно, ломается после config:cache
// Хорошо
$db = config('database.connections.mysql.database');
Подключение к базе из кода тоже идёт через конфиг: DB_HOST и другие переменные попадают в config/database.php, а модель и соединения читают уже оттуда. То же с кешем (config/cache.php), почтой (config/mail.php), очередями (config/queue.php).
Взаимосвязь с lifecycle из прошлого конспекта: конфиги и .env загружаются на этапе bootstrap, до контейнера и middleware. Именно поэтому на проде конфиги кешируют одной командой — и именно поэтому после этого env() в обычном коде возвращает null.
Плохо / Хорошо
| Плохо | Хорошо |
|---|---|
env('API_KEY') в контроллере или сервисе | Задать ключ в config/services.php и читать через config('services.api.key') |
Добавить новый параметр в .env и использовать напрямую | Добавить строку в нужный конфиг со значением env(...) и дефолтом |
Коммитить .env в git | Коммитить .env.example с названиями переменных без секретов |
| Править настройки на проде редактором в файлах | Менять переменные окружения (панель хостинга, docker-compose) и кешировать конфиг |
| Заливать миграции правкой дампа руками | Писать миграции и держать схему в коде |
| Кешировать конфиги в разработке | config:cache — только для прода; локально после смены .env просто перезапускаем |
Подводный камень
env()возвращаетnullпослеconfig:cache. На проде конфиги кешируют в файл — и.envперестаёт читаться в рантайме. Любойenv()внеconfig/молча вернётnull. Это самая частая ловушка темы: локально код работает (кеша нет), на проде — падает.- Смена
.envне даёт эффекта «просто так». Значения кешируются вместе с конфигами, а долгоживущие процессы (octane, очереди, демоны) держат старые значения в памяти. Поменяли переменную — сбросьте кеш и перезапустите воркеры очереди. storageиbootstrap/cacheдолжны быть доступны на запись. Логи, сессии, скомпилированные шаблоны и кеш конфигов пишутся именно туда. Типичный прод-фолбэк: «permission denied» после деплоя — забыли выставить права владельцу процесса php-fpm.vendor— чужая территория. Правки в пакетах вvendor/сотрутся при первом жеcomposer install. Хотите изменить поведение пакета — переопределяйте конфиг, класс через контейнер или форкайте пакет, а не редактируйте файлы.migrate:freshстирает базу целиком. Название говорит честно: дроп всех таблиц и миграции с нуля. На проде это приговор данным, поэтому команда — только для локальной разработки и тестовых окружений.
Мини-шпаргалка
bash# Ежедневный минимум
php artisan make:model Post -mf # модель + миграция + фабрика
php artisan make:controller X --resource
php artisan migrate # накатить миграции
php artisan route:list # посмотреть роуты и middleware
php artisan tinker # живая консоль с приложением
# Окружение
php artisan config:clear # сбросить кеш конфигов
php artisan optimize:clear # сбросить все кеши разом
# Прод-релиз
php artisan config:cache # закешировать конфиги (после этого env() вне config — null)
php artisan route:cache # закешировать роуты
php// Правило чтения настроек:
env() — только в файлах config/
config() — везде в коде приложения
Три вывода
- Веб-сервер смотрит только в
public, данные пишутся вstorage, код приложения — вapp. Это три границы, которые нельзя нарушать. .env— для окружения, конфиги — для приложения.env()живёт только вconfig/, везде дальше —config(). Это правило снимает половину проблем «на локалке работает, на проде нет».- Artisan — не набор заклинаний, а рабочие руки фреймворка.
route:listиtinkerэкономят больше времени, чем любые генераторы кода.
Коварный вопрос
Вопрос: «Почему после деплоя с закешированными конфигами значения из .env перестали читаться?»
Подвох: кажется, что кеш — это просто «быстрее достать те же данные». На деле config:cache переводит приложение в другой режим: конфиги собираются в один файл, а .env больше не загружается в рантайме вовсе — на то он и кеш. Спотыкаются на этом даже опытные разработчики: код с env() вне config/ выглядит рабочим, пока не окажется на проде.