Skip to content

Commit c0d9735

Browse files
committed
Adjust attribute cast determination
1 parent a6b3868 commit c0d9735

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ trait HasAttributes
148148
*/
149149
protected static $attributeMutatorCache = [];
150150

151+
/**
152+
* The cache of the "Attribute" return type marked mutated, gettable attributes for each class.
153+
*
154+
* @var array
155+
*/
156+
protected static $getAttributeMutatorCache = [];
157+
151158
/**
152159
* The cache of the "Attribute" return type marked mutated, settable attributes for each class.
153160
*
@@ -418,7 +425,7 @@ public function getAttribute($key)
418425
if (array_key_exists($key, $this->attributes) ||
419426
array_key_exists($key, $this->casts) ||
420427
$this->hasGetMutator($key) ||
421-
$this->hasAttributeGetMutator($key) ||
428+
$this->hasAttributeMutator($key) ||
422429
$this->isClassCastable($key)) {
423430
return $this->getAttributeValue($key);
424431
}
@@ -552,12 +559,12 @@ public function hasGetMutator($key)
552559
}
553560

554561
/**
555-
* Determine if a "Attribute" return type marked get mutator exists for an attribute.
562+
* Determine if a "Attribute" return type marked mutator exists for an attribute.
556563
*
557564
* @param string $key
558565
* @return bool
559566
*/
560-
public function hasAttributeGetMutator($key)
567+
public function hasAttributeMutator($key)
561568
{
562569
if (isset(static::$attributeMutatorCache[get_class($this)][$key])) {
563570
return static::$attributeMutatorCache[get_class($this)][$key];
@@ -574,6 +581,25 @@ public function hasAttributeGetMutator($key)
574581
$returnType->getName() === Attribute::class;
575582
}
576583

584+
/**
585+
* Determine if a "Attribute" return type marked get mutator exists for an attribute.
586+
*
587+
* @param string $key
588+
* @return bool
589+
*/
590+
public function hasAttributeGetMutator($key)
591+
{
592+
if (isset(static::$getAttributeMutatorCache[get_class($this)][$key])) {
593+
return static::$getAttributeMutatorCache[get_class($this)][$key];
594+
}
595+
596+
if (! $this->hasAttributeMutator($key)) {
597+
return static::$getAttributeMutatorCache[get_class($this)][$key] = false;
598+
}
599+
600+
return static::$getAttributeMutatorCache[get_class($this)][$key] = is_callable($this->{Str::camel($key)}()->get);
601+
}
602+
577603
/**
578604
* Get the value of an attribute using its mutator.
579605
*
@@ -623,8 +649,8 @@ protected function mutateAttributeForArray($key, $value)
623649
{
624650
if ($this->isClassCastable($key)) {
625651
$value = $this->getClassCastableAttributeValue($key, $value);
626-
} elseif (isset(static::$attributeMutatorCache[get_class($this)][$key]) &&
627-
static::$attributeMutatorCache[get_class($this)][$key] === true) {
652+
} elseif (isset(static::$getAttributeMutatorCache[get_class($this)][$key]) &&
653+
static::$getAttributeMutatorCache[get_class($this)][$key] === true) {
628654
$value = $this->mutateAttributeMarkedAttribute($key, $value);
629655

630656
$value = $value instanceof DateTimeInterface
@@ -948,7 +974,8 @@ public function hasAttributeSetMutator($key)
948974

949975
return static::$setAttributeMutatorCache[$class][$key] = $returnType &&
950976
$returnType instanceof ReflectionNamedType &&
951-
$returnType->getName() === Attribute::class;
977+
$returnType->getName() === Attribute::class &&
978+
is_callable($this->{$method}()->set);
952979
}
953980

954981
/**
@@ -2029,7 +2056,7 @@ public function getMutatedAttributes()
20292056
*/
20302057
public static function cacheMutatedAttributes($class)
20312058
{
2032-
static::$attributeMutatorCache[$class] =
2059+
static::$getAttributeMutatorCache[$class] =
20332060
collect($attributeMutatorMethods = static::getAttributeMarkedMutatorMethods($class))
20342061
->mapWithKeys(function ($match) {
20352062
return [lcfirst(static::$snakeAttributes ? Str::snake($match) : $match) => true];

tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ public function testModelsAreProperlyMatchedToParents()
2323
$model1->shouldReceive('getAttribute')->with('parent_key')->andReturn(1);
2424
$model1->shouldReceive('getAttribute')->with('foo')->passthru();
2525
$model1->shouldReceive('hasGetMutator')->andReturn(false);
26-
$model1->shouldReceive('hasAttributeGetMutator')->andReturn(false);
26+
$model1->shouldReceive('hasAttributeMutator')->andReturn(false);
2727
$model1->shouldReceive('getCasts')->andReturn([]);
2828
$model1->shouldReceive('getRelationValue', 'relationLoaded', 'setRelation', 'isRelation')->passthru();
2929

3030
$model2 = m::mock(Model::class);
3131
$model2->shouldReceive('getAttribute')->with('parent_key')->andReturn(2);
3232
$model2->shouldReceive('getAttribute')->with('foo')->passthru();
3333
$model2->shouldReceive('hasGetMutator')->andReturn(false);
34-
$model2->shouldReceive('hasAttributeGetMutator')->andReturn(false);
34+
$model2->shouldReceive('hasAttributeMutator')->andReturn(false);
3535
$model2->shouldReceive('getCasts')->andReturn([]);
3636
$model2->shouldReceive('getRelationValue', 'relationLoaded', 'setRelation', 'isRelation')->passthru();
3737

0 commit comments

Comments
 (0)