Including relations
allowedIncludes() lists the relations a request may load. The include parameter takes a list of relation names:
QueryBuilder::for(User::class)
->allowedIncludes('posts', 'permissions')
->get();GET /users?include=posts,permissionsThe relations are eager loaded with with(). An include not in the list throws InvalidIncludeQuery.
Nested relations
->allowedIncludes('posts.comments')A nested path allows every prefix too: include=posts and include=posts.comments both work.
Another relation name
use MyProgs\QueryBuilder\AllowedInclude;
AllowedInclude::relationship('profile', 'userProfile')The client includes profile, the query loads userProfile.
Aggregates
A relation name in allowedIncludes() also allows its count and existence:
GET /users?include=postsCount,postsExistsThey are loaded with withCount() and withExists(), so every user gets posts_count and posts_exists. Nested paths allow the aggregates of their first relation only. The suffixes come from the suffixes config key.
To allow an aggregate without the relation itself, list it on its own:
->allowedIncludes('postsCount', AllowedInclude::exists('postsExists'))Other aggregates take the relation and the column:
AllowedInclude::min('postsViewsMin', 'posts', 'views'),
AllowedInclude::max('postsViewsMax', 'posts', 'views'),
AllowedInclude::sum('postsViewsSum', 'posts', 'views'),
AllowedInclude::avg('postsViewsAvg', 'posts', 'views'),They are loaded with withMin(), withMax(), withSum() and withAvg(), so the attribute is posts_min_views and so on. Every aggregate takes an optional closure that constrains the related query:
AllowedInclude::count('publishedPostsCount', 'posts', fn ($query) => $query->where('published', true))Callback includes
AllowedInclude::callback('posts', fn ($query) => $query->where('published', true))The closure constrains the eager load of the relation: it is passed to with() as ['posts' => $closure]. The third argument names the relation when it differs from the include name.
Custom include classes
Implement MyProgs\QueryBuilder\Includes\IncludeInterface and register it with 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')The class receives the root query and the relation name, the third argument.
Fields of included relations
With allowedFields(), the client may narrow the columns of an included relation, and the keys the relation needs are added automatically. See Selecting fields.