Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.x] Add ability to define "with" relations as a nested array #42690

Merged
merged 3 commits into from
Jun 9, 2022

Conversation

timacdonald
Copy link
Member

Purpose

This PR aims to add the ability to specify relationship "withs" as a PHP array, rather than dot notation.

Usage

// before...

User::with([
    'avatar',
    'posts.tags',
    'posts.author',
    'posts.featureImage',
    'posts.comments.tags' => fn ($q) => $q->latest(),
])->get();

// after...

User::with([
    'avatar',
    'posts' => [
        'tags',
        'author',
        'featureImage',
        'comments' => [
            'tags' => fn ($q) => $q->latest(),
        ],
    ],
])->get();

Advanced

// supports chaining...

User::with([
    'posts' => fn ($q) => $q->withCount('comments')->with([
        'comments' => [
            'tags',
        ],
    ]),
])->get();

// supports specifying attributes inline, although I think with this notation you
// should probably be specifying selects via a constraint.

User::with([
    'posts:id,title,user_id' => [
        'comments:id,content,post_id' => [
            'tags',
        ],
    ],
])->get();

// supports mixing notation. Not saying you should, just saying you can 🙈

User::with([
    'posts' => [
        'comments',
    ],
    'posts.image',
])->get();

// merges constraints from different notation - again, not saying you should. just saying you can.

User::with([
    'posts.comments' => fn ($q) => $q->with('tags'),
    'posts:id,title,user_id' => [
        'comments' => fn ($q) => $q->withCount('tags'),
    ],
])->get();

What isn't supported

I should note that merging of selects from different notation is not supported. I don't see this as a problem, as the current dot notation suffers from the same constraint...

// does not select "id" and "name"
User::query()
    ->with(['users:id,name'])
    ->with(['users:email'])
    ->get();

// nor does this...

User::query()
    ->with(['users' => fn ($q) => $q->select(['id', 'name'])])
    ->with(['users:email'])
    ->get();

and so the following is explicitly not supported...

User::with([
    'posts.comments' => fn ($q) => $q->addSelect(['id']),
    'posts' => [
        'comments' => fn ($q) => $q->addSelect(['post_id'])
    ],
])->get();

User::with([
    'posts' => [
        'comments:post_id,title'
    ],
    'posts.comments:id',
])->get();

or any other mixture of notation with duplicate selects.

Notes

I'd love to get some eyes on this from a range of people who are deep in Eloquent land.

@taylorotwell taylorotwell merged commit 1c0b3d2 into laravel:9.x Jun 9, 2022
@timacdonald timacdonald deleted the nested-withs branch June 13, 2022 02:31
@OzanKurt
Copy link
Contributor

Does this also work on ->load()?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants