lorisleiva / laravel-actions

⚡️ Laravel components that take care of one specific task
https://laravelactions.com
MIT License
2.52k stars 124 forks source link

How to do avoid using policies? #138

Closed armen9494 closed 3 years ago

armen9494 commented 3 years ago

Hi, thank you for cool package and great documentation.

I have a model - Project. I have created for that model an action - RemoveProject. In this action I have authorize method:

public function authorize(ActionRequest $request): bool
{
    return $request->user()->hasRole('admin') && $request->project->hasClients();
}

Now I want to check in another action (for example in ShowProjectEdit) if user can delete this project. The issue here is that I can't call this function from another action keeping code clean.

In usual Laravel syntax I would create ProjectPolicy, write this part in delete method and then to pass it from controller to frontend in this way for example

public function edit(Project $project)
{
    ......
    return [
        'data' => $data,
        'canDelete' => $this->authorize('delete', $project),
    ];
}

Do you have idea how to do this using only actions? Maybe it's possible to create some new Trait for that approach. I can still create a policy and use it in actions, but would be nice to have all logic for removing project in one place.

lorisleiva commented 3 years ago

Hi there 👋

If your application needs to keep track of authorisation in multiple places, including passing on that information to the frontend, then I would recommend using a Policy. Policies are a good pattern and put all your security concerns in one file for a given model, I wouldn't fight them if your application could benefit from them. You can then make your authorize methods delegate to the Policies directly like so.

use Illuminate\Support\Facades\Gate;

public function authorize(ActionRequest $request): bool
{
    return Gate::check('delete', $request->project);
}

And also use them anywhere else in your code:

public function edit(Project $project)
{
    ......
    return [
        'data' => $data,
        'canDelete' => Gate::check('delete', $project);
    ];
}

Note that I don't think doing this is an anti-pattern of the "having everything in one place" mentality of Laravel Actions. Some actions will benefit from delegating to Policies but they might not be relevant for other less CRUD-y actions. Effectively, you can see Policies as an additional security layer that your actions can use to keep their code clean and reusable.