I have multiple Policy classes.
and these policies' update, delete, restore
functions have the same logic evaluation which is to check if the authenticated user owns the resource.
For example, I have a Post and a Comment model.
Then for PostPolicy and CommentPolicy, both of their update, delete, restore
functions will all have:
public function update(User $user, Post $post)
{
return $user->id == $post->user_id;
}
public function delete(User $user, Post $post)
{
return $user->id == $post->user_id;
}
public function restore(User $user, Post $post)
{
return $user->id == $post->user_id;
}
// Also the same with CommentPolicy
With that, I might as well have a trait like this:
trait AuthorizableTrait
{
public function authorize(User $user, Resource $resource)
{
return $user->id == $resource->user_id;
}
}
So, my question is, is it possible to inject a dynamic instance of the current model inside the trait, for example, Post
and Comment
models now will become Resource
? if so, how?
CodePudding user response:
There's a couple other ways to handle this too. In your trait, you can simply replace Resource $resource
with Model $model
. As long as your Post.php
, Comment.php
and Resource.php
Models have are class ... extends Model { ... }
, then it'll accept it:
<?php
namespace App\Models\Traits;
use Illuminate\Database\Eloquent\Model;
trait AuthorizableTrait {
public function authorize(User $user, Model $model) {
return $user->id == $model->user_id;
}
}
If that is too "loose", and you don't want this available for all Models (i.e. in the possible case that not all Models have a user_id
column), then you can use Union Types (assuming you are on a compatible PHP version):
<?php
namespace App\Models\Traits;
use App\Models\Post;
use App\Models\Comment;
use App\Models\Resource;
trait AuthorizableTrait {
public function authorize(User $user, Post|Comment|Resource $model) {
return $user->id == $model->user_id;
}
}
CodePudding user response:
If you don't specify the type of the authorize function second parameter, I think it will be all right.
If you define the following function, without the Resource
type:
public function authorize(User $user, $resource)
You will be able to send everything you want in $resource
(a post, a comment, etc.) and then the check will work... unless you always have a user_id
attribute.
CodePudding user response:
UPDATE:
I decided to use PHPStan.
And the neon script requires that all function's parameter and return type must be specified.
Thus, I ended up specifying Model
as $resource
's type.
public function authorize(User $user, Model $resource)
However, for some reason, in your use-case, Model
is too generic.
Then you can do something like what @TimLewis did.