Reputation: 4320
I'm defining my class as such:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Foo extends Model
{
use HasFactory;
protected $fillable = [
'id', 'first_name'
];
public function getFirstNameAttribute($value = null)
{
return ucfirst($value);
}
}
Then I populate my DB with entry for that model:
\App\Models\Foo::create(['first_name' => 'foo']);
Then I'm calling accessor as follows:
\App\Models\Foo::first()->first_name;
=> "Foo"
which is expected
and
\App\Models\Foo::first()->firstName;
=> ""
which is unexpected (but understandable as even though getFirstNameAttribute
method is being called, DB property firstName
is being accessed and that doesn't exist)
I'd like to ensure that in both cases correct property (first_name
) is being accessed.
Does this mean that ($value = null)
is unreliable and one should always rely on $this->attributes['first_name']
?
As such, this code becomes:
public function getFirstNameAttribute($value = null)
{
return ucfirst($this->attributes['first_name']);
}
Though I'd probably expect
>>> \App\Models\Foo::first()->first_____na______me;
=> "Foo"
to not do this.
Upvotes: 3
Views: 596
Reputation: 40683
When you try to access a model attribute then Laravel will (a) try to retrieve the given attribute and (b) look for an accessor which matches the attribute you attempted to access.
However the convention is that database fields are named using snake_case and PHP functions are named using camelCase (with one humped camels). The rule for naming accessors is get{AttributeName}Attribute
which means that to find whether there's an accessor for first_name
then Laravel will convert the first_name
to StudlyCase (or two humped CamelCase or PascalCase) and look for a function called getFirstNameAttribute
and then call it using the underlying database value as a parameter. It will always do this regardless of what the attribute requests was named. It does not actually have to be snake_case
However the problems are:
getFirstNameAttribute
as getFirstNaMeAttribute
will work just fine and call the same methodFirstName
will have the same name as an accessor for first_name
Therefore your ->first_na__me
call will look for an accessor getFirstNaMeAttribute
and ->firstName
will do the same, however only first_name
will have an actual underlying database value to pass in the $value
parameter.
It's easy to determine what accessor first_name
corresponds to but it's really hard to determine what database value getFirstNameAttribute
corresponds to because php function names are not case sensitive so you can go one way but not the other. Therefore it's just easier to get the literal database field and then call the accessor rather than associate an accessor with a database field
Upvotes: 2