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

tylerwiegand's avatar

Permissions on Model

I've used Spatie's package and Laratrust for various permission models with Teams and without before, but I've recently run into a client desire that I'm not sure I'm planning on handling correctly.

Basically the Client wants every individual User on the platform to have individualized levels of access to "Post" instead of a Role that dictates permissions for all Posts, and not limited to whomever creates it. So, Joe creates Post 1 and invites Marcy to have Editor permissions on Post 1, but only on Post 1.

So my first instinct is to just use Spatie's package, as I have, but to append something like $user->givePermissionTo('edit_post_1'); But then I thought it would just be ... i dunno, gross? Also sounds like a terribly inefficient query to run, but since I hadn't tried it at scale I can't say for sure. My next step would be to generate about a million entries and see how long queries take, but it doesn't seem like something that scales well.

Then I thought of maybe individual tables for each "Post" for permissions, but that sounds like a big headache... I dunno, someone have some better ideas? I've been thinking about this for weeks, im ashamed to say, and I need some help. PLEASE!

0 likes
6 replies
D9705996's avatar

You might be able to use the bouncer package as it has a concept of ownership the you could leverage with closures to allow for advanced permissions

https://github.com/JosephSilber/bouncer#ownership

Bouncer::ownedVia(Post::class, function ($post, $user) {
    return $post->users->has($user);
});

If you have a many to many relationship between post and users (who are able to manage the post) the above should work with a bit of tinkering. You would just need to setup how you manage the allowed users.

tylerwiegand's avatar

Per your suggestion I took a very close look at bouncer. I remember looking at this package a few years ago, but didn't remember it being this customizable.

While it is nice to be ABLE to account for this type of relationship, it isn't exactly a round peg for my round hole. I might end up going with Bouncer in general though -- it seems very well thought out.

I'm not sure if it's really that unusual of an ask or I'm just thinking about this the wrong way, but I still haven't found an elegant solution to this...

Thank you for responding!!

PatrickSJ's avatar

How about a model called PostAssignment that contains post_id, user_id, and permission_id?

It can be checked to see if the user_id for a given post_id has the permission_id?

$post->givePermissionTo('edit_post', $user_id);

// Post.php

public function giveUserPermissionTo($permission, $user) {
    $this->post->assignments()->create([
        'permission_id' => $permission->id,
        'user_id' => $user->id
    ]);

    return $this;
}

public function userHasPermission($permission, $user) {
    return Post::whereHas('post_assignments', function($query)  use ($permission, $user) {
        $query->where([
            ['user_id' => $user->id],
            ['permission_id' => $permission->id],
        ])->get()
          ->isNotEmpty();
    });
}

Edit:

I don't like 3-way pivots but.... I suppose we could restructure the tables. Hrm. Need to sleep on it.

Edit2:

Okay, I'll sleep in a bit. You can probably has a hasMany to a post_permission table and a hasManyThrough it to a post_assignment table to avoid a 3-way pivot.

post_permission = id, post_id, permission_id post_assignment = id, post_permissions_id, user_id

Chain through it to all permitted editors and see if the returned collection contains the user id?

1 like
smnhunt's avatar
smnhunt
Best Answer
Level 9

You could have a permissions JSON field on the Post model that contains a JSON array. This would localise post specific permissions within the post model, rather than have the requirements spill over into the rest of your app.

The array could look something like:

{
    "permissions": [
        "editor": [
            'user_id_1', 'user_id_2'
        ],
        "owner": [
            'user_id_3', 'user_id_4'
        ]
    ],
}

etc.

This article has more information about JSON features that were introduced in Laravel 5.3: https://themsaid.com/laravel-mysql-json-colum-fast-lookup-20160709

1 like
tylerwiegand's avatar

@SMNHUNT - now THAT is interesting...I really like that approach. Might just use that. Thank you!!!

Yknow, I had seen a package by spatie for schemaless attributes, I had no idea it was essentially "built in" since 5.3! Wow! THANK YOUUUUUUUU

tylerwiegand's avatar

To all those who might care, we decided to eventually go with the Bouncer package and just throw individual model instance permissions to everyone.

Please or to participate in this conversation.