I wanted to take a quick break in my barrage of Artisan posts to write about defining one-to-many and many-to-many relationships in Laravel’s Eloquent. Eloquent also supports one-to-one relationships but I felt like those are used so rarely that I could skip it.
In this example, we’re going to work through setting up a very basic one-to-many relationship where a User must belong to a Subscriber.
We’re going to create a single migration for each step of this process. Our first step is to create our subscribers table.
To keep it simple we’ll create the table with just a name plus the default columns.
Now we’ll create a migration to add the subscriber_id column to the users table.
We’re going to be using the User model that comes with Laravel but we do need to create a Subscriber model.
Now that we have our models we’re going to create a test Subscriber and User.
In our Subscriber model we’re going to create a function named users that uses the hasMany() helper function to define the relationship.
There’s a little bit of magic going on behind the scenes because the hasMany function call above has some “hidden” parameters so it’s equivalent to:
The subscriber_id string is determined by taking the name of the class (“subscriber”) and appending “id”. The “id” string is assumed because it’s the default for Eloquent models’ auto incrementing column.
Let’s say we name our subscriber_id column subId then we could replace the function call above with:
Personally, my preference is being able to only pass one parameter so it’s as clean as possible but I like the fact we can override what Eloquent is expecting.
Now that we’ve defined our users() function we can get an instance of the Subscriber model and then query for the Users associated with it using the users attribute.
The other thing we need to do is define the inverse of this relationship. So in the User model we need to add a subscriber() function:
Again, there are two default parameters that have sensible defaults and this above function is equivalent to:
We’ve now defined the inverse of the relationship we can access the Subscriber thorough any of it’s Users:
In this example, we’re going to work through setting up a very basic many-to-many relationship where a User might have multiple Accounts they’re responsible for.
I’m going to be lazy and create the model and migration all in one go.
And the related migration is again super simple.
Now here is where the magic starts to come in. When Eloquent does it’s many-to-many functions it automatically looks for a table named [firstModel]_[secondModel] where the order is determined by alphabetically. In this example, we’re going to have accounts and users so our pivot table name will need to be account_user to minimize the amount of work we have to do later. Again, I recommend sticking to the process that generates the cleanest code.
We also need to make sure we have a [firstModel]_id and a [secondModel]_id column in the table. I also setup the foreign key relationships but that’s not explicitly required.
I also created three test Accounts for our testing:
In our User model we’re going to create an accounts() function that calls the belongsToMany function with the other model (App\Account in this case) as the parameter.
We also need to create a users() function in our Account model that also calls the belongsToMany function so we can reference these both ways.
Again, this is shorthand for the following:
Where account_user is the pivot table and user_id and account_id are the columns that determine the relationship.
In case you’re wondering why we didn’t create an Account_User model it’s because we don’t need one. Eloquent is smart enough to handled this all on it’s own without an extra class mucking up our source code.
Now that we have all these functions setup to define the relationships between the models we can use the attach() function to link a user to an account:
And then we can use the accounts property to see all the Accounts tied to the User.
And the opposite:
There is also a detach() function that’s the opposite of the attach() function:
attach() and detach() will also work with an id instead of an object:
And you can also use the sync() function to specify a list of relationships and Eloquent will insert the missing values:
As a quick note this process allows you to order the results in case you need them sorted:
What if you have a slightly more complicated relationship with your Accounts? For example, you might have a sales representative who closed the Account and an account representative who helps them if they have problems. Eloquent has a solution for this.
First where going to add two columns to our account_user table.
Now in our account table we can define these relationship in some new functions:
Then when we attach the Users to the Accounts we need to specify the column values:
Then we can use the salesReps and accountReps attributes to access the Users just like we used the users before:
This is really only scratching the surface of what can be done with relationship in Eloquent but I think it covers most of the important parts.
Like this post? Don't forget to follow us on Twitter and Facebook for updates.