Accessor not working when "snakeAttributes = false" #42703
-
Environment
I am trying to get another date from the datetime column. public static $snakeAttributes = false; As shown below, it is set up so that it can also be retrieved by the API. protected $appends = ['created_on'];
protected function createdOn(): Attribute
{
return Attribute::make(
get: fn ($value, $attributes) => date('Y-m-d', strtotime($attributes['created_at'])),
);
} I am getting an error when using the accessor at that time.
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
try this
|
Beta Was this translation helpful? Give feedback.
-
With public static $snakeAttributes = false; Your accessors/mutators defined with You can either: 1. use camel case for this attribute// you then access as $model->createdOn
protected $appends = ['createdOn'];
protected function createdOn(): Attribute
{
return Attribute::make(
get: fn ($value, $attributes) => date('Y-m-d', strtotime($attributes['created_at'])),
);
} 2. define the attribute method in snake caseprotected $appends = ['created_on'];
protected function created_on(): Attribute
{
return Attribute::make(
get: fn ($value, $attributes) => date('Y-m-d', strtotime($attributes['created_at'])),
);
} 3. use the previous accessor/mutator syntax as suggested by @hussein4alaaprotected $appends = ['created_on'];
public function getCreatedOnAttribute()
{
return date('Y-m-d', strtotime($this->attributes['created_at']));
} |
Beta Was this translation helpful? Give feedback.
-
This is still a bug though, right? (I'm on Laravel 8 but from OP's post it sounds like it's also in 9) "$snakeAttributes Indicates whether attributes are snake cased on arrays". In other words:
$snakeAttributes should have no effect on attributes that are already snake case, right? However... When serialization is evaluated on attribute my_snake_example, it doesn't even try to call getMySnakeExampleAttribute(). Digging in a bit I traced this to Illuminate\Database\Eloquent\Concerns\HasAttributes::getMutatedAttributes() which returns a list of attributes that have mutators. This is passed to addMutatedAttributesToArray() which verifies the attribute exists before calling the mutator. And here's the problem:
getMutatedAttributes() gets its attribute list from getMutatorMethods() which looks for "get...Attribute" methods, takes whatever is between "get" and "Attribute" and lower-cases the first letter. So if the mutator is getMySnakeExampleAttribute() that yields "mySnakeExample". Now it depends on $snakeAttributes:
I can trick it by naming the mutator getmy_snake_exampleAttribute(), which verifies there is a my_snake_example attribute but then still tries to call getMySnakeExampleAttribute(). So I guess here's another workaround which looks wacky but doesn't require $appends and IMO deals more directly with the bug: // existence of this method forces Laravel to recognize a mutator on a snake case attribute even if $snakeAttributes is false
public function getmy_snake_exampleAttribute(){}
public function getMySnakeExampleAttribute()
{
return doSomethingTo($this->attributes['my_snake_example'])
} If you're wondering why I have $snakeAttributes = false when I have snake case attributes, it's because I don't want relation names to be converted to snake case. I want plain attributes in snake and relations in camel. Basically I don't want Laravel to be messing with my attribute names at all. But some of that seems to be built in to the mutator logic. |
Beta Was this translation helpful? Give feedback.
try this