Skip to content

Лайфхаки и приёмы

Малоизвестные возможности Laravel, которые экономят время каждый день. Формат: приём → зачем. Подробности — в официальной доке (laravel-boost__search-docs).

Artisan — диагностика и интроспекция

КомандаЧто даёт
php artisan aboutВся диагностика окружения одним экраном: версии, драйверы, кеши. Первое, что смотреть на «у меня не работает»
php artisan model:show OrderВсе поля, касты, связи, observers модели — без открытия кода. Идеально перед доработкой чужой модели
php artisan db:table ordersСтолбцы, индексы, FK таблицы прямо из консоли
php artisan route:list --except-vendorРоуты без пакетного шума; --path=api — фильтр по префиксу
php artisan schedule:listВсе cron-задачи с временем следующего запуска
php artisan queue:monitor redis:default --max=100Алерт при переполнении очереди (в cron)
php artisan pailСтрим логов в реальном времени с фильтрами (--filter=, --user=) — вместо tail -f
php artisan migrate --pretendПоказывает SQL миграции, не выполняя — проверка перед прод-запуском
php artisan config:show databaseИтоговый конфиг после всех env/кешей — когда «почему подключается не туда»
php artisan tinkerREPL: быстро проверить запрос/связь/скоуп, не создавая тестовый роут

Eloquent — приёмы, о которых забывают

ПриёмЗачем
sole() вместо first()Бросает исключение, если записей не ровно одна — ловит дубли данных на раннем этапе
createOrFirst()Безопаснее firstOrCreate() под гонкой: сначала INSERT с ловлей duplicate key (нужен уникальный индекс)
upsert([...], unique, update)Массовая вставка-или-обновление одним запросом — основа быстрых импортов
whereBelongsTo($city)Читабельнее where('city_id', $city->id) и не ошибётся в имени FK
is() / isNot()Сравнение моделей без ->id === ->id
loadMissing('relation')Догрузить связь, только если ещё не загружена — без повторного запроса
withWhereHas('reviews', fn...)whereHas + eager load тем же условием — одним вызовом, без дублирования замыкания
chaperone() на hasManyОбратная ссылка на родителя у детей без N+1 ($review->post не делает запрос)
value('name') / pluck('name', 'id')Одно поле/словарь без гидрации моделей — заметно быстрее на больших выборках
toQuery()Коллекцию моделей обратно в запрос — для массового update() по выбранному
withCount() / withSum() / withAvg()Агрегаты подзапросом вместо загрузки связей ради подсчёта
lazy() / lazyById()Обход больших таблиц с константной памятью, интерфейс обычной коллекции

Валидация — тонкости FormRequest

ПриёмЗачем
bail первым правиломОстановить проверку поля на первой ошибке — не гонять дорогие правила (exists) по заведомо пустому
$request->safe()->only([...])Взять из валидированного только нужное — защита от «пролезших» полей при расширении правил
exclude_if / excludeПоле проверяется, но не попадает в validated() — для чекбоксов-соглашений
prohibited_ifЯвный запрет поля в определённых условиях — для API, где лишнее поле = ошибка клиента
Rule::dimensions()->maxWidth(...)Валидация размеров изображения до обработки
sometimes() в withValidatorУсловные правила, зависящие от других полей — вместо каши в rules()
stopOnFirstFailure()Для форм из 20+ полей: не собирать все ошибки, если важна первая

Blade — директивы, которые сокращают шаблоны

ДирективаВместо чего
@class(['active' => $isActive])Тернарники в атрибуте class
@checked($value) / @selected(...) / @disabled(...)
@onceСкрипт компонента, который в цикле вставился бы N раз
@aware(['color'])Проброс prop родительского компонента вглубь без цепочки атрибутов
@session('status')Блок «показать если есть флеш» без @if(session(...))
@forelse ... @empty@if($items->count()) + @foreach (и по стандарту студии — обязателен)

HTTP-клиент — надёжные интеграции без обвязки

ПриёмЗачем
Http::retry(3, 200)Ретраи с паузой из коробки — не писать циклы
Http::timeout(5)->connectTimeout(2)Всегда ставить: зависший внешний API не должен вешать ваш запрос
Http::pool(fn...)Параллельные запросы к нескольким API — суммарное время = максимум, а не сумма
->throw()Превратить 4xx/5xx в исключение — вместо ручной проверки successful()
Http::fake([...]) в тестахМокать внешние API декларативно, Http::assertSent() — проверять вызовы

Хелперы и утилиты последних версий

ИнструментЗачем
Number::forHumans(12500) → «12,5 тыс.»Форматирование чисел/размеров/валют с локалью — не писать свои функции
Str::mask($email, '*', 3)Замаскировать персональные данные в UI/логах
Str::squish()Трим + схлопывание внутренних пробелов — нормализация пользовательского ввода
Benchmark::dd(fn() => ...)Быстро замерить кусок кода без Telescope
Sleep::for(2)->seconds()Вместо sleep() — в тестах фейкается (Sleep::fake()), не тормозит CI
once(fn() => ...)Мемоизация в рамках запроса — для повторных вычислений в цикле
Context::add('order_id', $id)Сквозной контекст: попадает во все логи и в очередь вместе с джобом — находка для отладки продовых инцидентов
defer(fn() => ...)Выполнить после отправки ответа — лёгкая альтернатива очереди для некритичного (метрики, прогрев)
rescue(fn() => ..., $default)try/catch с логированием одной строкой — для некритичных операций

Carbon и даты

  • CarbonImmutable по умолчанию (Date::use(CarbonImmutable::class) в AppServiceProvider): обычный Carbon мутабелен — $date->addDay() меняет исходный объект, это источник трудноуловимых багов в циклах и сравнениях.
  • Хранить всегда в UTC, конвертировать при выводе. APP_TIMEZONE менять с UTC — грабли с DST и сравнением дат.
  • Русские даты — translatedFormat('d F Y') (по стандарту студии), не ручные массивы месяцев.

Filament — мелочи, экономящие часы

ПриёмЗачем
->live(onBlur: true) вместо ->live()Реактивность без запроса на каждый символ — формы заметно отзывчивее
Tables\Actions\ReplicateAction«Дублировать запись» бесплатно — частая просьба клиентов
->defaultGroup('category.name')Группировка строк таблицы без кастомного кода
->persistFiltersInSession()Фильтры переживают уход со страницы — админы это любят
->recordUrl(null) + explicit actionsОтключить клик по строке, когда он открывает не то, что ждут
Section::make()->aside()Форма «поля слева, описание справа» — читабельнее для длинных форм
->helperText() / ->hint()Подсказки прямо в форме — меньше вопросов от контент-менеджера
php artisan make:filament-issueВоспроизводимый багрепорт Filament с версиями окружения

Работа с очередями — практика

  • ->afterCommit() на dispatch внутри транзакции: иначе воркер может взять джоб раньше, чем транзакция закоммитится, и не найти запись (классический «job model not found»).
  • Bus::batch() для пакетов: прогресс, then/catch/finally, отмена — не городить свой учёт.
  • WithoutOverlapping middleware: джобы по одному ресурсу не выполняются параллельно.
  • ShouldBeUnique: защита от дублей джобов в очереди (например, «пересчитать рейтинг»).
  • Разные очереди по приоритету (notifications, heavy) — по стандарту студии; воркер слушает --queue=high,default в порядке приоритета.

Внутренняя база знаний студии