laravel/framework

Inconsistent accessor attribute name conversion

Open

#54,570 opened on Feb 11, 2025

View on GitHub
 (7 comments) (1 reaction) (0 assignees)PHP (34,705 stars) (11,882 forks)batch import
help wanted

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();

Contributor guide

Inconsistent accessor attribute name conversion · laravel/framework#54570 | Good First Issue