Automatically Format Laravel Database Fields with Accessors and Mutators

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
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 aUser Eloquent model. These are the fields on our User:
- first_name
- last_name
- email
- username
- password
- expires_at
- explodes_at
- gets_mad_at
Here is the code for when we create a user:
$user = App\User::create([
    'first_name'  => 'chris',
    'last_name'   => 'sevilleja',
    'email'       => 'chris&64;scotch.io',
    'password'    => 'password',
    'expires_at'  => Carbon::now()->addMonth(),
    'explodes_at' => Carbon::now()->addDay(),
    'gets_mad_at' => Carbon::yesterday()
]);
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);
    }
}
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);
    }
}
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 plain text 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 ourUser model called settings and we store all their settings in a JSON field.
// get the scotchyscotch user
$user = App\User::where('username', 'scotchyscotch')->first();
// give them some settings
$user->settings = [
    'notifications' => true,
    'location'      => 'Las Vegas'
];
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 grabbbed 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 aslug for that article.
// the article
$title = 'What Does Water on Mars Mean?';
// the slug
$slug = 'what-does-water-on-mars-mean';
<?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);
    }
}
$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 PHPDateTime 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));
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 awesomedude user
$user = App\User::where('username', 'awesomedude')->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();
$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'
    ];
}
Inversely, all of the
$dates fields will be casted into Carbon instances upon retrieval.
// get awesomedudette
$user = App\User::where('username', 'awesomedudette')->first();
// find an hour before the time this user explodes at
$explodeWarning = $user->explodes_at->subHour();
 
