Tutorial

Automatically Format Laravel Database Fields with Accessors and Mutators

Draft updated on Invalid Date
author

Chris on Code

Automatically Format Laravel Database Fields with Accessors and Mutators

This tutorial is out of date and no longer maintained.

Introduction

There’s a really neat feature in Laravel that often gets overlooked because of the feature’s complicated-sounding name. We’re talking about accessors and mutators.

What exactly are accessors and mutators?

  • Accessors: Format something when retrieving from the database
  • Mutators: Format something when saving to the database

Both of these can help us save immense amounts of time (and frustration) because we know that whenever retrieving or saving information to our database, we will know it will always be saved in the correct format.

One of the most common uses for a mutator is to be sure that a user’s password is always hashed before it gets saved into the database. This ensures that you don’t have to always remember to hash a password wherever you save a user.

The Basics

For our examples, let’s say that we have a User Eloquent model. These are the fields on our User:

    - first_name
    - last_name
    - email
    - username
    - password
    - expires_at
    - explodes_at
    - gets_mad_at

For our most basic of examples, let’s say that we always want to ensure that when we grab a user, their first name is capitalized. This is so we can display it to our users and not have to worry about all lowercase names.

Here is the code for when we create a user:

    $user = App\User::create([
        'first_name'  => 'chris',
        'last_name'   => 'sevilleja',
        'email'       => 'chris@example.com',
        'password'    => 'password',
        'expires_at'  => Carbon::now()->addMonth(),
        'explodes_at' => Carbon::now()->addDay(),
        'gets_mad_at' => Carbon::yesterday()
    ]);

Our user didn’t care to enter in their first name or last name with the proper punctuation but we still want to show their name as capitalized. If we save our user to the database with the above, we’ll need to use an accessor to format the user’s first_name and last_name when we retrieve them.

Accessors use getAttribute

An accessor will be defined on our User model:

    <?php

    // app/User.php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model {

        /**
         * Always capitalize the first name when we retrieve it
         */
        public function getFirstNameAttribute($value) {
            return ucfirst($value);
        }

        /**
         * Always capitalize the last name when we retrieve it
         */
        public function getLastNameAttribute($value) {
            return ucfirst($value);
        }

    }

Very easy to do. We just define a getAttribute() method and make sure that we camel case the attribute name (first_name turns into getFirstName).

Then we use PHP’s ucfirst function to capitalize the first letter. Easy!

Mutators use setAttribute

Now let’s say we wanted to handle capitalizing a user’s name when we save them to the database so that our database is uniform in all of its name fields. Just like how we created the getAttribute method, we’ll create a setAttribute method.

The process itself will be a little different though.

    <?php

    // app/User.php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model {

        /**
         * Always capitalize the first name when we save it to the database
         */
        public function setFirstNameAttribute($value) {
            $this->attributes['first_name'] = ucfirst($value);
        }

        /**
         * Always capitalize the last name when we save it to the database
         */
        public function setLastNameAttribute($value) {
            $this->attributes['last_name'] = ucfirst($value);
        }

    }

The big difference is we are adding Attribute to the naming convention here and instead of returning something (we’re not getting anything), we’ll directly call the attribute on the model using $this->attributes.

Now whenever we save to the database, we can make sure that these fields are capitalized.

Which do I use?

Now that we’ve seen accessors and mutators in action, which do you use and when? That really all depends on the scenario. Sometimes you’ll need to only use an accessor or mutator; other times you will need to use both.

An instance of just using a mutator would be hashing passwords. We’re not going to unhash a password when we retrieve it.

A time we would use both accessor and mutator is for json_encodeing and json_decodeing JSON objects in a Postgres database.

Let’s look at some more examples to get the hang of things.

Hashing Passwords

Here’s a really quick example of how we can always ensure that passwords are never saved plaintext into our database.

    <?php

    // app/User.php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    use Hash;

    class User extends Model {

        /**
         * Always capitalize the first name when we save it to the database
         */
        public function setPasswordAttribute($value) {
            $this->attributes['password'] = Hash::make($value);
        }

    }

Encoding and Decoding JSON Objects

Let’s say we add a field to our User model called settings and we store all their settings in a JSON field.

    // get the example user
    $user = App\User::where('username', 'example')->first();

    // give them some settings
    $user->settings = [
        'notifications' => true,
        'location'      => 'Las Vegas'
    ];

Now, this wouldn’t save to our database since it’s an array going into a JSON field. We could json_encode the settings field but that would be tedious to remember to do it all over our application.

We would also have to remember to json_decode this settings field whenever we grabbed a user.

Luckily we can use an accessor and a mutator to ensure this settings field is always the way we want it to be.

    <?php

    // app/User.php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model {

        /**
         * Always json_decode settings so they are usable
         */
        public function getSettingsAttribute($value) {
            return json_decode($value);

            // you could always make sure you get an array returned also
            // return json_decode($value, true);
        }

        /**
         * Always json_encode the settings when saving to the database
         */
        public function setSettingsAttribute($value) {
            $this->attributes['settings'] = json_encode($value);
        }

    }

Slug-ifying Slugs

Another quick example is when we are saving an article to a database. We will need to have a slug for that article.

    // the article
    $title = 'What Does Water on Mars Mean?';

    // the slug
    $slug = 'what-does-water-on-mars-mean';

We wouldn’t want to have a user enter in the slug every time they saved a new article. We can use a mutator to create the slug for us!

    <?php

    // app/User.php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model {

        /**
         * Create the slug from the title
         */
        public function setSlugAttribute($value) {

            // grab the title and slugify it
            $this->attributes['slug'] = str_slug($this->title);
        }

    }

We are calling $this->title and the Laravel helper method str_slug to create the slug attribute when we save our model.

We are using $this->title instead of $this->attributes['title'] because we are not actually setting the title, we just want to get it.

Always Get Date Objects

It is much easier to use Carbon, the extension of the native PHP DateTime class when dealing with dates or times.

    // this is much easier
    $date = Carbon::now();
    $date = $date->addMonth();

    // than dealing with this
    $date = '2012-01-31 00:00:00';
    $date = date('Y-m-d', strtotime('+1 month', $date));

The DateTime string is not the easiest thing to read or work with so we usually have to use Carbon to work with our dates. Laravel handily makes sure that all of our dates are stored in the correct format.

When saving our dates, we are allowed to pass in different dates like so:

    // get the example user
    $user = App\User::where('username', 'example')->first();

    // all are valid ways to set the date
    $user->expires_at = '2015-09-30 23:01:34';
    $user->expires_at = '2015-06-26';
    $user->expires_at = Carbon::now();
    $user->expires_at = Carbon::tomorrow();
    $user->expires_at = 1443765240; // unix timestamp

    // save the user
    $user->save();

How does Laravel know which fields are dates though? That can be defined on the Eloquent Model using the $dates property. By default, the created_at and updated_at fields are automatically mutated into dates.

Unlike the above accessors/mutators where we define a specific method, we can override the default dates and set more date fields to be mutated by overriding the $dates property on our model like so:

    <?php

    // app/User.php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model {

        /**
         * The attributes that should be mutated to dates.
         *
         * @var array
         */
        protected $dates = [
            'created_at',
            'updated_at',
            'expires_at',
            'gets_mad_at'
        ];

    }

All of the fields above will be set to the proper date type now when saving our model.

Inversely, all of the $dates fields will be cast into Carbon instances upon retrieval.

    // get the example user
    $user = App\User::where('username', 'example')->first();

    // find an hour before the time this user explodes at
    $explodeWarning = $user->explodes_at->subHour();

Conclusion

When working with a large application and large teams of developers, it’s always a good idea to have safety valves in precise places so simple errors don’t slip through the cracks.

With accessors and mutators, your entire application will always take certain actions when dealing with the database. No plain text passwords, never having to remember to json_decode a field, and having easy-to-use dates at all times are great reasons to use another useful Laravel feature.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products


About the authors
Default avatar
Chris on Code

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel