laravel/framework

Inconsistent accessor attribute name conversion

Ouverte

#54 570 ouverte le 11 févr. 2025

 (7 commentaires) (1 réaction) (0 personne assignée)PHP (11 951 forks)batch import
help wanted

Métriques du dépôt

Stars
 (34 872 étoiles)
Métriques de merge PR
 (Merge moyen 1j 22h) (129 PRs mergées en 30 j)

Description

Laravel Version

11.42.0

PHP Version

8.4.3

Database Driver & Version

No response

Description

Define a custom attribute with a convoluted name using the Attribute syntax:

Example:

protected function foo1Bar(): Attribute
{
    return Attribute::make(
        get: fn () => 'yay',
    );
}

Accessing a custom attribute is internally done by a snake-to-camel case conversion. So this means both foo1_bar and foo_1_bar will yield the expected value.

However, some features in Eloquent do the inverse by calling upon the attribute cache ($getAttributeMutatorCache): a camel-to-snake case conversion. This means that foo1Bar now only translates to foo1_bar, and not anymore to foo_1_bar even though its value would get returned when retrieving it.

echo $model->foo1_bar; // "yay"
$model->append('foo1_bar');
$model->toArray(); // Works fine.

echo $model->foo_1_bar; // "yay"
$model->append('foo_1_bar');
$model->toArray(); // Call to undefined method Model::getFoo1BarAttribute() 

On the contrary, when resorting back to the good old getFoo1BarAttribute() everything works as expected for both foo1_bar and foo_1_bar.

protected function getFoo1BarAttribute()
{
    return 'yay';
}
echo $model->foo1_bar; // "yay"
$model->append('foo1_bar');
$model->toArray(); // Works fine.

echo $model->foo_1_bar; // "yay"
$model->append('foo_1_bar');
$model->toArray(); // Works fine.

So, because of internal two-way case conversions to support the newer attribute syntax some unexpected and disfunctional ambiguity gets introduced.

I think both syntaxes (Attribute vs getXXXAttribute()) should behave equally. But I'm not quite sure how to proceed with this. Should foo_1_bar get blocked for access to prevent this kind of expectations further down the line? Or should it also resolve properly when doing the camel-to-snake conversion? Or...?

Steps To Reproduce

protected function foo1Bar(): Attribute
{
    return Attribute::make(
        get: fn () => 'yay',
    );
}
$model->append('foo_1_bar');
$model->toArray();

Guide contributeur