Search code examples
phplaravellaravel-11laravel-gate

Laravel UserPolicy not working properly without models


I am using Laravel 11.36.1, when I try to get the authorization status in a policy method without model (like the documentation explains) it always returns "false". I tried putting a dd('hello world') to see if it shows something different and it doesn't work.

UserPolicy

<?php

namespace App\Policies;

use App\Models\User;

class UserPolicy
{
    public function create(User $user): bool
    {
        dd('hello word', $user->id);
    }
}

What I'm testing

User::find(2)->can('create'); // Returns `false`
User::find(2)->can('create', User::find(5)); // Returns the dd with `hello world` and `2`
User::find(2)->can('create', User::class); // Returns `false`
User::find(2)->can('create', new User); // Returns the dd with `hello world` and `2`

// Test in Pest
test('example', function() {
    $user = \App\Models\User::factory()->create();

    $this->actingAs($user);

    dd(
        auth()->user()->can('create') // Returns `false`
    );
});

What I'm expecting

User::find(2)->can('create'); // Returns `hello world` and `2`

Some considerations

  • I'm also using Laravel Permission by Spatie (v6.9).
  • I tried to put Gate::policy(User::class, UserPolicy::class) in the boot method of the AppServiceProvider.php, it didn't make any difference.
  • Using User::find(2)->can('create', new User) is neither an optimal, maintainable and aesthetic solution, so I discarded it.
  • Maybe I'm misunderstanding how Policies and Authorizations in Laravel work, but I'm tired of searching and I'm honestly didn't find any explanation.

Solution

  • I solved the problem. In the Laravel documentation explains that if the ability does not require models, is necessary to pass a reference to the parent model (in my case, User model).

    use App\Models\User;
    
    User::find(2)->can('create', User::class); // It works now!