Search code examples
phplaraveldatabaseeloquentlaravel-11

How to filter records based on existing records on other Models in Laravel (Implement user blocking)


I have a User model and a Blocklist model, Now when I call User::all() I only want to return Users who are not related based on records in the block list table.

For instance:

user Table

id ...
1 ...
2 ...
3 ...
4 ...
5 ...

blocklist Table

id user_id blockable_id blockable_type
1 1 2 \App\Models\User
2 1 3 \App\Models\User
2 5 1 \App\Models\User

User Model

...

public function blocklist()
{
    return $this->hasMany(Block::class);
}

Blocklist Model

...

public function blockable(): MorphTo
{
   return $this->morphTo();
}

UserController

...
$users = \App\Models\User::whereDoesntHave('blocklist', function (Builder $query) {
    $query->where('user_id', auth('sanctum')->id());
    $query->orWhere(function (Builder $query) {
       $query->where('blockable_id', auth('sanctum')->id());
       $query->where('blockable_type', User::class);
    });
})->all();

The idea is that, if user: 1 is making this request they should not see user: 2 and user: 3 whom they have blocked and they should also not see user: 5 who has also blocked them, but this is not how it works, whatever I do all the users are still returned.


Solution

  • I think might this will help you, you had a small logic error in your query, instead of checking if the blockable_id is equal to auth user's id you should be checking if the user_id matches.

    $users = \App\Models\User::whereDoesntHave('blocklist', function (Builder $query) {
    $query->where('user_id', auth('sanctum')->id()); // Check if the authenticated user is blocking someone
    $query->orWhere(function (Builder $query) {
        $query->where('blockable_id', auth('sanctum')->id()); // Check if someone is blocking the authenticated user
        $query->where('blockable_type', User::class);
    });
    })->get();