There are often times when your data has a “belongsToMany” relationship. Laravel handles this relationship really beautifully!
I learn best by example, so we’ll do this post as an example I’m currently working on.
In our application we have multiple related websites. Each of these sites stands on its own with users being able to register individually on each site. We wanted to update this so that when a user registers on one site their details are automatically pushed to a central database server and then from there pushed to the other sites in the group.
The websites are written in WordPress (not my choice – I love wordpress as a CMS but I think for a pure app Laravel is better). The central database app I’ve written in Laravel.
Within our laravel app we have the users table:
[snippet slug=users-table lang=text]
There is also a sites table:
[snippet slug=table-sites lang=text]
As stated, each user should be pushed to all the sites so we have User belongsToMany relationship with Sites.
To achieve that in Laravel we need to add a pivot table. Laravel expects the pivot table to be named with the names of the table making up the relationship, and with the table belonging to the other table first…
In other words, our users belong to many sites, so our pivot table is:
[snippet slug=table-users_sites lang=text]
In our users model we create a function called sites. This name is the name of the Sites model we have the belongs to many relationship with. In function sites we return the belongs to many relationship object:
[snippet slug=users-model-2 lang=php]
Finding users belonging to sites:
It now becomes extremely easy to find which sites users belong to:
By viewing the table entries above you can see that user John (me:) belongs only to site Foo.
To see this is Laravel we use the sites function as a PROPERTY call on the user object! Open tinker and see this working as such:
[snippet slug=user lang=text]
using the \App\Users::find(1); where 1 is the user’s ID we can an object ($c) of that user.
We can now call the sites function as a property on that object to see the sites the users belongs to, ie, $c->sites:
[snippet slug=tinker-get-user-2 lang=text]
Finding users NOT in the belongsToMany Relationship in Laravel
As mentioned, our application calls for users to belong to all the sites. To do this we have a queue running over this relationship to see which sites a user still needs to be pushed to.
Of course, in the example above the relationship shows us which site the user DOES belong to and we want to see which (s)he DOESN’T belong to.
One approach is to use Laravel’s diff function on objects.
We first get an object with all the sites:
[snippet slug=users-model lang=text]
Next, we call diff on the allSites object by passing in the User object ($c) we created earliers:
[snippet slug=belongstomany-not-in lang=text]
And there we have it. With only a few simple lines of code Laravel reduces the complexity of these relationships!
Let me know in the comments if spot a mistake or improvement or ask if you have a question!
John is a freelance Full Stack Developer. Experienced in PHP, Laravel and Vue3/Nuxt3 he can code anything you need.
Based in South Africa, I am available for PHP, Laravel or Vue3/Nuxt3 freelance jobs in person or remotely.