0

I have a method bulk_destroy in the controller that accepts an array of ids that user wants to delete. I've to check for each record whether the user is the owner of that record or he has the specific role to delete that record.

At the end I've to return the all record ids which get deleted and the remaining one for which user does not have specific role. Is there any efficient way to delete records on the basis of role.


One way I can think about is that I'll fetch the records and then I'll iterate over each record and for each record, I'll check whether logged in user is the owner of that record or he has the specific role or not. If he has then I'll delete that record. Something like below:

$posts = Post::withTrashed()->whereIn('_id', $request->ids);
$deleted_post_ids = [];
$not_deleted_post_ids = [];
foreach($posts as $post) {
    if ($post->owner_id == auth()->id() || auth()->user()->hasAnyRole(['super-admin', 'admin', 'moderator']) {
      array_push($deleted_post_ids, $post->forceDelete());
    }
    else {
      array_push($not_deleted_post_ids, $post->id);
    }
}

return response()->json([
    'success' => [
        'message' => 'posts deleted successfully',
        'ids' => $deleted_post_ids,
    ],
    'error' => [
        'message' => 'not authorized',
        'ids' => $not_deleted_post_ids,
    ],
], 200);

But in that case, for each record, it is making a database query to delete the record, which I think is not the correct way to go.


Other solution that I can think of is:

$posts = Post::withTrashed()->whereIn('_id', $request->ids);
$deleted_post_ids = [];
$not_deleted_post_ids = [];

if (!auth()->user()->hasAnyRole(['super-admin', 'admin', 'moderator'])
{
  $posts = $post->where('owner_id', auth()->id());
}

$deleted_post_ids = $posts->forceDelete();
$not_deleted_post_ids = array_diff($request->ids, $deleted_post_ids);

Actually I'm thinking of below soulution:

$posts = Post::withTrashed()->whereIn('_id', $request->ids);
$deleted_post_ids = $posts->forceDelete(); // it should take care of authorization

But how to constraint forceDelete() to delete only specific records. Is there any way I can override forceDelete() method?

Or some elegant solution is much appreciated.


Update

I can't use policy, because if I use,

$user->can('deleteBulk', [Post::class, $ids]);

It returns true/false, then how will I delete only those resources which user is authorized to? because in some cases $ids may contain a mix of authorized and unauthorized ids.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
Sadhu
  • 59
  • 9
  • 1
    Why not use Laravel's built-in authorization functionality with policies? – Devon Bessemer Jan 11 '19 at 13:47
  • Actually @Devon, I'm using [spatie laravel permission](https://github.com/spatie/laravel-permission) which internally uses laravel gates and policies. – Sadhu Jan 11 '19 at 13:50
  • Anyways I tried with policies also, and after implementation what I understood is that policies are for only handling one resource at a time but not for bulk operation. I may be wrong. – Sadhu Jan 11 '19 at 13:51

1 Answers1

1

If you're using a package that enables policies, shouldn't you be checking if the policy allows the auth user to delete the resource?

You "could" build a policy method that accepts multiple IDs, there's nothing preventing you from doing this, but most policies probably work best with an instance of the resource.

Example:

$user->can('deleteBulk', [Post::class, $ids]);

Since deletions usually aren't performed often in applications, selecting all the resources and passing each instance individually to check authorization before deleting may sound inefficient but practically won't be that noticeable.

Read laravel authorization policy method for more about writing policies. The only parameter that needs to exist is the $user, other than that, you define what gets passed and used in the method.

Sadhu
  • 59
  • 9
Devon Bessemer
  • 34,461
  • 9
  • 69
  • 95
  • I'm really sorry that right now I'm not in a position to update my question about what challenges I faced while using policies. Once I'll update it, I'll ping you. – Sadhu Jan 11 '19 at 14:00
  • Ok, make sure you actually read all the docs beforehand and see if that solves your problem. – Devon Bessemer Jan 11 '19 at 14:01
  • @Sadhu you can check them individually but a request that only performs part of the intended work is faulty in my opinion. It should either fail or succeed. – Devon Bessemer Jan 14 '19 at 11:50