Search code examples
phplaravellaravel-livewirelaravel-11

How to automatically register and use Policies in Laravel 11?


I'm creating a policy for model todo to authorize the user role and then set custom access for model functions like create(), update(), etc. As written in Laravel Documentation, we can create a policy for the todo model with php artisan make:policy todoPolicy --model=todo.

When we use modelname + Policy for our policy name that is located in App\Policies folder, Laravel automatically register them for the model, as we used todoPolicy for todo Model.

Also, to check if this Policy works or not, I had set return true; for the create() function in the todoPolicy file, and I'm calling $this->authorize('create,' todo::class); in add function of component for testing it.

But it always returns 403, not an authorized page. What's the problem with my code?

Component / Controller

namespace App\Livewire\Elements\Todolist;

use Livewire\Component;
use App\Models\todo;

class Todolist extends Component
{
    public $description;

    public function done($id) {
        sleep(0.5);
        todo::where('id',$id)->first()->update([
            'is_done' => true,
        ]);
    }

    public function restore($id) {
        sleep(0.5);
        todo::where('id',$id)->first()->update([
            'is_done' => false,
        ]);
    }

    public function delete($id) {
        sleep(0.5);
        todo::where('id',$id)->first()->delete();
    }

    public function add(todo $todo) {
        $this->authorize('create',$todo);
        
        $this->validate([
            'description' => ['required','max:128'],
        ]);
        sleep(0.5);
        todo::create([
            'user_id' => session('user_id'),
            'description' => $this->description,
        ]);
        $this->reset();
    }

    public function render()
    {
        return view('livewire.elements.todolist.todolist',[
            'todos' => todo::orderBy('is_done','ASC')->orderBy('created_at','DESC')->get(),
        ]);
    }
}

TodoPolicy

namespace App\Policies;

use App\Models\User;
use App\Models\todo;
use Illuminate\Auth\Access\Response;

class todoPolicy
{
    /**
     * Determine whether the user can view any models.
     */
    public function viewAny(User $user): bool
    {

    }

    /**
     * Determine whether the user can view the model.
     */
    public function view(User $user, todo $todo): bool
    {

    }

    /**
     * Determine whether the user can create models.
     */
    public function create(User $user): bool
    {
        return true;
    }

    /**
     * Determine whether the user can update the model.
     */
    public function update(User $user, todo $todo): bool
    {
        //
    }

    /**
     * Determine whether the user can delete the model.
     */
    public function delete(User $user, todo $todo): bool
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     */
    public function restore(User $user, todo $todo): bool
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     */
    public function forceDelete(User $user, todo $todo): bool
    {
        //
    }
}

I have tried registering policies manually, but it didn't change anything.


Solution

  • The problem was that when we want to return true; a policy function without passing models to it, we should make the model optional like this:

    public function create(?User $user): bool
    {
        return true;
    }
    

    It's so Important specially when you don't use Laravel Authentication System.