Includes
includes() lists what include= accepts:
public function includes(): array
{
return [
'profile',
'posts.comments',
Relationship::to('author', UserQuery::class),
Relationship::count('posts'),
Relationship::max('posts', 'views'),
Relationship::callback('recentPosts', fn ($query) => $query->where('created_at', '>', now()->subWeek()), 'posts'),
Relationship::morphTo('commentable', [Post::class => PostQuery::class, Video::class => VideoQuery::class]),
];
}Relations
A relation path as a string ('posts.comments') allows the relation; every prefix of the path is allowed as well.
Nested definitions
Relationship::to('posts', PostQuery::class) describes the relation by its own definition: its fields, includes and aggregates are allowed under the path.
Definitions may refer to each other: UserQuery includes posts, and PostQuery includes author, described by UserQuery. A definition that repeats on its own path is a leaf there, so include=posts.author is allowed with the fields of UserQuery, while posts.author.posts is not.
->withFilters() publishes the filters of the nested definition on the root (see Filters), and ->withSorts() its sorts (see Sorts).
Aggregates
Relationship::count('posts'), exists, min, max, sum and avg. They are requested as postsCount, postsExists, postsMaxViews; the suffixes come from the query-builder.suffixes config, and ->as('name') changes the name. Each takes an optional closure that constrains the related query.
Callback relations
Relationship::callback('recentPosts', fn ($query) => ..., 'posts') loads a relation with a constraint, under its own name.
morphTo
Relationship::morphTo('commentable', [Post::class => PostQuery::class, Video::class => VideoQuery::class]) describes a morphTo with a definition per related model. fields[posts] narrows the posts under commentable, and the nested includes of a type are loaded only for the models of that type.