Mohamed Omar
Mohamed Omar

Reputation: 287

Laravel Many to Many - 3 models

Some help with many to many relationships in Laravel:

Using the example for roles and users - basically:

I want to add to the third table, eg Year. basically the pivot table will have user_id, role_id and year_id.

I want to be able to make a query to pull for example all users assigned a specific role in a specific year. Eg All users with role_id = 2, and year_id = 1.

Any help will be appreciated

Upvotes: 1

Views: 473

Answers (3)

Erich
Erich

Reputation: 2616

A very late answer to a very old question, but Laravel has supported additional intermediate (pivot) table columns of at least Laravel 5.1 judging from the documentation, which hasn't changed at least through Laravel 6.x.

You can describe these extra columns when defining your many-to-many relationship:

return $this->belongsToMany(Role::class)->withPivot('column1', 'column2');

or in your case, the below would also do the job:

return $this->belongsToMany(Role::class)->withTimestamps();

which you can then access via the pivot attribute on your model:

$user = User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

Note that the pivot attribute is on the distant relationship model (a single Role) and not on the relationship itself.

To get all the Roles assigned to Users in any given year, you might create a special relationship:

// User.php

public function rolesInYear($year) {
    return $this->belongsToMany(Role::class)
        ->wherePivot('created_at', '>=', Carbon::create($year))
        ->wherePivot('created_at', '<', Carbon::create($year + 1));
}

Upvotes: 0

alxscms
alxscms

Reputation: 3067

The best way to achieve a three way relation with Eloquent is to create a model for the table representing this relation. Pivot tables is meant to be used for two way relations.

You could have then a table called roles_users_year which could have data related to this 3 way relation like a timestamp or whatever...

Upvotes: 0

vFragosop
vFragosop

Reputation: 5773

Before answering, I would like to suggest you not to put year on database like this. All your tables should have created_at and updated_at which should be enough for that.

To filter users like you want. You could do this:

// This queries all users that were assigned to 'admin' role within 2013.
User::join('role_users', 'role_users.user_id', '=', 'users.id')
    ->join('roles', 'roles.id', '=', 'role_users.role_id')
    ->where('roles.name', '=', 'admin')
    ->where(DB::raw('YEAR(role_users.created_at)', '=', '2013')
    ->get();

This example may not be the precise query you are looking for, but should be enough for you to come up with it.

Upvotes: 1

Related Questions