Back to Course |
Laravel 11 Eloquent: Expert Level

Attributes: Accessors and Mutators

Let's get familiar with a few more terms about Eloquent which are Accessors and Mutators or combined, they are called Attributes from Laravel 9.

If you work with projects before Laravel 9, there may be different syntax in older tutorials or examples. I will show you the old syntax at the end of this lesson.

So, Accessors and Mutators are used if you want to change the value when getting or setting the data. Now, why would you do that?


Example 1: Accessors

For example, you have a created_at field but want to show it in a human format.

Because created_at is automatically casted to a datetime and is a Carbon object, you can use diffForHumans() directly on the field. Now, of course, you can do that in the blade or the API response directly. But what if you want to reuse it in all cases where you use the model, so it makes sense to have some kind of function inside the Model, which is an Accessor.

So, you define the Accessor as an attribute. Interestingly, the Accessor method name is camel case, but it is returned as snake case.

app/Models/User.php:

use Illuminate\Database\Eloquent\Casts\Attribute;
 
class User extends Authenticatable
{
// ...
 
protected function createdDiff(): Attribute
{
return Attribute::make(
get: fn($value) => $this->created_at->diffForHumans(),
);
}
}

The attribute must return the Eloquent cast Attribute. The attribute may have a get and a set function. Now, on the Model, we can call created_diff to get this attribute value.


Example 2: Mutators

Mutators are the opposite of Accessors: they are used when you need to change some value when saving the data.

For example, you're creating a user, and the user is provided with a lowercase name, like "taylor". But you want to respect people and save that with the first uppercase letter anyway.

To do that, you define the name as an attribute, and instead of get, you define a set.

app/Models/User.php:

use Illuminate\Database\Eloquent\Casts\Attribute;
 
class User extends Authenticatable
{
// ...
 
protected function name(): Attribute
{
return Attribute::make(
set: fn($value) => ucfirst($value),
);
}
}

When creating a user, the name will be set to the first uppercase letter before saving it into the database.


Example 3: Accessor & Mutator together

Let's get to the example of mixing of Accessor and Mutator, using get and set in the same field.

A typical example would be date formatting before and after. For example, you have a birth date formatted in some non-standard format, different from the database. In the database, the date should be saved in Y-m-d, but your users may provide it in a different format.

So, when saving the data, you must format it into the MySQL format. When getting the data, you need to format it back to the user format, so users won't see how it is stored in the database.

To do that, we would define a birthDate attribute. The actual user field is birth_date with underscore in the database.

app/Models/User.php:

use Illuminate\Support\Carbon;
use Illuminate\Database\Eloquent\Casts\Attribute;
 
class User extends Authenticatable
{
// ...
 
protected function birthDate(): Attribute
{
return Attribute::make(
get: fn($value) => Carbon::createFromFormat('Y-m-d', $value)->format('m/d/Y'),
set: fn($value) => Carbon::createFromFormat('m/d/Y', $value)->format('Y-m-d'),
);
}
}

You can try to create a User.

User::create([
'name' => 'taylor',
'email' => 'test@test.com',
'password' => bcrypt('password'),
'birth_date' => '01/25/1990',
]);

In the database, the birth date is in the correct format.

And, when the field is called, the format is different.


Old Syntax

The old syntax still works, but it's not in the official documentation of Laravel: the newer syntax aimed to combine getters and setters in the same function.

So, the old syntax for the function name consists of three parts:

  • Prefix of get or set
  • The column name (CamelCase)
  • The word Attribute

The example for a birth_date column would be getBirthDateAttribute() and setBirthDateAttribute().

app/Models/User.php:

use Illuminate\Support\Carbon;
 
class User extends Authenticatable
{
// ...
 
public function setBirthDateAttribute($value)
{
$this->attributes['birth_date'] = Carbon::createFromFormat('m/d/Y', $value)->format('Y-m-d');
}
 
public function getBirthDateAttribute($value)
{
return Carbon::createFromFormat('Y-m-d', $value)->format('m/d/Y');
}
}

Notice: For columns like created_at and updated_at, be careful when using accessors to override the values of the same fields. For more explanation on why, you can check the YouTube video Eloquent Accessors: Dates, Casts, and "Wrong Way"