How to name a policy for multimodel route in Laravel?

Tags: , , , ,



I’m trying to write a policy for this route:

Route::delete(
    'users/{user}/locations/{location}',
    [UserLocationController::class, 'destroy'],
)->middleware('can:delete,user,location');

but I don’t know how to name the policy to allow Laravel to find it automatically. I’m deleting records from location_user table, but I don’t have model for this table. My policy function looks like this:

public function delete(User $user, User $userModel, Location $location)
{
    return $user->id === $userModel->id
        && $user->locations->contains($location->id);
}

I’ve tried names like LocationUserPolicy, UserLocationPolicy, LocationPolicy, but none of them works. Do you have any suggestions how to name the policy or how to write custom logic to allow Laravel to find it?

Answer

Okay, I found the answer right in the Laravel documentation 😀 The trick is in the changing the order of the can middleware attributes.

The first element in the array will be used to determine which policy should be invoked, while the rest of the array elements are passed as parameters to the policy method and can be used for additional context when making authorization decisions.

So I changed my route to this:

Route::delete(
    'users/{user}/locations/{location}',
    [UserLocationController::class, 'destroy']
)->middleware('can:delete,location,user');

named the policy LocationPolicy (by first attribute) and changed my policy function to this:

public function delete(User $user, Location $location, User $model)
{
    return $user->id === $model->id
        && $user->locations->contains($location->id);
}

Now it works like a charm.



Source: stackoverflow