Статический анализ с Larastan
С Larastan пакет проверяет определения запросов до их выполнения. Подключите его расширение после Larastan в phpstan.neon:
includes:
- vendor/larastan/larastan/extension.neon
- vendor/myprogs/query-builder/extension.neonЧто проверяется
PHPStan сообщает на строке объявления:
| Проблема | Идентификатор |
|---|---|
путь связи с сегментом, которого нет у модели (includes(), Relationship, поля и фильтры через точку, сортировки по связям и агрегатам) | queryBuilder.relation |
Sort::relation() через связь, которая не «к одному» | queryBuilder.toOne |
Relationship::to() или тип Relationship::morphTo(), определение которого описывает другую модель | queryBuilder.definition |
| колонка, которой нет в таблице: поля, зависимости виртуальных полей, колонки фильтров и сортировок, колонки агрегатов | queryBuilder.column |
Filter::scope() без такого скоупа у модели | queryBuilder.scope |
| сортировка по умолчанию, которой нет среди сортировок | queryBuilder.defaultSort |
Колонки берутся из миграций и дампов схемы, которые читает Larastan, поэтому проверяются только для моделей, чью таблицу Larastan знает. Чтобы отключить проверку колонок:
parameters:
queryBuilder:
checkColumns: falseЧто пропускается
Проверяется только то, что записано буквально: метод, возвращающий [...] со строками и вызовами Field, Relationship, Filter и Sort. Элементы, собираемые во время выполнения (переменные, spread, array_merge()), методы, унаследованные от базового определения, и разовые запросы Query::for() пропускаются.
Связь прослеживается, когда её возвращаемый тип называет связанную модель (@return HasMany<Post, $this>); morphTo прослеживается через типы, перечисленные в morphTypes() или Relationship::morphTo(). Вложенное определение сверяется со связью, когда анализируются оба файла.
Типизированные запросы
Query обобщён по своей модели, поэтому скоупы модели и методы builder остаются известны по всей цепочке, например OrderCommentQuery::for($request)->where('order_id', $id)->owned()->paginate().
Query::for(User::class)иQuery::for(User::query())— этоQuery<User>.- Определение называет свою модель через
@extends QueryDefinition<User>, либо расширение берёт её изmodel(), когда тот возвращаетUser::class. Без того и другого запрос —Query<Model>. - Переопределённый
query()может возвращать собственный тип builder определения (Builder<User>).