Terry Harvey

5 Laravel Eloquent Tips & Tricks

Certain tasks within Laravel’s Eloquent ORM can become very repetitive and tedious within larger applications. I’ve compiled a quick list of five of the lesser-known tips that have collectively saved me hours of time during development. Let’s dig in, shall we?

1 – Quickly Generate Model & Migration

This isn’t a very well known trick and, currently, is not mentioned in the Laravel documentation. Let’s take the trivial example of a blog and generate both a model and a migration for posts.

$ php artisan make:migration create_posts_table
$ php artisan make:model Post

The above can easily be condensed into a single command:

$ php artisan make:model Post -m

2 – Eloquent Query Scopes

Retaining our previous example of a blog application, let’s say that our posts table has a is_published column which will always be either 1 or 0 (true or false respectively). Now, on the blog index page, we want to make sure that users can only view published posts. So how would we filter the non-published posts out with Eloquent? The obvious answer would to use a simple where query:

Post::where('is_published', true)->get();

That’s perfectly fine of course, but what if we wanted to re-use that snippet somewhere else within our codebase? There’s nothing wrong with simply re-using that snippet of code, but in attempt to comply with the DRY principle and to make our code a bit more readable, we’ll utilise an Eloquent query scope. Within our Post model, we’ll create ascopePublished method:

class Post extends Model
{
    public function scopePublished($query)
    {
        return $this->where('is_published', true);
    }
}

In order to retrieve our published posts, we can simply call:

Post::published()->get();

Eloquent is clever enough to translate that into the scopePublished method. Any methods you have in your Eloquent models prefixed with the word scope will be assumed to be an Eloquent scope.

It’s worth noting that the return value of a scope method must be a query builder instance, so you can’t call something like ->get() or ->paginate() within a scope.

3 – Accessors

In many cases, you may want to be able to access a computed property of an Eloquent model that doesn’t exist as a value in the database. Sorry for the jargon! Let’s look at an example. We have a users table, within which we have two columns: forenames and surname. If we want to display a users full name within one of our views, we’d have to do something like this:

{{ $user->forenames . ' ' . $user->surname }}

Firstly, it’s likely that we’ll be using that little snippet in multiple places throughout our application and it’s impractical to type that over and over. Secondly, ugh. That syntax is ugly and looks sooooo out of place. Let’s have a look at how we can clean that up a bit with accessors (A.K.A. attributes). Let’s create a new method within our User model.

class User extends Model
{
    public function getNameAttribute()
    {
        return $this->forenames . ' ' . $this->surname;
    }
}

Similarly to how Eloquent recognises the scopes, anything encapsulated in the words get and Attribute in a method name will automatically be picked up by Eloquent as an accesor. So now, when we try to execute the following snippet, we should get the same result as earlier:

{{ $user->name }}

Not only is this reusable and much easier to type, but it’s also much more readable.

4. Dynamic Method Names

…for lack of a better term. Eloquent is extremely intelligent with certain methods such as where(). Take the following examples:

// Post::where('published', 1)->get();
Post::wherePublished(1)->get();

// Post::where('category', null)->get();
Post::whereNull('category')->get();

// Post::where('category', '!=', null)->get();
Post::whereNotNull('category')->get();

Ah, much cleaner!

5. Appending Accessors

Let’s expand upon trick #3. Sometimes, particularly when working with APIs, you may need to append particular accessors (or attributes) to the default collection returned by Eloquent when retrieving records from the database. Sorry if that doesn’t make sense, let me show you an example. After calling echo User::find(1), we’ll get an array looking a little something like this:

{
    id: 1,
    forenames: "Terry",
    surname: "Harvey",
    email: "contact@terryharvey.co.uk",
    created_at: "2016-05-02 21:27:58",
    updated_at: "2016-05-03 18:09:37",
}

That’s all well and good, but what if want to expose that full name attribute we created earlier? Let’s go back to our model and add an $appends property.

class User extends Model
{
    protected $appends = ['name'];
}

If we repeat the earlier command, the name should now be appended to the result, ready for the user of our API to consume.

{
    id: 1,
    forenames: "Terry",
    surname: "Harvey",
    name: "Terry Harvey",
    email: "contact@terryharvey.co.uk",
    created_at: "2016-05-02 21:27:58",
    updated_at: "2016-05-03 18:09:37",
}

Conclusion

I regularly use all of these tips during my day job and they’ve all served me well. I hope you all find them just as useful, and as always, if you have any specific questions you’d like me to answer, please don’t hesitate to contact me via my contact page.