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
[8.x] Eager Loaded Pseudo Relationships #37656
Conversation
this change allows you to alias and eager load relationships with additional constraints. ```php $posts = \App\Post::with(['comments as activeComments', function($query) { return $query->where('status', 'active'); }])->get(); ```
In your examples you pass an array to ::with(['leads as openLeads' => fn ($query) ... ]) |
You are correct. Tried coding freehand in the markdown, clearly not a good idea. Comment has been updated. |
@taylorotwell Maybe a duplicate of PR #31976, i really need this, it´s like If i use framework/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php Lines 375 to 381 in 11387ec
|
Works on nested eager loading |
Can you take a look on this? framework/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php Lines 368 to 379 in 09feffb
|
We should not forget about ->with(['leads:id,name']) as in will this: ->with(['leads:id,name as completedLeads']) still work? Also, I don't know how many in the community know, but: ->with(['leads:id,name as other_name,tilte']) is also a thing. |
Thanks for your pull request to Laravel! Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include. If possible, please consider releasing your code as a package so that the community can still take advantage of your contributions! If you feel absolutely certain that this code corrects a bug in the framework, please "@" mention me in a follow-up comment with further explanation so that GitHub will send me a notification of your response. |
@taylorotwell @donnysim already works with public function testBasicEagerLoadingWithAlias()
{
$user = EloquentTestUser::create(['email' => '[email protected]']);
$user->posts()->create(['name' => 'First Post']);
$user->posts()->create(['name' => 'Second Post']);
$user = EloquentTestUser::with([
'posts:id,user_id,name AS autor',
'posts AS posts1:id,user_id,name AS autor,parent_id',
'posts AS posts2' => function ($q) {
$q->where('name', 'Second Post');
},
])->where('email', '[email protected]')->first();
$this->assertSame('First Post', $user->posts->first()->autor);
$this->assertSame('First Post', $user->posts1->first()->autor);
$this->assertSame('Second Post', $user->posts2->first()->name);
}
|
Different PR for the same feature a little over a year ago, same outcome/response. :( |
Did anybody care to extract this funtionality to a package yet? |
@OzanKurt no, feel free to make it possible |
TLDR
Create pseudo relationship that can be eager loaded:
Current Scenario
Imagine you have a
Salesperson
with manyLead
s.Lead
s have astatus
of "open" or "completed", and aresult
of "sale" or "no sale".You are trying to build a dashboard that shows the
Salesperson
's metrics.It is a simple 1:many relationship between the models.
In your controller you fetch all the
Salesperson
s.In your view you loop through the
Salesperson
s.Because we are calling
->leads()
as a method and not a property (in order to tack on our additional conditions), this will result in new queries being run for each of these groupings, and we don't benefit from the eager loading we did in the controller.There are 2 ways we could currently handle this. We could create additional constrained relationships in the Model:
and then eager load these in the Controller:
This gets rid of our N+1, but the problem with this is it quickly becomes very verbose and unmanageable.
The other option is to filter in PHP (rather than the query) using the returned Collections. In our controller we revert to our simple eager load on the
leads
relationship:and now in our view we use Collection methods to filter out our desired data:
This option benefits from the eager loading, so our query count is very low. However, there is a lot of "logic" in the view, which some people do not like. We also duplicate 2 conditions in our "Close Rate" column that we've already determined. Finally, this does offload the filtering and sorting to PHP rather than the database, which could be undesirable in some scenarios, possibly for performance reasons.
Proposed Improvement
This PR allows us to define eager loaded pseudo relationships. The benefit to this is it avoids our N+1 issues, keeps the filtering and sorting in the database, and keeps the majority of the logic out of the view.
These "relationships" are then available on the models in the view:
Thanks!