Skip to content

jsonSerialize() on relations is not called when serializing the parent model #55825

@clementbirkle

Description

@clementbirkle

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions