From dae1ab2b60e22a3bbee4c50beee179a86c894cbf Mon Sep 17 00:00:00 2001 From: Sami Mazouz Date: Fri, 13 Dec 2024 11:35:45 +0100 Subject: [PATCH] [11.x] Fix mutator access in `loadMissing` --- .../Database/Eloquent/Collection.php | 2 +- .../Database/EloquentModelLoadMissingTest.php | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 022e27dcc6c2..e5c6c383addb 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -271,7 +271,7 @@ protected function loadMissingRelation(self $models, array $path) return; } - $models = $models->pluck($name)->whereNotNull(); + $models = $models->pluck($name)->filter(); if ($models->first() instanceof BaseCollection) { $models = $models->collapse(); diff --git a/tests/Integration/Database/EloquentModelLoadMissingTest.php b/tests/Integration/Database/EloquentModelLoadMissingTest.php index eb4983b432a1..939b8c231b62 100644 --- a/tests/Integration/Database/EloquentModelLoadMissingTest.php +++ b/tests/Integration/Database/EloquentModelLoadMissingTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Integration\Database\EloquentModelLoadMissingTest; use DB; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; @@ -12,20 +13,40 @@ class EloquentModelLoadMissingTest extends DatabaseTestCase { protected function afterRefreshingDatabase() { + Schema::create('users', function (Blueprint $table) { + $table->increments('id'); + $table->string('name'); + }); + + Schema::create('comment_mentions_users', function (Blueprint $table) { + $table->unsignedInteger('comment_id'); + $table->unsignedInteger('user_id'); + }); + Schema::create('posts', function (Blueprint $table) { $table->increments('id'); + $table->unsignedInteger('first_comment_id')->nullable(); + $table->string('content')->nullable(); }); Schema::create('comments', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('parent_id')->nullable(); $table->unsignedInteger('post_id'); + $table->string('content')->nullable(); }); Post::create(); - Comment::create(['parent_id' => null, 'post_id' => 1]); + Comment::create(['parent_id' => null, 'post_id' => 1, 'content' => 'Hello ']); Comment::create(['parent_id' => 1, 'post_id' => 1]); + + User::create(['name' => 'Taylor']); + User::create(['name' => 'Otwell']); + + Comment::first()->mentionsUsers()->attach([1, 2]); + + Post::first()->update(['first_comment_id' => 1]); } public function testLoadMissing() @@ -39,6 +60,17 @@ public function testLoadMissing() $this->assertCount(1, DB::getQueryLog()); $this->assertTrue($post->comments[0]->relationLoaded('parent')); } + + public function testLoadMissingNoUnnecessaryAttributeMutatorAccess() + { + $posts = Post::all(); + + DB::enableQueryLog(); + + $posts->loadMissing('firstComment.parent'); + + $this->assertCount(1, DB::getQueryLog()); + } } class Comment extends Model @@ -51,14 +83,42 @@ public function parent() { return $this->belongsTo(self::class); } + + public function mentionsUsers() + { + return $this->belongsToMany(User::class, 'comment_mentions_users'); + } + + public function content(): Attribute + { + return new Attribute(function (?string $value) { + return preg_replace_callback('//', function ($matches) { + return '@'.$this->mentionsUsers->find($matches[1])?->name; + }, $value); + }); + } } class Post extends Model { public $timestamps = false; + protected $guarded = []; + public function comments() { return $this->hasMany(Comment::class); } + + public function firstComment() + { + return $this->belongsTo(Comment::class, 'first_comment_id'); + } +} + +class User extends Model +{ + public $timestamps = false; + + protected $guarded = []; }