In a Laravel 5.2 application I have three models: User, Role and Task. 
A User is associated with multiple Roles, and a Role is associated with multiple Tasks. 
Therefore each user is associated to multiple tasks, through their roles.
I am trying to access all Tasks associated with a User, through their Roles.
The relevant parts of my models look like:
class User extends Authenticatable
{    
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
    public function tasks()
    {
        return $this->hasManyThrough('App\Task', 'App\Role');
    }
}
class Role extends Model
{
    public function tasks()
    {
        return $this->belongsToMany('App\Task');
    }
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}
class Task extends Model
{    
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    } 
}
The following returns an SQL error;
Column not found: 1054 Unknown column 'roles.user_id'
It seems to be trying to access the relationship through a (non-existent) foreign key in the Role model, rather than through the pivot table.
$user = Auth::user;
$tasks = $user->tasks;
How can I access all tasks related to a user through these relationships?
hasOne relationship in laravel is used to create the relation between two tables. hasOne means create the relation one to one. For example if a article has comments and we wanted to get one comment with the article details then we can use hasOne relationship or a user can have a profile table.
I have developed a custom BelongsToManyThrough relationship which might interest you.  You would need to add the new relation class (as given in my gist; it is too long to paste here), and also override your base Model class as described in the gist to implement belongsToManyThrough.
Then (assuming you are using Laravel's default table naming schemes - if not, you can specify the joining tables as well), you would define your relationship as:
public function tasks()
{
    return $this->belongsToManyThrough(
        'App\Task',
        'App\Role');
}
belongsToManyThrough will not only give you a list of Tasks for your User(s), it will also tell you the Role(s) via which each User has each Task.  For example, if you had:
$user->tasks()->get()
The output would look something like:
 [
    {
        "id": 2,
        "name": "Ban spammers",
        "roles_via": [
            {
                "id": 2,
                "slug": "site-admin",
                "name": "Site Administrator",
                "description": "This role is meant for \"site administrators\", who can basically do anything except create, edit, or delete other administrators."
            },
            {
                "id": 3,
                "slug": "group-admin",
                "name": "Group Administrator",
                "description": "This role is meant for \"group administrators\", who can basically do anything with users in their same group, except other administrators of that group."
            }
        ]
    },
    {
        "id": 13,
        "name": "Approve posts",
        "roles_via": [
            {
                "id": 3,
                "slug": "group-admin",
                "name": "Group Administrator",
                "description": "This role is meant for \"group administrators\", who can basically do anything with users in their same group, except other administrators of that group."
            }
        ]
    },
    {
        "id": 16,
        "name": "Reboot server",
        "roles_via": [
            {
                "id": 2,
                "slug": "site-admin",
                "name": "Site Administrator",
                "description": "This role is meant for \"site administrators\", who can basically do anything except create, edit, or delete other administrators."
            }
        ]
    }
]
My custom relationship does this efficiently, with only a few queries, as opposed to other solutions involving foreach, which would create an n+1 query problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With