Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

DavidPetrov's avatar

Using laravel policy to filter eloquent query

So I recently just got into the concept of gates and policies and totally loved it. However, a natural question that appeared alongside my work was if I could somehow simply use similar logic to filter my eloquent queries based on access constraints defined in policies, because that would really optimise my infrastructure and boost performance.

I can, however, see that policies are made to work with implicit model binding and are using fetched instances. Would there be an analogy for such an approach when building queries anyway?

A modest example would be the following: I've got two models, Role and DocumentCategory that share a belongsToMany relationship. Every User has a role and I want to only fetch the documents for the use to see, whose categories belong to the user's role. Policies work like a charm and I realize filtering my query would not be that simple.

Any Ideas? Thanks in advance!

0 likes
7 replies
jlrdw's avatar
jlrdw
Best Answer
Level 75

belong to the user's role

That's where the authorized users ID comes in.

public function getPets($petsearch = '')
    {
        $petsearch = $petsearch . "%";
        $query = Pet::where('petname', 'like', $petsearch);
        if (Auth::user()->role !== 'admin') {
            $userid = Auth::user()->id;
            $query->where('ownerid', '=', $userid);
        }
        $results = $query->orderBy('petname', 'asc')->paginate(5);
        return $results;
    }

So if admin show all otherwise show only the currently logged in users data.

Multiple roles:

Can write whatever method you see fit to see if a logged in user is also an admin.

I am in no way suggesting to use any of this code.

I wrote one, but do your own the way you want:

public static function userRole($role = null)
    {
        $userrole = Auth::user()->role;
        $checkrole = explode(',', $userrole);
        if (in_array($role, $checkrole)) {
            return $role;
        }
        return false;
    }

Then to use:

public function getPets($petsearch = '')
    {
        $petsearch = $petsearch . "%";
        $query = Pet::where('petname', 'like', $petsearch);
        if (ChkAuth::userRole('admin') === false) {
            $userid = Auth::user()->id;
            $query->where('ownerid', '=', $userid);
        }
        $results = $query->orderBy('petname', 'asc')->paginate(5);
        return $results;
    }

If user is admin this part

if (ChkAuth::userRole('admin') === false) {
            $userid = Auth::user()->id;
            $query->where('ownerid', '=', $userid);
        }

Is not used, since admin will see all.

Again just example of what I did, I am not saying use anything here, write your own logic.

But the key to a user seeing their own data only is:

$query->where('ownerid', '=', $userid);
// or
$query->where('user_id', '=', $userid);

Something like that.

In RBAC there are hundreds of ways to setup, I try to stay simple.

There's nothing in the docs that prevents you from writing some custom methods to check a role.

Also here's an S.O. article: https://stackoverflow.com/questions/44226475/check-if-auth-user-role-id-matches-array-in-laravel

1 like
DavidPetrov's avatar

@JLRDW - Thank you for the detailed answer! I'm already aware of everything you mentioned and that's my current approach. I was more likely imagining something as simple as App\Document::whereCan('view')->get() to filter the documents query the way I mentioned: only get the documents which the curret user can view similarly to the way policies function (if($user->can('view', $document)). But I guess there's no such SO simple way to achieve that...

@Snapey - I already employ global scopes in mentioned filtering, I was just wondering if I could somehow combine the logic with the one defined in the policies. But it didn't make direct sense to me since policies are designed to work with loaded model instances which are backend objects and have nothing to do with the sql query, so I wondered if there's an alternative to it in terms of query building. Seems not. Thanks anyway! New ideas are still welcome!

1 like
Snapey's avatar

When defining the global scope, you can refer to the policy to know if the scope should be applied or if the scope varies according to the policy.

1 like
jlrdw's avatar

@DAVIDPETROV - First thank you for thanking both of us.

RBAC became a little clearer to me when I pictured it like this.

Pretend you are in a large industrial complex with many rooms and many doors.

They have a maintenance department accounting department Human Resources, executives (admins).

So a user is walking through and each door either user can or cannot enter.

And me I like looking at each controller method the same way, the logged in user can or cannot do that method.

And of course the other part of RBAC as mentioned above, is to allow a user to see and edit their own data while disallowing other uses.

Even Jeffrey in one of his videos mentioned setting this stuff up can be tricky at first but once learned gets easier.

1 like
mr_reboot's avatar

I know this is a super old thread but I found it on Google and was wondering if anyone ever figured this out.

I understand the metaphor of a large industrial complex but in our case imagine this scenario:

We have a directory of users at /users

Some users can see all the users, other user should only be allowed to see users they have view permission on. There is no specific column on the users model that could identify what users can see it. As that would be set entirely at the policy level. For example maybe a user with the role "shop tech" can see all users. But user with role "manager for project A" can only see users that have a role in project A. Note a manager for project A might be a manger for 10 other projects. And a member of one project might be a member of n other projects.

If we have a policy that defines this named "view-users-that-share-project" for example. The policy will deny the request if the user tries to access a user they don't share a project with. But there is no way to scope the query so those users are never shown to the user on the users page when doing Users::all() for example. Or is doing scopes outside of the standard Auth packages the only way to go about this?

Obviously we can't check the permissions on /users route or controller. Since they need access to it. But we need to limit what specific users they can see.

Being able to do this at the query level would be extremely beneficial.

That's why what @davidpetrov suggested would be so useful:

App\User::whereCan('view-users-that-share-project')->get()

Does that make sense? Has anyone figured out how to do this well with existing Auth tools?

Or would we need to figure out how to write our own models/relations to accomplish this?

jlrdw's avatar

@mr_reboot My answer was above was a quick example. In a real app you would of course go over some if statement scenarios. I normally have the logic in another class I call and return what's needed.

Please or to participate in this conversation.