Code Happy: Eloquent ORM

← Back to Index

Please note that this chapter was written for VERSION 3 of the Laravel PHP Framework.

An ORM is a really useful package, it stands for Object Relational Mapper. Sounds pretty complicated right? Let's break it down a little. (add bass beat) The mapper part, is because we are mapping our PHP objects or classes to database tables and rows. The Relational part will become clear in the relationships section.

There are many ORM solutions out there, but none as Eloquent as... well Eloquent. Eloquent ships with Laravel, and can be used out of the box. For this portion I am going to assume that you set up your database as described in the Migrations chapter, and that you are familiar with the methods and chaining from the Fluent Query Builder chapter. We are going to build on these.

You see Eloquent is an alternative to using Fluent, but it shares many of the same methods. The only difference is that we are going to be interacting with Eloquent models as results, rather than the stdObject we get back from Fluent. It's going to make our code look even clearer. Let's dive right in and check out the Eloquent model.

Creating and using Eloquent Models

<?php

// application/models/user.php

class User extends Eloquent
{

}

Actually thats it.. no really, I am serious. You see, Eloquent trusts you. It knows that you have already created a nice migration for the users table. It doesn't need you to tell it about the fields that exist. It's going to trust that you know them. You should, you wrote the migration and made the table. Oh by the way, you did put an increments('id') in your table right? This is a common practice and Eloquent needs this to work.

Another thing you might have noticed about the model is that the class is called User and the table is called users. This isn't a typo. Eloquent is so clever that it can detect the plurals for the English language. Our object is singular, so we define it as a User. However our database table users will contain any number of users, so Laravel knows to look for a table with a plural of the object name.

You may have picked up on the fact that it only detects plurals for the English language. What if you use another language, or a certain plural doesn't work for you? Simply add the word and its plural version to the array in the application/config/strings.php file. Now it will work as expected!

Maybe you don't like having the table name as plural form? Not a problem, simply use the static $table class attribute to specify another table name. For example..

<?php

class User extends Eloquent
{
    public static $table = 'app_users';
}

Right, typing that huge model definition must have worn you out (please note the sarcasm). Let's have a go at using our new model.

<?php

$user = User::find(1);

Wait hold on... we have seen this before. Do you remember find() from our Fluent chapter? It brings back a single result by its primary key. You will find that Eloquent uses many of the methods used by Fluent. This is really convenient because you can use a combination of both database libraries without forgetting which method is for what. Sweet!

For eloquent simply use the object's name, and supply a static method. We don't need to use DB::table() for this one.

You can use the result object in a similar way. The truth is you are now interacting with an Eloquent object, but you couldn't really tell the difference at this point. Let's get that users name.

<?php

echo $user->name;

Yep thats the same as last time. Nice and easy.

What if we would rather have our User object returned as an array? Simply call the to_array() method on any Eloquent model to receive an array instead of an object.

<?php

$user = $user->to_array();

If you want to exclude certain fields from this array, you could add a $hidden static attribute to your Eloquent model, containing an array of all the fields to exclude. For example :

<?php

class User extends Eloquent
{
    public static $hidden = array('nickname');
}

Say we want multiple results back? We can use the fancy all() method to bring back every user, then we can have a sexy user party.

<?php

$users = User::all();

What we now have is an array of user objects. We can loop through them to access each one individually. Simple as that.

<?php

foreach ($users as $user)
{
    add_to_sexy_party($user);
}

Nice, its really swinging in here. Quite a few guys though.. Well let's increase our chances and get rid of the other guys. Then it really will be a sexy party!

<?php

$sexy_users = User::where('sex', '=', 'female')->get();

Whoop, lots better! The eye-candy threshold went up significantly. You see we just used a where() chain method and get() just like we did with fluent. There is nothing new there, just increased clarity.

I could cover all the query methods again for returning results, but I don't really need to. Simply flick back a chapter and mentally replace the word Fluent with Eloquent. You will get the idea.

Instead, let's see what has changed. Creating and updating objects (rows) just got a whole lot easier!

<?php

$user = new User();

$user->name = 'Captain Sexypants';
$user->mojo = '100%';

$user->save();

Best not to invite Captain Sexypants to our party, we won't get any action with him around. Even his parrot has swagger.

You see we simply create a new User object, set class attributes for the fields that exist (we don't need to set the ID, Eloquent handles that) and save() the object to write our changes to the database. This is commonly known as the Active Record design pattern. It's a really nice way of interacting with our rows by treating them the same as any other object in our application. It's like the database and all that nasty SQL doesn't even exist!

If we already have a key-value array describing our friend 'Captain Sexypants' then we can either pass it as a constructor parameter to the new object, or use the mass-assignment method fill() to add him to the database. Check this out..

<?php

$user = new User(array(
    'name' => 'Captain Sexypants',
    'mojo' => '100%'    
));

$user->save();

or

<?php

$arr = array(
    'name' => 'Captain Sexypants',
    'mojo' => '100%'    
);

$user = new User();
$user->fill($arr);
$user->save();

Please be careful not to let any extra information slip through when using mass-assignment as it could result in a potential security risk.

So what about updating a row? It's very similar, except we need to query for the user we want to change first. Let's see..

<?php

$user = User::where('name', '=', 'Captain Sexypants')->first();

Here we use first() because we want to make sure we only get one object back. We can't change the values on an array, we would have to loop through each one and that would make a longer example than we need!

<?php

$user->mojo = '5%';
$user->save();

Well I couldn't take all his mojo, that wouldn't be fair. At least he can come to the party now. So you see, updating is performed exactly the same way as inserting except that we need to find the object that we want to update first.

Do you remember using $table->timestamps() with in the migrations chapter to make updated_at and created_at fields? Eloquent will update these automatically for you, inserting a timestamp when an object is created and updating the updated_at field every time you save. If you would like to disable this feature simply add the $timestamps class attribute to your model and set it to false.

<?php

class User extends Eloquent
{
    public static $timestamps = false;
}

Relationships

Relationships are beautiful. No I haven't gone all soppy. I mean relationships between tables. In Eloquent they are beautiful. None of that 'JOIN' rubbish! We can define 'one-to-one', 'one-to-many' and 'many-to-many' just by adding some simple methods to our Eloquent Models. Let's jump right in. You will learn more with a code snippet in front of you.

On To One

Jumping right in..

<?php

class User extends Eloquent
{
    public function invite()
    {
        return $this->has_one('Invite');
    }
}

Let's go ahead and assume that we have made an invites table and an Invite model to contain our sexy party invites.

We have created a new public method called invite(), which will return $this->has_one('Invite') to find a users invite via a has one relationship.

Now we can retrieve a user's (or party guest) invite with a clear expressive syntax. Let's take a peek:

<?php

$invite = User::find(1)->invite()->first();

Again we are using first() because we only want one result. You see by adding ->invite()-> to the chain, which is of course our relationship method name, we retrieve the Invite object that is related to our user.

This relationship will execute two queries :

SELECT * FROM "users" WHERE "id" = 1;
SELECT * FROM "invites" WHERE "user_id" = 1;

From the query you will see that Eloquent is looking for user_id automatically as the foreign key. So if we want to use this relationship, we will need to create a user_id integer field with our migration, in the Invites table. What if we want to call our foreign key something else? No problem! We simply pass a second parameter to the has_one() method (or other relationship methods) to specify the new field name. For example..

<?php

class User extends Eloquent
{
    public function invite()
    {
        return $this->has_one('Invite', 'the_invite_id');
    }
}

What about the inverse of this relationship? What if we have an Invite, but we want to know who it belongs to? This is where the belongs_to() method comes in handy. Let's take a look at the model.

<?php

class Invite extends Eloquent
{
    public function user()
    {
        return $this->belongs_to('User');
    }
}

A similar syntax, but using belongs_to() instead to point out that the foreign key exists in this table.

Now we can use..

<?php

$user = Invite::find(1)->user()->first();

Easy!

One To Many

What if we want to return many related items? Well as you may have guessed from the header there's a method for that. Let's take a look. ( I say that a lot don't I? Maybe it can be my catchphrase. )

<?php

Class User extends Eloquent
{
    public function hats()
    {
        return $this->has_many('Hat');
    }
}

Again, you will see that we are passing the object name in string format with capitalisation to the has_many() method.

In this example the hats table will need a user_id foreign key. We can then use..

<?php

$hats = User::find(1)->hats()->get();

Note that we could also use a dynamic property with the same name to retrieve the same results with a shorter syntax. For example :

<?php

$hats = User::find(1)->hats;

Nicer still!

As before, you can pass another foreign key as a second parameter to use that instead. Let's move on!

Many To Many

Here things will get a little more complicated, but don't worry.. I am here to get you through this. Take my hand Wendy. Let's imagine that we have two Eloquent models, User and Task. A user may have many tasks, and a task may have many users. For this type of relationship we will need a third table.

This table is known by many names. A pivot table, a lookup table, an intermediate table, or el pivote grande.

It's simply a table with two integer fields user_id and task_id, that links the two tables together. This forms a many to many relationship.

The table is named after both related tables in a plural form, in an alphabetical order. Sounds complicated but it looks simple, check it out:

tasks_users

Great, now that we have our table, let's form the relationship:

<?php

class User extends Eloquent
{
    public function tasks()
    {
        return $this->has_many_and_belongs_to('Task');
    }
}

again, similar syntax, with a slightly longer method name.

This time we can pass an optional second parameter to specify a different pivot table name. Simple.

Inserting Related Models

When we are inserting related models, we can set the user_id or hat_id foreign key ourselves, but thats not very pretty. Why not pass the object instead?

<?php

$hat = Hat::find(1);
$user = User::find(1);
$user->hats()->insert($hat);

That looks a lot better! It's like handing objects to each other and is much cleaner than dealing with those integer foreign keys directly.

With has_many() relationships you can pass an array of field-value pairs to the save() method to insert or update related models. For example:

<?php

$hat = array(
    'name'      => 'Dennis',
    'style' => 'Fedora'
);

$user = User::find(1);

$user->hats()->save($hat);

Clean!

When we are creating a new related item with a many-to-many relationship, if we use the insert() method Eloquent will not only create the new object, but also update the pivot table with the new entry. For example :

<?php

$hat = array(
    'name'      => 'Dennis',
    'style' => 'Fedora'
);

$user = User::find(1);

$user->hats()->insert($hat);

But what if the objects already exist, and we just want to create the relationship between them? We can do this easily with the attach() method by passing the $id (or the object) of the object to be related. Let's see the code.

<?php

$user->hats()->attach($hat_id);

The pivot will have been updated for you!

Next is a method that I myself have only recently become aware of. I will assume it arrived with Eloquent in 3.1. We can use the sync() method with an array of ids and once the method has executed only the id's in the array will be in the pivot table. Very handy! Here's a code snippet.

<?php

$user->hats()->sync(array(4, 7, 8));

Pivot Tables

What if we want access to our pivot table directly, rather than just the tables that are related? Eloquent provides the pivot() method to accomplish this task.

<?php

$pivot = $user->hats()->pivot();

Now we have an array of result objects, just like any other query, but for those which relate the users hats.

What if we want to retrieve the exact row that has been used to relate an object? This is easy with the pivot dynamic attribute. The official docs has a great example of this, and I am going to steal it because I am a nasty person. Don't worry, I will make it look a bit different. Kinda like with your high school assignments?

<?php

$user = User::find(1);

foreach ($user->hats as $hat)
{
    echo $hat->pivot->created_at;
}

Now we can access the created_at field on the pivot table row to see when our hat was made.

Ok, I'm getting pretty sick of hats! In fact I want to delete my hats, every last one of them. Fortunately I know my user id, its number 7, lucky number 7. Let's do it right now, let's delete() all of my hats!

<?php

User::find(7)->hats()->delete();

There done. I will have a cold head from now on, but its worth it now you know how to use the delete() method.

Eager Loading

Eloquent gives the option of Eager Loading to help solve the highly debated N+1 issue. If you don't know what this is, let me break it down for you using what we have already learned. Take a look at the following snippet of code.

<?php

$users = User::all();

foreach ($users as $user)
{
    echo $user->hat->size();
}

For every loop iteration, Eloquent has to perform another SQL query to retrieve that users Hat object and find its size. Now this isn't going to be a huge problem on small data sets, but with hundreds of rows it could drastically affect performance. With eager loading we can tell Eloquent to run a SELECT * FROM hats; when retrieving the User object so that we already have all the data we need. This reduces the amount of strain to only two SQL queries. Much better!

Let's see how we can tell Eloquent to eager load a relation:

<?php

$users = User::with('hat')->get();

There, now the hat relationship is eager loaded. If we want to eager load several relationships, simply pass an array to the with() method. It's worth noting that the with() method is static and as such must always be at the start of the chain.

You can even eager load nested relationships. Let's assume that our Hat object has a hatstand() relationship to let us know which stand it's on. We can eager load both of the relationships like this.

<?php

$users = User::with(array('hat', 'hat.hatstand'))->get();

Simply prefix the relationship name with the nested object.

What if we want to add some conditions to our eager loading? Maybe we are only going to be using blue hats? Of course we can do this with Eloquent! Simply pass the relationship name as a key to the array, and a closure containing conditions as a parameter. This is better explained through code.

<?php

$users = User::with(array('hat' => function($query) {
    $query->where('color', '=', 'blue');
}))->get();

Simple. You can add as many queries as you need to!

Setters and Getters

Setters are handy little methods that allow us to format our new model data in a certain way when it is assigned. Let's take a look at a code snippet.

<?php

public function set_password($password)
{
    $this->set_attribute('hashed_password', Hash::make($password));
}

We create a method with the name of the setter prefixed with set_, and pass it a variable which will receive the field value. Now we can use set_attribute() to set a field to its new value. This will allow us to modify the passed value anyway we like. The snippet above will cause the hashed_password field to be updated with a hashed version of the supplied value when we call :

<?php

$user->password = "secret_panda_ninja";

Very useful!

Getters are the exact opposite. They can be used to adjust a value when it is being read. For example :

<?php

public function get_panda_name()
{
    return 'Panda'.$this->get_attribute('name');
}

Now if our name is Dayle we can use..

<?php

echo $user->panda_name;

which would give 'PandaDayle'.

In the next chapter we will take a look at Laravel's simple events system.

My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.

It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new books from the comfort of my sofa!