Description
Laravel Version
12.15.0
PHP Version
8.3.20
Database Driver & Version
No response
Description
When calling toJson()
or jsonSerialize()
on an Eloquent model that has loaded relationships, the jsonSerialize()
method of the related model(s) is not invoked. Instead, the default serialization behavior is used for the related models, which bypasses any custom serialization logic defined in their jsonSerialize()
method.
This is inconsistent with what happens when the related model is serialized independently, where jsonSerialize()
is correctly called.
This makes it impossible to customize the JSON representation of related models when serializing the parent, which is unexpected and inconsistent.
Steps To Reproduce
/**
* @property string $name
* @property-read \App\Models\UserConfig $config
*/
class User extends Model
{
public function config(): HasOne
{
return $this->hasOne(UserConfig::class);
}
}
/**
* @property array $custom_fields
*/
class UserConfig extends Model
{
public function jsonSerialize(): array
{
return [
'customFields' => (object) $this->custom_fields,
];
}
}
// Serializing the related model directly works as expected:
$userConfig = UserConfig::find(1);
echo $userConfig->toJson(); // {"customFields":{}}
// ✅ jsonSerialize is called
// Serializing the parent model that has a loaded relation does not:
$user = User::with('config')->find(1);
echo $user->toJson(); // {"name":"John Doe","config":{"custom_fields":[]}}
// ❌ jsonSerialize on UserConfig is NOT called
Expected Behavior:
The jsonSerialize()
method of related models should be invoked when the parent model is serialized.
Current Behavior:
Related models are serialized using the default Eloquent logic, ignoring any custom jsonSerialize()
methods defined on them.