In this Blog, we’ll understand mutators and accessors of the Eloquent ORM in the Laravel framework by examples. Laravel 12 Accessors, and Mutators allow us to alter data while saving and fetching. As per the name, the Accessor alters data while accessing and Mutators modify data while saving. The major difference between an Accessor and a Mutator is that data modification in an Accessor is temporary while in a Mutator modified data is stored in the database.
For example, if we want to store a user name in upper case in our database then we can define a mutator for that so that when we save the model it will automatically convert the name into uppercase and also store the name in uppercase.
Suppose we store the user’s name as first name and last name. We want to display full user names across various pages then we need to add them manually Right! But by using accessor, we can create an attribute that merges it and use that attribute whenever required.
Create Accessors and Mutators in a Laravel Model
Let’s take a practical example. Here, we will create a Post Model and define the Accessor and Mutator on it.
To create a model, enter the below command into your terminal:
php artisan make:model Post -m
It will create a Model and migration file for Post. Let’s modify them one by one:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'content',
'views',
'author_name',
'price',
];
}
Migration file changes:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->integer('views')->default(0);
$table->string('author_name');
$table->decimal('price', 8, 2)->default(0);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Titles generally use title case. which means, the first character of each word in a string to uppercase. Here, we will take user input into free text and store it in lowercase using Mutator and use the title in title case while displaying using accessors.
Here, we have created a basic database structure for our posts table now it’s time to migrate it. Enter the below command to migrate :
php artisan migrate
Let’s define a Mutator and accessor for the title attribute. The Mutator will be automatically called when we attempt to set the value of the title attribute on the model and the Accessor will convert the title into title case while fetching data.
Syntax
use Illuminate\Database\Eloquent\Casts\Attribute;
// Accessor
protected function attributeName(): Attribute
{
return Attribute::make(
get: fn ($value) => /* converted value */,
);
}
// Mutator
protected function attributeName(): Attribute
{
return Attribute::make(
set: fn ($value) => /* converted value */,
);
}
// Combined accessor and mutator
protected function attributeName(): Attribute
{
return Attribute::make(
get: fn ($value) => /* converted value */,
set: fn ($value) => /* converted value */
);
}
This syntax explains different examples to set Accessor and mutator. Let’s modify our model to set Accessor and Mutator for the title attribute. So make the below changes into Post Model :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Post extends Model
{
// Accessor Example: Get title in uppercase
protected function title(): Attribute
{
return Attribute::make(
get: fn ($value) => strtoupper($value),
);
}
// Mutator Example: Always store author_name in lowercase
protected function authorName(): Attribute
{
return Attribute::make(
set: fn ($value) => strtolower($value),
);
}
// Combined Accessor + Mutator Example: Price formatted on get, stored as integer on set
protected function price(): Attribute
{
return Attribute::make(
get: fn ($value) => number_format($value, 2),
set: fn ($value) => (float) $value,
);
}
// Optional: Mutator for views to increment automatically
protected function views(): Attribute
{
return Attribute::make(
set: fn ($value) => $value < 0 ? 0 : $value,
);
}
}
Checking Accessor and Mutator
Let’s check whether our Accessor and Mutator functions are working or not. Let’s use a controller to check it.
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function checkAccessor()
{
$post = Post::find(1);
if ($post) {
echo "Original Title: " . $post->getAttributes()['title'] . "<br>";
echo "Accessor Title: " . $post->title;
} else {
echo "Post not found";
}
exit;
}
public function checkMutator()
{
$post = new Post();
$post->title = 'New Post';
$post->content = 'This is a test content';
$post->author_name = 'John Doe';
$post->views = 10;
$post->price = 99.99;
$post->save();
echo "Saved Author Name (Mutator applied): " . $post->author_name;
exit;
}
public function checkCombined()
{
$post = Post::find(1);
if ($post) {
echo "Original Price in DB: " . $post->getAttributes()['price'] . "<br>";
echo "Formatted Price (Accessor): " . $post->price;
} else {
echo "Post not found";
}
exit;
}
}
let’s define the route too.
<?php
use App\Http\Controllers\TestController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('check-accessor', [TestController::class, 'checkAccessor']);
Route::get('check-mutator', [TestController::class, 'checkMutator']);
Route::get('check-combined', [TestController::class, 'checkCombined']);
Testing our Functionality
Now we are ready to test our functionality. open the terminal and run the below command :
php artisan serve
Open this URL in a browser and it will show location information.
http://127.0.0.1:8000/check-accessor
http://127.0.0.1:8000/check-mutator
http://127.0.0.1:8000/check-combined
When you open any URL for Accessor and Mutator it will find the first record and display it’s data based on your defined logic. While the check-mutator method will create new records from controller values.
Conclusion
Eloquent Accessors and Mutators in Laravel make it easy to format and modify model attributes automatically. They help keep your code clean and consistent. Using them improves maintainability and reduces repetitive logic.
For cases where you want to simplify repetitive logic inside your views, you can explore Creating Custom Laravel Blade Directive. It shows how to extend Blade with your own reusable directives, making templates cleaner and easier to maintain.