Repository: laravel/framework (php)

Issue:
Castable value object is not serialized correctly
<!-- DO NOT THROW THIS AWAY -->
<!-- Fill out the FULL versions with patch versions -->

- Laravel Version: 8.61.0
- PHP Version: 8.0.3
- Database Driver & Version: MYSQL

### Description:

Anonymous cast class is not invoked during serialization although `serialize` method is implemented.

Related docs:

- https://laravel.com/docs/8.x/eloquent-mutators#anonymous-cast-classes
- https://laravel.com/docs/8.x/eloquent-mutators#array-json-serialization

### Steps To Reproduce:

```php
class Product extends Model
{
    public $timestamps = false;

    protected $casts = [
        'sku' => Sku::class,
    ];
}

class Sku implements Castable
{
    private string $sku;

    public function __construct(string $sku)
    {
        $this->sku = $sku;
    }

    public function getValue()
    {
        return $this->sku;
    }

    public static function castUsing(array $arguments)
    {
        return new class implements CastsAttributes, SerializesCastableAttributes
        {
            public function get($model, string $key, $value, array $attributes)
            {
                return new Sku($value);
            }

            public function set($model, string $key, $value, array $attributes)
            {
                return $value->getValue();
            }

            public function serialize($model, string $key, $value, array $attributes)
            {
                return $value->getValue();
            }
        };
    }
}

$product = new Product();
$product->sku = new Sku('UGG-BB-PUR-06');
$product->save();

dump(Product::all()->toArray()); 
```

This is what i'm getting:

```
^ array:1 [
  0 => array:2 [
    "id" => 1
    "sku" => Sku^ {#19
      -sku: "UGG-BB-PUR-06"
    }
  ]
]
```

This is what i should be getting:

```
^ array:1 [
  0 => array:2 [
    "id" => 1
    "sku" => "UGG-BB-PUR-06"
  ]
]
```

<!-- If possible, please provide a GitHub repository to demonstrate your issue -->
<!-- laravel new bug-report --github="--public" -->


Pull request:
Fix castable value object not serialized correctly
Fixes #38811

Patch:
diff --git a/CHANGELOG-8.x.md b/CHANGELOG-8.x.md
index 941ca0664f..3bb502a375 100644
--- a/CHANGELOG-8.x.md
+++ b/CHANGELOG-8.x.md
@@ -1,6 +1,38 @@
 # Release Notes for 8.x
 
-## [Unreleased](https://github.com/laravel/framework/compare/v8.61.0...8.x)
+## [Unreleased](https://github.com/laravel/framework/compare/v8.62.0...8.x)
+
+
+## [v8.62.0 (2021-09-28)](https://github.com/laravel/framework/compare/v8.61.0...v8.62.0)
+
+### Added
+- Added singular syntactic sugar to wormhole ([#38815](https://github.com/laravel/framework/pull/38815))
+- Added a few PHP 8.1 related changes ([#38404](https://github.com/laravel/framework/pull/38404), [#38961](https://github.com/laravel/framework/pull/38961))
+- Dispatch events when maintenance mode is enabled and disabled ([#38826](https://github.com/laravel/framework/pull/38826))
+- Added assertNotSoftDeleted Method ([#38886](https://github.com/laravel/framework/pull/38886))
+- Adds new RefreshDatabaseLazily testing trait ([#38861](https://github.com/laravel/framework/pull/38861))
+- Added --pretend option for model:prune command ([#38945](https://github.com/laravel/framework/pull/38945))
+- Make PendingMail Conditionable ([#38942](https://github.com/laravel/framework/pull/38942))
+- Adds --pest option when using the make:test artisan command ([#38966](https://github.com/laravel/framework/pull/38966))
+
+### Reverted
+- Reverted ["Added posibility compare custom date/immutable_date using date comparison"](https://github.com/laravel/framework/pull/38720) ([#38993](https://github.com/laravel/framework/pull/38993))
+
+### Fixed
+- Fix getDirty method when using AsArrayObject / AsCollection ([#38869](https://github.com/laravel/framework/pull/38869))
+- Fix sometimes conditions that add rules for sibling values within an array of data ([#38899](https://github.com/laravel/framework/pull/38899))
+- Fixed Illuminate/Validation/Rules/Password::passes() ([#38962](https://github.com/laravel/framework/pull/38962))
+- Fixed for custom date castable and database value formatting ([#38994](https://github.com/laravel/framework/pull/38994))
+
+### Changed
+- Make mailable assertions fluent ([#38850](https://github.com/laravel/framework/pull/38850))
+- Allow request input to be retrieved as a collection ([#38832](https://github.com/laravel/framework/pull/38832))
+- Allow index.blade.php views for anonymous components ([#38847](https://github.com/laravel/framework/pull/38847))
+- Changed *ofMany to decide relationship name when it is null ([#38889](https://github.com/laravel/framework/pull/38889))
+- Ignore trailing delimiter in cache.headers options string ([#38910](https://github.com/laravel/framework/pull/38910))
+- Only look for files ending with .php in model:prune ([#38975](https://github.com/laravel/framework/pull/38975))
+- Notification assertions respect shouldSend method on notification ([#38979](https://github.com/laravel/framework/pull/38979))
+- Convert middleware to array when outputting as JSON in /RouteListCommand ([#38953](https://github.com/laravel/framework/pull/38953))
 
 
 ## [v8.61.0 (2021-09-13)](https://github.com/laravel/framework/compare/v8.60.0...v8.61.0)
diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
index 14baa4d22a..22dde6e6f9 100644
--- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
+++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
@@ -1308,7 +1308,7 @@ protected function isClassDeviable($key)
     protected function isClassSerializable($key)
     {
         return $this->isClassCastable($key) &&
-            method_exists($this->parseCasterClass($this->getCasts()[$key]), 'serialize');
+            method_exists($this->resolveCasterClass($key), 'serialize');
     }
 
     /**


Test patch:
diff --git a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php
index 474b5682fc..87133f6d43 100644
--- a/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php
+++ b/tests/Integration/Database/DatabaseEloquentModelCustomCastingTest.php
@@ -230,6 +230,7 @@ public function testWithCastableInterface()
         ]);
 
         $this->assertInstanceOf(ValueObject::class, $model->value_object_with_caster);
+        $this->assertSame(serialize(new ValueObject('hello')), $model->toArray()['value_object_with_caster']);
 
         $model->setRawAttributes([
             'value_object_caster_with_argument' => null,
@@ -418,7 +419,7 @@ public function __construct(string $name)
 
     public static function castUsing(array $arguments)
     {
-        return new class(...$arguments) implements CastsAttributes
+        return new class(...$arguments) implements CastsAttributes, SerializesCastableAttributes
         {
             private $argument;
 
@@ -440,6 +441,11 @@ public function set($model, $key, $value, $attributes)
             {
                 return serialize($value);
             }
+
+            public function serialize($model, $key, $value, $attributes)
+            {
+                return serialize($value);
+            }
         };
     }
 }