From 51000ec86d0479dc8807f8df437d14835e3d3db8 Mon Sep 17 00:00:00 2001 From: Tim Geisendoerfer Date: Mon, 24 Oct 2022 19:02:04 +0200 Subject: [PATCH 1/3] add hasAttribute method to HasAttributes eloquent concern --- .../Eloquent/Concerns/HasAttributes.php | 43 +++++++++++--- ...tBelongsToManyWithCastedAttributesTest.php | 2 + tests/Database/DatabaseEloquentModelTest.php | 58 +++++++++++++++++++ 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 5225cc01207f..abdc1cf94847 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -265,6 +265,40 @@ protected function addMutatedAttributesToArray(array $attributes, array $mutated return $attributes; } + /** + * Check if model has a given attribute. + * + * @param string $key + * @return bool + */ + public function hasAttribute($key) + { + // If the attribute exists in the attribute array or has a "get" mutator we will + // return the attribute's value. Otherwise, we will proceed as if the developers + // are asking for a relationship's value. This covers both types of values. + if (array_key_exists($key, $this->attributes)) { + return true; + } + + if (array_key_exists($key, $this->casts)) { + return true; + } + + if ($this->hasGetMutator($key)) { + return true; + } + + if ($this->hasAttributeMutator($key)) { + return true; + } + + if ($this->isClassCastable($key)) { + return true; + } + + return false; + } + /** * Add the casted attributes to the attributes array. * @@ -431,14 +465,7 @@ public function getAttribute($key) return; } - // If the attribute exists in the attribute array or has a "get" mutator we will - // get the attribute's value. Otherwise, we will proceed as if the developers - // are asking for a relationship's value. This covers both types of values. - if (array_key_exists($key, $this->attributes) || - array_key_exists($key, $this->casts) || - $this->hasGetMutator($key) || - $this->hasAttributeMutator($key) || - $this->isClassCastable($key)) { + if($this->hasAttribute($key)) { return $this->getAttributeValue($key); } diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php index 4432a5bc6846..9917d537371f 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -20,6 +20,7 @@ public function testModelsAreProperlyMatchedToParents() { $relation = $this->getRelation(); $model1 = m::mock(Model::class); + $model1->shouldReceive('hasAttribute')->passthru(); $model1->shouldReceive('getAttribute')->with('parent_key')->andReturn(1); $model1->shouldReceive('getAttribute')->with('foo')->passthru(); $model1->shouldReceive('hasGetMutator')->andReturn(false); @@ -28,6 +29,7 @@ public function testModelsAreProperlyMatchedToParents() $model1->shouldReceive('getRelationValue', 'relationLoaded', 'setRelation', 'isRelation')->passthru(); $model2 = m::mock(Model::class); + $model2->shouldReceive('hasAttribute')->passthru(); $model2->shouldReceive('getAttribute')->with('parent_key')->andReturn(2); $model2->shouldReceive('getAttribute')->with('foo')->passthru(); $model2->shouldReceive('hasGetMutator')->andReturn(false); diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 5c8cdea6f5af..be867fc12ca0 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -20,6 +20,7 @@ use Illuminate\Database\Eloquent\Casts\AsEncryptedArrayObject; use Illuminate\Database\Eloquent\Casts\AsEncryptedCollection; use Illuminate\Database\Eloquent\Casts\AsStringable; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\JsonEncodingException; use Illuminate\Database\Eloquent\MassAssignmentException; @@ -373,6 +374,49 @@ public function testOnly() $this->assertEquals(['first_name' => 'taylor', 'last_name' => 'otwell'], $model->only(['first_name', 'last_name'])); } + public function testHasAttributeWithAttributes() + { + $model = new EloquentModelStub; + $model->first_name = 'Taylor'; + $model->last_name = 'Otwell'; + + $this->assertTrue($model->hasAttribute('first_name')); + $this->assertTrue($model->hasAttribute('last_name')); + $this->assertFalse($model->hasAttribute('project')); + } + + public function testHasAttributeWithCasts() + { + $model = new EloquentModelStub; + + $this->assertTrue($model->hasAttribute('castedFloat')); + $this->assertFalse($model->hasAttribute('project')); + } + + public function testHasAttributeWithGetMutators() + { + $model = new EloquentModelGetMutatorsStub(); + + $this->assertTrue($model->hasAttribute('first_name')); + $this->assertFalse($model->hasAttribute('project')); + } + + public function testHasAttributeWithAttributeMutators() + { + $model = new EloquentModelWithAttributeMutator(); + + $this->assertTrue($model->hasAttribute('first_name')); + $this->assertFalse($model->hasAttribute('project')); + } + + public function testHasAttributeWithCastableCast() + { + $model = new EloquentModelCastingStub(); + + $this->assertTrue($model->hasAttribute('asarrayobjectAttribute')); + $this->assertFalse($model->hasAttribute('project')); + } + public function testNewInstanceReturnsNewInstanceWithAttributesSet() { $model = new EloquentModelStub; @@ -3047,6 +3091,20 @@ class EloquentModelWithUpdatedAtNull extends Model const UPDATED_AT = null; } +class EloquentModelWithAttributeMutator extends Model +{ + protected $table = 'stub'; + + public function firstName(): Attribute + { + return Attribute::make(function (){ + return 'Taylor'; + },function ($value){ + return $value; + }); + } +} + class UnsavedModel extends Model { protected $casts = ['name' => Uppercase::class]; From 744991290201bfbb7f2bea04895fd2e6220be204 Mon Sep 17 00:00:00 2001 From: Tim Geisendoerfer Date: Wed, 26 Oct 2022 18:55:49 +0200 Subject: [PATCH 2/3] cs fixes --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 4 ++-- tests/Database/DatabaseEloquentModelTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index abdc1cf94847..fd2a9af19554 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -268,7 +268,7 @@ protected function addMutatedAttributesToArray(array $attributes, array $mutated /** * Check if model has a given attribute. * - * @param string $key + * @param string $key * @return bool */ public function hasAttribute($key) @@ -465,7 +465,7 @@ public function getAttribute($key) return; } - if($this->hasAttribute($key)) { + if ($this->hasAttribute($key)) { return $this->getAttributeValue($key); } diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index be867fc12ca0..3ddc482c2595 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -3097,9 +3097,9 @@ class EloquentModelWithAttributeMutator extends Model public function firstName(): Attribute { - return Attribute::make(function (){ + return Attribute::make(function () { return 'Taylor'; - },function ($value){ + }, function ($value) { return $value; }); } From f1dbce13027c489aa49114d4414454dcf3b24278 Mon Sep 17 00:00:00 2001 From: Tim Geisendoerfer Date: Wed, 26 Oct 2022 19:00:30 +0200 Subject: [PATCH 3/3] fix comments --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index fd2a9af19554..3206de9a74a1 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -273,9 +273,6 @@ protected function addMutatedAttributesToArray(array $attributes, array $mutated */ public function hasAttribute($key) { - // If the attribute exists in the attribute array or has a "get" mutator we will - // return the attribute's value. Otherwise, we will proceed as if the developers - // are asking for a relationship's value. This covers both types of values. if (array_key_exists($key, $this->attributes)) { return true; } @@ -465,6 +462,9 @@ public function getAttribute($key) return; } + // If the attribute exists in the attribute array or has a "get" mutator we will + // return the attribute's value. Otherwise, we will proceed as if the developers + // are asking for a relationship's value. This covers both types of values. if ($this->hasAttribute($key)) { return $this->getAttributeValue($key); }