bouncer
bouncer copied to clipboard
Assign role for a particular model
Considering that it is possible to do grant an ability only to a specific model
Bouncer::allow($user)->to('edit', $post);
I think it should also be possible to grant a role to a specific model. That is, take all the abilities a particular role has and give it to a user, but only for a particular model. That is:
Bouncer::assign('admin', $post)->to($user);
rather than just Bouncer::assign('admin')->to($user);
This is a feature request that keeps on coming up, but it's more complicated than it sounds. Caching becomes really complicated. See here.
In your case, you could use the toManage method:
Bouncer::allow($user)->toManage($post);
This allows all abilities on that model. It's syntactic sugar for:
Bouncer::allow($user)->to('*', $post);
Ah okay, that makes sense. However, the solution you proposed allows all abilities on that model. But what if we need(as in my case), to only assign abilities of a particular role( that is not an admin or super admin, say editor).
What I came up with though, is a little hack, which I'm 100% sure isnt a great solution at all and I haven't written custom tests for it. But it works.... I'd like your opinion on it please.
I created a helper class called BouncerExt, and within it I put:
/**
* Assign a given user with a role(e.g admin etc), but only for the given model.
* @link https://github.com/JosephSilber/bouncer/issues/592
*
* @param User $user
* @param string $role
* @param Object $model
* @return void
*/
public static function assignUserWithRoleForModel(User $user, string $role, Object $model)
{
$fake_user = User::factory()->create();
Bouncer::assign($role)->to($fake_user);
$abilities_of_roles = collect($fake_user->getAbilities()->all());
// Give all the fake user's abilities to the user
$abilities_of_roles->map(function($ability) use ($user,$model) {
// If user already has such ability, then skip it.
#if(!$user->abilities()->where('name',$ability->name)->exists()) {
Bouncer::allow($user)->to($ability->name,$model);
#}
});
$fake_user->delete();
#dd($fake_user->getAbilities()->all(), $user->getAbilities()->unique('original.name')->all());
}
Then used as follows:
BouncerExt::assignUserWithRoleForModel(auth()->user(),'editor',$post);