Efficiently Store and Retrieve Data with Laravel 10 Accessors and Mutators

Published: 1 year ago - Updated: 1 year ago

6 minutes - 278 Words

article 'Efficiently Store and Retrieve Data with Laravel 10 Accessors and Mutators' banner

Summary

Learn how to use Laravel's Accessors and Mutators to store and retrieve data from a database.

Introduction

Mutators and Accessors are methods that allow you to access and modify the values of an object’s properties. In Laravel, setters and getters are used to store and retrieve data from a database.

The Mutators and Accessors will run whenever you create or update a model using the Laravel Eloquent Model. If you use Raw Queries these mutators will not run and you have to update the values of the mutator manually.

We can create Accessor and Mutator in these two ways

  • The Old Syntax (It still works in Laravel 9)
  • The New Syntax

The old syntax

This method takes a value and formats it using the setPriceAttribute method to create a value for the price. The getPriceAttribute method is used to retrieve the value from the database and return it.

Accessor

public function setPriceAttribute($value) {
	$this->attributes['price'] = $value * 100;
}

Mutator

public function getPriceAttribute() {
	return $this->attributes['price'] / 100 ;
}

The new syntax

In Laravel 9 there is a new way of doing the above with just one method.
The code example below shows how to set the price attribute using the Illuminate\Database\Eloquent\Casts\Attribute class.

Accessor & Mutator in one function

use Illuminate\Database\Eloquent\Casts\Attribute;

// ...

protected function price():Attribute
{
	return Attribute::make(
		get: fn ($value) => $value / 100,
		set: fn ($value) => $value * 100 ;
	);
}

Example

Bellow is a practical example of setting the price field in a Product table. As you might have known the payment services such as stripe use cents and you have to multiply the price to change it from dollars to cent.
We can achieve this behaviour using mutators in two ways.

The product table migration file.

// 2023_01_28_141837_create_products_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->integer('price');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
};

For our demonstration purposes the products table is very simple it contains name,price and timestamps.
I have added a few entries to the products table and after querying it, we will get something like this.
The mutator and accessor is not applied yet.

The Database
desc

The UI
desc

As you can see the price value is the same in the Database and in the UI.Now let’s create a new product with the mutator and accessor. To do that simply add the bellow funtion to your model and you will be setup.

// App/Modesl/Product.php

protected function price():Attribute
{
	return Attribute::make(
		get: fn ($value) => $value / 100,
		set: fn ($value) => $value * 100 ;
	);
}

Now let’s create a new product with the name Icon Pack and price of 20

desc

After saving the new product since we are multipying its price by 100 in our mutator, the price would be 2000.

desc

And same way in our accessor we are dividing the value by 100, we will get 20 back to display it in the front-end of our application.

desc

What happens to the old records

As you remember I added two records befor creating the Accessor&Mutator, you might ask what will happen to those records ?
Since the Accessor works with all products, it will be automatically applied to the old products as well , dividing their value by 100 and will return a misleading/wrong prices to our front-end application, as it is shown in the screenshot bellow.

desc

The price of UI/UX Components Pack is shown as 0.10 but it is 10 in the Database.

How to fix it ?

To apply the mutator for old records you have to manually update all the records. You can do this from the application’s front-end forms or create a new migration file and update the records.

By creating migration

Warning: Make sure to run the migration before adding new products.
or set a filter migration ie. only update products created before a specific date

Create a new migration by running the bellow artisan command.

php artisan make:migration update_old_products_price

In the creaed migration file add the bellow code

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Product;

return new class extends Migration
{
  
    public function up()
    {
        $products = Product::all()->each(function (Post $post) {
            $product->price = $product->price * 100;
            $product->save();
        });
    }

};

The above migration performs these tasks:

  • Get all the products
  • Multiply the price to 100 (Change it to cents)
  • Save the product

The mutator and Accessor will not run if

  • The field is not present in the request
  • You are using raw sql queries instead of using eloquent

Add Comment

Conversations (0)

Sign up for our newsletter

Stay up to date with the latest news and articles.