Подгрузка связей
allowedIncludes() перечисляет связи, которые может загрузить запрос клиента. Параметр include принимает список имён связей:
QueryBuilder::for(User::class)
->allowedIncludes('posts', 'permissions')
->get();GET /users?include=posts,permissionsСвязи загружаются жадно через with(). Include не из списка выбрасывает InvalidIncludeQuery.
Вложенные связи
->allowedIncludes('posts.comments')Вложенный путь разрешает и каждый свой префикс: работают и include=posts, и include=posts.comments.
Другое имя связи
use MyProgs\QueryBuilder\AllowedInclude;
AllowedInclude::relationship('profile', 'userProfile')Клиент подгружает profile, запрос загружает userProfile.
Агрегаты
Имя связи в allowedIncludes() также разрешает её количество и наличие:
GET /users?include=postsCount,postsExistsОни загружаются через withCount() и withExists(), так что каждый пользователь получает posts_count и posts_exists. Вложенные пути разрешают агрегаты только своей первой связи. Суффиксы берутся из ключа конфигурации suffixes.
Чтобы разрешить агрегат без самой связи, укажите его отдельно:
->allowedIncludes('postsCount', AllowedInclude::exists('postsExists'))Остальные агрегаты принимают связь и колонку:
AllowedInclude::min('postsViewsMin', 'posts', 'views'),
AllowedInclude::max('postsViewsMax', 'posts', 'views'),
AllowedInclude::sum('postsViewsSum', 'posts', 'views'),
AllowedInclude::avg('postsViewsAvg', 'posts', 'views'),Они загружаются через withMin(), withMax(), withSum() и withAvg(), так что атрибут называется posts_min_views и так далее. Каждый агрегат принимает необязательное замыкание, ограничивающее запрос связанной модели:
AllowedInclude::count('publishedPostsCount', 'posts', fn ($query) => $query->where('published', true))Include-callback
AllowedInclude::callback('posts', fn ($query) => $query->where('published', true))Замыкание ограничивает жадную загрузку связи: оно передаётся в with() как ['posts' => $closure]. Третий аргумент задаёт имя связи, если оно отличается от имени include.
Собственные классы include
Реализуйте MyProgs\QueryBuilder\Includes\IncludeInterface и зарегистрируйте его через custom():
use Illuminate\Database\Eloquent\Builder;
use MyProgs\QueryBuilder\Includes\IncludeInterface;
class AggregateInclude implements IncludeInterface
{
public function __construct(protected string $column, protected string $function) {}
public function __invoke(Builder $query, string $relations): void
{
$query->withAggregate($relations, $this->column, $this->function);
}
}AllowedInclude::custom('comments_sum_votes', new AggregateInclude('votes', 'sum'), 'comments')Класс получает корневой запрос и имя связи — третий аргумент.
Поля подгруженных связей
С allowedFields() клиент может сузить колонки подгруженной связи, а ключи, нужные связи, добавляются автоматически. См. Выбор полей.