Search code examples
phplaraveleloquentpermissions

Laravel spatie permission many to through? query


I have two tables: Schedules and Tasks, with a one-to-one relation

class Schedule extends Model
{
    public function task() {
        return $this->belongsTo(Task::class, 'task_id');
    }

And the Task model has a one-to-many relation with Spatie Roles with a task_role pivot table:

class Task extends Model
{
    public function roles() {
        return $this->belongsToMany(Role::class);
    }

How can I make a query that retrieves all schedules associated with tasks with permission for the logged in user?

For example: Tasks:

id name
1 task1
2 task2
3 task3

task_role:

task_id role_id
1 1
2 3
3 1

Schedule:

id name task_id
1 schedule1 1
2 schedule2 1
3 schedule3 5

Spatie model_has_roles:

role_id model_type model_id
1 App\Models\User 2
2 App\Models\User 1
3 App\Models\User 5

When user2 is logged in he should be able to see only schedule 1 and 2.


Solution

  • It would have been ideal to use hasManyThrough but this would mean some modifications to your schema. However, you can achieve this result by chaining Eloquent relationships and a custom query. For your example, you can do this by

    getting all the role IDs of the user then getting all tasks associated with these roles and finally fiter schedules based on this ID'.

    Or you can define a custom method on user to do same.

    example with code.

    
    // In your Schedule model
    
    public static function getSchedulesForUser($user)
    {
       // Get the role IDs of the user
        $roleIds = $user->roles()->pluck('id');
    
        // Get tasks associated with these roles using Eloquent relationship
        $tasks = Task::whereHas('roles', function ($query) use ($roleIds) {
            $query->whereIn('id', $roleIds);
        })->get();
    
        // Extract task IDs from the tasks collection
        $taskIds = $tasks->pluck('id');
    
        // Return the schedules associated with these tasks
        return self::whereIn('task_id', $taskIds)->get();
    }
    
    

    or

    //in your User model 
    
    
      public function schedules()
        {
            // Get role IDs
            $roleIds = $this->roles()->pluck('roles.id');
    
            // Get task IDs associated with these roles
            $taskIds = Task::whereHas('roles', function ($query) use ($roleIds) {
                $query->whereIn('roles.id', $roleIds);
            })->pluck('tasks.id');
    
            // Return schedules associated with these tasks
            return Schedule::whereIn('task_id', $taskIds)->get();
        }
    
    

    or

    //directly in your controller 
    
    // Get the logged-in user
    $user = Illuminate\Support\Facades\Auth::user();
    
    // Get the role IDs of the logged-in user
    $roleIds = $user->roles->pluck('id');
    
    // Get the task IDs associated with these roles
    $taskIds = DB::table('task_role')
        ->whereIn('role_id', $roleIds)
        ->pluck('task_id');
    
    // Get the schedules associated with these tasks
    $schedules = Schedule::whereIn('task_id', $taskIds)->get();