diff --git a/src/Illuminate/Contracts/Database/Eloquent/Castable.php b/src/Illuminate/Contracts/Database/Eloquent/Castable.php index e3f1bccda411..8656646f14da 100644 --- a/src/Illuminate/Contracts/Database/Eloquent/Castable.php +++ b/src/Illuminate/Contracts/Database/Eloquent/Castable.php @@ -7,7 +7,7 @@ interface Castable /** * Get the name of the caster class to use when casting from / to this cast target. * - * @return string + * @return string|\Illuminate\Contracts\Database\Eloquent\CastsAttributes|\Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes */ public static function castUsing(); } diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 609ff1f65c79..b01069f4f5a6 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1066,7 +1066,7 @@ protected function resolveCasterClass($key) $arguments = []; - if (strpos($castType, ':') !== false) { + if (is_string($castType) && strpos($castType, ':') !== false) { $segments = explode(':', $castType, 2); $castType = $segments[0]; @@ -1077,6 +1077,10 @@ protected function resolveCasterClass($key) $castType = $castType::castUsing(); } + if (is_object($castType)) { + return $castType; + } + return new $castType(...$arguments); } diff --git a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php index 2e72a54910dc..5df983887fd8 100644 --- a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php +++ b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php @@ -130,6 +130,12 @@ public function testWithCastableInterface() ]); $this->assertEquals('argument', $model->value_object_caster_with_argument); + + $model->setRawAttributes([ + 'value_object_caster_with_caster_instance' => serialize(new ValueObject('hello')), + ]); + + $this->assertInstanceOf(ValueObject::class, $model->value_object_caster_with_caster_instance); } } @@ -155,6 +161,7 @@ class TestEloquentModelWithCustomCast extends Model 'options' => JsonCaster::class, 'value_object_with_caster' => ValueObject::class, 'value_object_caster_with_argument' => ValueObject::class.':argument', + 'value_object_caster_with_caster_instance' => ValueObjectWithCasterInstance::class, ]; } @@ -249,6 +256,14 @@ public static function castUsing() } } +class ValueObjectWithCasterInstance extends ValueObject +{ + public static function castUsing() + { + return new ValueObjectCaster(); + } +} + class Address { public $lineOne;