Laravel belongsToMany relationship

Laravel belongsToMany relationship

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:

table users

id  |   name   |    email               |   updated_at              |   modified_at
1       John        john@example.com        2018-01-01 01:00:00         2018-01-01 01:00:00

There is also a sites table:

table sites
id  |   name   |    url         |   created_at              |   modified_at
1       Foo         http://foo      2018-01-01 01:00:00         2018-01-01 02:00:00
2       Bar         http://bar      2018-01-01 01:00:00         2018-01-01 02:00:00

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:

table users_sites

id  |   users_id    |   sites_id |  updated_at              |   modified_at
1       1               1           2018-01-01 23:20:12         2018-01-01 23:20:12

 

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:

<?php

namespace App;

use IlluminateDatabase\Eloquent\Model;

class Users extends Model
{

    public function sites()
    {
        return $this->belongsToMany(Sites::class);
    }
}

 

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:

>>> $c = \App\Users::find(1);
=> App\Users {#825
     id: 1,
     name: "John",
     email: "it@rftags.co.za",
     created_at: "2018-02-14 09:53:01",
     updated_at: "2018-02-14 09:53:01",
   }

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:

>>> $c->sites
=> Illuminate\Database\Eloquent\Collection {#784
     all: [
       App\Sites {#810
         id: 1,
         name: "Foo",
         created_at: "2018-02-14 09:53:27",
         updated_at: "2018-02-14 09:53:27",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#822
           clients_id: 1,
           sites_id: 1,
         },
       },
     ],
   }

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:

>>> $allSites = \App\Sites::all();
=> Illuminate\Database\Eloquent\Collection {#826
     all: [
       App\Sites {#832
         id: 1,
         site_name: "Foo",
         url: "http://foo",
         created_at: "2018-02-14 09:53:27",
         updated_at: "2018-02-14 09:53:27",
       },
       App\Sites {#833
         id: 2,
         site_name: "Bar",
         url: "http://bar",
         created_at: "2018-02-14 09:53:39",
         updated_at: "2018-02-14 09:53:39",
       },
     ],
   }

 

Next, we call diff on the allSites object by passing in the User object ($c) we created earliers:

>>> $notIn = $allSites->diff($c->sites);
=> Illuminate\Database\Eloquent\Collection {#821
     all: [
       AppSites {#833
         id: 2,
         site_name: "Bar",
         url: "http://bar",
         created_at: "2018-02-14 09:53:39",
         updated_at: "2018-02-14 09:53:39",
       },
     ],
   }

 

Conclusion

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!

Share

Leave a Reply

Your email address will not be published. Required fields are marked *