From 5d292a2b8a250678206e3c4ec5c4920fef2c526b Mon Sep 17 00:00:00 2001 From: Pavel Borunov <8665691+mrneatly@users.noreply.github.com> Date: Sat, 28 May 2022 09:57:03 +0300 Subject: [PATCH 1/6] Respect new Laravel accessors's approach Fix getting a value from a one-word `\Illuminate\Database\Eloquent\Casts\Attribute`-returning accessors --- src/Eloquent/Model.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 226bc357d..ac11b9ae0 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -155,8 +155,12 @@ public function getAttribute($key) } // This checks for embedded relation support. - if (method_exists($this, $key) && ! method_exists(self::class, $key)) { - return $this->getRelationValue($key); + if ( + method_exists($this, $key) + && ! method_exists(self::class, $key) + && ! $this->hasAttributeGetMutator($key) + ) { + return $this->getRelationValue($key); } return parent::getAttribute($key); From ce693a8cfbea811fe506d540528cda3714e41e99 Mon Sep 17 00:00:00 2001 From: Rosemary Orchard Date: Thu, 25 Aug 2022 14:17:58 +0100 Subject: [PATCH 2/6] Fix formatting --- src/Eloquent/Model.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index ac11b9ae0..0cb303262 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -156,11 +156,11 @@ public function getAttribute($key) // This checks for embedded relation support. if ( - method_exists($this, $key) - && ! method_exists(self::class, $key) - && ! $this->hasAttributeGetMutator($key) - ) { - return $this->getRelationValue($key); + method_exists($this, $key) + && !method_exists(self::class, $key) + && !$this->hasAttributeGetMutator($key) + ) { + return $this->getRelationValue($key); } return parent::getAttribute($key); From 79fad0e9e7bb772ea658e41cc5993370d19a7a39 Mon Sep 17 00:00:00 2001 From: Rosemary Orchard Date: Thu, 25 Aug 2022 14:22:46 +0100 Subject: [PATCH 3/6] More CS-Fixer formatting, unrelated to the PR --- src/Eloquent/Model.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 0cb303262..cf2b3c01b 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -57,15 +57,15 @@ public function getIdAttribute($value = null) { // If we don't have a value for 'id', we will use the Mongo '_id' value. // This allows us to work with models in a more sql-like way. - if (! $value && array_key_exists('_id', $this->attributes)) { + if (!$value && array_key_exists('_id', $this->attributes)) { $value = $this->attributes['_id']; } // Convert ObjectID to string. if ($value instanceof ObjectID) { - return (string) $value; + return (string)$value; } elseif ($value instanceof Binary) { - return (string) $value->getData(); + return (string)$value->getData(); } return $value; @@ -90,7 +90,7 @@ public function fromDateTime($value) } // Let Eloquent convert the value to a DateTime instance. - if (! $value instanceof DateTimeInterface) { + if (!$value instanceof DateTimeInterface) { $value = parent::asDateTime($value); } @@ -145,7 +145,7 @@ public function getTable() */ public function getAttribute($key) { - if (! $key) { + if (!$key) { return; } @@ -216,16 +216,16 @@ public function attributesToArray() // nicely when your models are converted to JSON. foreach ($attributes as $key => &$value) { if ($value instanceof ObjectID) { - $value = (string) $value; + $value = (string)$value; } elseif ($value instanceof Binary) { - $value = (string) $value->getData(); + $value = (string)$value->getData(); } } // Convert dot-notation dates. foreach ($this->getDates() as $key) { if (Str::contains($key, '.') && Arr::has($attributes, $key)) { - Arr::set($attributes, $key, (string) $this->asDateTime(Arr::get($attributes, $key))); + Arr::set($attributes, $key, (string)$this->asDateTime(Arr::get($attributes, $key))); } } @@ -245,7 +245,7 @@ public function getCasts() */ public function originalIsEquivalent($key) { - if (! array_key_exists($key, $this->original)) { + if (!array_key_exists($key, $this->original)) { return false; } @@ -273,7 +273,7 @@ public function originalIsEquivalent($key) } return is_numeric($attribute) && is_numeric($original) - && strcmp((string) $attribute, (string) $original) === 0; + && strcmp((string)$attribute, (string)$original) === 0; } /** @@ -354,7 +354,7 @@ protected function pushAttributeValues($column, array $values, $unique = false) foreach ($values as $value) { // Don't add duplicate values when we only want unique values. - if ($unique && (! is_array($current) || in_array($value, $current))) { + if ($unique && (!is_array($current) || in_array($value, $current))) { continue; } @@ -396,7 +396,7 @@ protected function pullAttributeValues($column, array $values) */ public function getForeignKey() { - return Str::snake(class_basename($this)).'_'.ltrim($this->primaryKey, '_'); + return Str::snake(class_basename($this)) . '_' . ltrim($this->primaryKey, '_'); } /** @@ -461,13 +461,13 @@ public function getQueueableRelations() if ($relation instanceof QueueableCollection) { foreach ($relation->getQueueableRelations() as $collectionValue) { - $relations[] = $key.'.'.$collectionValue; + $relations[] = $key . '.' . $collectionValue; } } if ($relation instanceof QueueableEntity) { foreach ($relation->getQueueableRelations() as $entityKey => $entityValue) { - $relations[] = $key.'.'.$entityValue; + $relations[] = $key . '.' . $entityValue; } } } From e5a8272816b29587c7022276d9ad9ed40cd178e0 Mon Sep 17 00:00:00 2001 From: Rosemary Orchard Date: Thu, 25 Aug 2022 14:25:57 +0100 Subject: [PATCH 4/6] PSR2?! --- src/Eloquent/Model.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index cf2b3c01b..5836cf83d 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -57,15 +57,15 @@ public function getIdAttribute($value = null) { // If we don't have a value for 'id', we will use the Mongo '_id' value. // This allows us to work with models in a more sql-like way. - if (!$value && array_key_exists('_id', $this->attributes)) { + if (! $value && array_key_exists('_id', $this->attributes)) { $value = $this->attributes['_id']; } // Convert ObjectID to string. if ($value instanceof ObjectID) { - return (string)$value; + return (string) $value; } elseif ($value instanceof Binary) { - return (string)$value->getData(); + return (string) $value->getData(); } return $value; @@ -90,7 +90,7 @@ public function fromDateTime($value) } // Let Eloquent convert the value to a DateTime instance. - if (!$value instanceof DateTimeInterface) { + if (! $value instanceof DateTimeInterface) { $value = parent::asDateTime($value); } @@ -145,7 +145,7 @@ public function getTable() */ public function getAttribute($key) { - if (!$key) { + if (! $key) { return; } @@ -157,8 +157,8 @@ public function getAttribute($key) // This checks for embedded relation support. if ( method_exists($this, $key) - && !method_exists(self::class, $key) - && !$this->hasAttributeGetMutator($key) + && ! method_exists(self::class, $key) + && ! $this->hasAttributeGetMutator($key) ) { return $this->getRelationValue($key); } @@ -216,16 +216,16 @@ public function attributesToArray() // nicely when your models are converted to JSON. foreach ($attributes as $key => &$value) { if ($value instanceof ObjectID) { - $value = (string)$value; + $value = (string) $value; } elseif ($value instanceof Binary) { - $value = (string)$value->getData(); + $value = (string) $value->getData(); } } // Convert dot-notation dates. foreach ($this->getDates() as $key) { if (Str::contains($key, '.') && Arr::has($attributes, $key)) { - Arr::set($attributes, $key, (string)$this->asDateTime(Arr::get($attributes, $key))); + Arr::set($attributes, $key, (string) $this->asDateTime(Arr::get($attributes, $key))); } } @@ -245,7 +245,7 @@ public function getCasts() */ public function originalIsEquivalent($key) { - if (!array_key_exists($key, $this->original)) { + if (! array_key_exists($key, $this->original)) { return false; } @@ -273,7 +273,7 @@ public function originalIsEquivalent($key) } return is_numeric($attribute) && is_numeric($original) - && strcmp((string)$attribute, (string)$original) === 0; + && strcmp((string) $attribute, (string) $original) === 0; } /** @@ -354,7 +354,7 @@ protected function pushAttributeValues($column, array $values, $unique = false) foreach ($values as $value) { // Don't add duplicate values when we only want unique values. - if ($unique && (!is_array($current) || in_array($value, $current))) { + if ($unique && (! is_array($current) || in_array($value, $current))) { continue; } @@ -396,7 +396,7 @@ protected function pullAttributeValues($column, array $values) */ public function getForeignKey() { - return Str::snake(class_basename($this)) . '_' . ltrim($this->primaryKey, '_'); + return Str::snake(class_basename($this)).'_'.ltrim($this->primaryKey, '_'); } /** @@ -461,13 +461,13 @@ public function getQueueableRelations() if ($relation instanceof QueueableCollection) { foreach ($relation->getQueueableRelations() as $collectionValue) { - $relations[] = $key . '.' . $collectionValue; + $relations[] = $key.'.'.$collectionValue; } } if ($relation instanceof QueueableEntity) { foreach ($relation->getQueueableRelations() as $entityKey => $entityValue) { - $relations[] = $key . '.' . $entityValue; + $relations[] = $key.'.'.$entityValue; } } } From 6b11977468929e744bd07d9eba827b513e49fd04 Mon Sep 17 00:00:00 2001 From: Rosemary Orchard Date: Thu, 25 Aug 2022 14:17:58 +0100 Subject: [PATCH 5/6] Fix formatting More CS-Fixer formatting, unrelated to the PR PSR2?! --- src/Eloquent/Model.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index ac11b9ae0..5836cf83d 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -156,11 +156,11 @@ public function getAttribute($key) // This checks for embedded relation support. if ( - method_exists($this, $key) - && ! method_exists(self::class, $key) - && ! $this->hasAttributeGetMutator($key) - ) { - return $this->getRelationValue($key); + method_exists($this, $key) + && ! method_exists(self::class, $key) + && ! $this->hasAttributeGetMutator($key) + ) { + return $this->getRelationValue($key); } return parent::getAttribute($key); From c27924cff38c264db95dd7317daef3addfd154e1 Mon Sep 17 00:00:00 2001 From: Rosemary Orchard Date: Thu, 25 Aug 2022 17:11:29 +0100 Subject: [PATCH 6/6] Add tests for the mutator --- tests/ModelTest.php | 18 ++++++++++++++++++ tests/models/User.php | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/ModelTest.php b/tests/ModelTest.php index 75723c1cb..9e8f60fea 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Date; +use Illuminate\Support\Str; use Jenssegers\Mongodb\Collection; use Jenssegers\Mongodb\Connection; use Jenssegers\Mongodb\Eloquent\Model; @@ -678,6 +679,23 @@ public function testDotNotation(): void $this->assertEquals('Strasbourg', $user['address.city']); } + public function testAttributeMutator(): void + { + $username = 'JaneDoe'; + $usernameSlug = Str::slug($username); + $user = User::create([ + 'name' => 'Jane Doe', + 'username' => $username, + ]); + + $this->assertNotEquals($username, $user->getAttribute('username')); + $this->assertNotEquals($username, $user['username']); + $this->assertNotEquals($username, $user->username); + $this->assertEquals($usernameSlug, $user->getAttribute('username')); + $this->assertEquals($usernameSlug, $user['username']); + $this->assertEquals($usernameSlug, $user->username); + } + public function testMultipleLevelDotNotation(): void { /** @var Book $book */ diff --git a/tests/models/User.php b/tests/models/User.php index ff96b89e4..b394ea6e7 100644 --- a/tests/models/User.php +++ b/tests/models/User.php @@ -6,7 +6,9 @@ use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Str; use Jenssegers\Mongodb\Eloquent\HybridRelations; use Jenssegers\Mongodb\Eloquent\Model as Eloquent; @@ -21,10 +23,14 @@ * @property \Carbon\Carbon $birthday * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at + * @property string $username */ class User extends Eloquent implements AuthenticatableContract, CanResetPasswordContract { - use Authenticatable, CanResetPassword, HybridRelations, Notifiable; + use Authenticatable; + use CanResetPassword; + use HybridRelations; + use Notifiable; protected $connection = 'mongodb'; protected $dates = ['birthday', 'entry.date']; @@ -84,4 +90,12 @@ protected function serializeDate(DateTimeInterface $date) { return $date->format('l jS \of F Y h:i:s A'); } + + protected function username(): Attribute + { + return Attribute::make( + get: fn ($value) => $value, + set: fn ($value) => Str::slug($value) + ); + } }