Certainly! Here’s a solution to the Laracasts forum question. The main issue is that Spatie Permissions' can method short-circuits the policy if there’s a matching permission, so your policy is never triggered. If you want to check both the permission and the user-specific logic in the policy, here’s how to achieve that:
Solution:
First, define your policy with the extra user check, e.g. PostPolicy:
public function update(User $user, Post $post)
{
// Only allow if user has permission AND owns the post
return $user->can('edit post') && $user->id === $post->user_id;
}
Then, make sure it’s registered in AuthServiceProvider:
protected $policies = [
\App\Models\Post::class => \App\Policies\PostPolicy::class,
];
When you check the authorization in your controller or route, use the authorize method or policy gate:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// ... update logic
}
Important:
If you call $user->can('edit post') directly, Spatie’s permission trait will return true if the user has the permission without running your policy logic. Always use the policy call ($this->authorize() or Gate::allows()) to enforce the extra logic.
If you want the policy to be evaluated every time (and not short-circuited by Spatie), avoid assigning edit post as a permission directly on the user/role and let the policy handle the check.
Or, if you want finer control, you can modify the policy method to check for both the permission and the user match, as in the example above.
Summary:
- Write an explicit policy for your model (
PostPolicy). - Register it in
AuthServiceProvider. - Use
$this->authorize('update', $post)in your controller—not$user->can('edit post')directly. - In your policy, combine permission and ownership checks as needed.
Let me know if you need a more advanced example!