Skip to content

Commit a46c765

Browse files
angus-mcritchieAngus McRitchietaylorotwell
authored
[12.x] Add support for nested array notation within loadMissing (#56711)
* init * fix colon select test --------- Co-authored-by: Angus McRitchie <[email protected]> Co-authored-by: Taylor Otwell <[email protected]>
1 parent a8b554d commit a46c765

File tree

2 files changed

+135
-16
lines changed

2 files changed

+135
-16
lines changed

src/Illuminate/Database/Eloquent/Collection.php

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -222,28 +222,29 @@ public function loadMissing($relations)
222222
$relations = func_get_args();
223223
}
224224

225-
foreach ($relations as $key => $value) {
226-
if (is_numeric($key)) {
227-
$key = $value;
228-
}
225+
if ($this->isNotEmpty()) {
226+
$query = $this->first()->newQueryWithoutRelationships()->with($relations);
229227

230-
$segments = explode('.', explode(':', $key)[0]);
228+
foreach ($query->getEagerLoads() as $key => $value) {
229+
$segments = explode('.', explode(':', $key)[0]);
231230

232-
if (str_contains($key, ':')) {
233-
$segments[count($segments) - 1] .= ':'.explode(':', $key)[1];
234-
}
231+
if (str_contains($key, ':')) {
232+
$segments[count($segments) - 1] .= ':'.explode(':', $key)[1];
233+
}
235234

236-
$path = [];
235+
$path = [];
237236

238-
foreach ($segments as $segment) {
239-
$path[] = [$segment => $segment];
240-
}
237+
foreach ($segments as $segment) {
238+
$path[] = [$segment => $segment];
239+
}
241240

242-
if (is_callable($value)) {
243-
$path[count($segments) - 1][array_last($segments)] = $value;
244-
}
241+
if (is_callable($value)) {
242+
$path[count($segments) - 1][array_last($segments)] = $value;
243+
}
245244

246-
$this->loadMissingRelation($this, $path);
245+
246+
$this->loadMissingRelation($this, $path);
247+
}
247248
}
248249

249250
return $this;

tests/Integration/Database/EloquentCollectionLoadMissingTest.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,123 @@ public function testLoadMissingWithoutInitialLoad()
118118
$this->assertEquals(1, $user->posts[1]->postRelation->postSubRelations[0]->postSubSubRelations->count());
119119
$this->assertInstanceOf(PostSubSubRelation::class, $user->posts[1]->postRelation->postSubRelations[0]->postSubSubRelations[0]);
120120
}
121+
122+
public function testLoadMissingWithNestedArraySyntax()
123+
{
124+
$posts = Post::with('user')->get();
125+
126+
DB::enableQueryLog();
127+
128+
$posts->loadMissing([
129+
'comments' => ['parent'],
130+
'user',
131+
]);
132+
133+
$this->assertCount(2, DB::getQueryLog());
134+
$this->assertTrue($posts[0]->comments[0]->relationLoaded('parent'));
135+
$this->assertTrue($posts[0]->relationLoaded('user'));
136+
}
137+
138+
public function testLoadMissingWithMultipleDotNotationRelations()
139+
{
140+
$posts = Post::with('comments')->get();
141+
142+
DB::enableQueryLog();
143+
144+
$posts->loadMissing([
145+
'comments.parent',
146+
'user.posts',
147+
]);
148+
149+
$this->assertCount(3, DB::getQueryLog());
150+
$this->assertTrue($posts[0]->comments[0]->relationLoaded('parent'));
151+
$this->assertTrue($posts[0]->relationLoaded('user'));
152+
$this->assertTrue($posts[0]->user->relationLoaded('posts'));
153+
}
154+
155+
public function testLoadMissingWithNestedArrayWithColon()
156+
{
157+
$posts = Post::with('comments')->get();
158+
159+
DB::enableQueryLog();
160+
161+
$posts->loadMissing(['comments' => ['parent:id']]);
162+
163+
$this->assertCount(1, DB::getQueryLog());
164+
$this->assertTrue($posts[0]->comments[0]->relationLoaded('parent'));
165+
$this->assertArrayNotHasKey('post_id', $posts[0]->comments[1]->parent->getAttributes());
166+
}
167+
168+
public function testLoadMissingWithNestedArray()
169+
{
170+
$posts = Post::with('comments')->get();
171+
172+
DB::enableQueryLog();
173+
174+
$posts->loadMissing(['comments' => ['parent']]);
175+
176+
$this->assertCount(1, DB::getQueryLog());
177+
$this->assertTrue($posts[0]->comments[0]->relationLoaded('parent'));
178+
}
179+
180+
public function testLoadMissingWithNestedArrayWithClosure()
181+
{
182+
$posts = Post::with('comments')->get();
183+
184+
DB::enableQueryLog();
185+
186+
$posts->loadMissing(['comments' => ['parent' => function ($query) {
187+
$query->select('id');
188+
}]]);
189+
190+
$this->assertCount(1, DB::getQueryLog());
191+
$this->assertTrue($posts[0]->comments[0]->relationLoaded('parent'));
192+
$this->assertArrayNotHasKey('post_id', $posts[0]->comments[1]->parent->getAttributes());
193+
}
194+
195+
public function testLoadMissingWithMultipleNestedArrays()
196+
{
197+
$users = User::get();
198+
$users->loadMissing([
199+
'posts' => [
200+
'postRelation' => [
201+
'postSubRelations' => [
202+
'postSubSubRelations',
203+
],
204+
],
205+
],
206+
]);
207+
208+
$user = $users->first();
209+
$this->assertEquals(2, $user->posts->count());
210+
$this->assertNull($user->posts[0]->postRelation);
211+
$this->assertInstanceOf(PostRelation::class, $user->posts[1]->postRelation);
212+
$this->assertEquals(1, $user->posts[1]->postRelation->postSubRelations->count());
213+
$this->assertInstanceOf(PostSubRelation::class, $user->posts[1]->postRelation->postSubRelations[0]);
214+
$this->assertEquals(1, $user->posts[1]->postRelation->postSubRelations[0]->postSubSubRelations->count());
215+
$this->assertInstanceOf(PostSubSubRelation::class, $user->posts[1]->postRelation->postSubRelations[0]->postSubSubRelations[0]);
216+
}
217+
218+
public function testLoadMissingWithMultipleNestedArraysCombinedWithDotNotation()
219+
{
220+
$users = User::get();
221+
$users->loadMissing([
222+
'posts' => [
223+
'postRelation' => [
224+
'postSubRelations.postSubSubRelations',
225+
],
226+
],
227+
]);
228+
229+
$user = $users->first();
230+
$this->assertEquals(2, $user->posts->count());
231+
$this->assertNull($user->posts[0]->postRelation);
232+
$this->assertInstanceOf(PostRelation::class, $user->posts[1]->postRelation);
233+
$this->assertEquals(1, $user->posts[1]->postRelation->postSubRelations->count());
234+
$this->assertInstanceOf(PostSubRelation::class, $user->posts[1]->postRelation->postSubRelations[0]);
235+
$this->assertEquals(1, $user->posts[1]->postRelation->postSubRelations[0]->postSubSubRelations->count());
236+
$this->assertInstanceOf(PostSubSubRelation::class, $user->posts[1]->postRelation->postSubRelations[0]->postSubSubRelations[0]);
237+
}
121238
}
122239

123240
class Comment extends Model
@@ -200,6 +317,7 @@ class Revision extends Model
200317
class User extends Model
201318
{
202319
public $timestamps = false;
320+
protected $guarded = [];
203321

204322
public function posts()
205323
{

0 commit comments

Comments
 (0)