-
-
Notifications
You must be signed in to change notification settings - Fork 1
Resource setup
This package gives you precise control over which abilities should be checked when hydrating your API resources. Some
extra methods have to be added to your models and API resources. In your models,
add the HasAbilities
trait.
use AgilePixels\ResourceAbilities\HasAbilities;
class Post extends Model
{
use HasAbilities;
}
In your API resources, add the
AgilePixels\ResourceAbilities\JsonResource\ProcessesAbilities
trait. Please do note the JsonResource
namespace.
use AgilePixels\ResourceAbilities\JsonResource\ProcessesAbilities;
class PostResource extends JsonResource
{
use ProcessesAbilities;
}
While resources transform a single model into an array, resource collections transform a collection of models into an
array. However, it is not absolutely necessary to define a resource collection class for each one of your models since
all resources provide a collection method to generate an "ad-hoc" resource collection on the fly. However, if you need
to customize the meta data returned with the collection, it is necessary to define your own resource collection.
Therefore this package also supports the use of ResourceCollection
classes. Add the
AgilePixels\ResourceAbilities\ResourceCollection\ProcessesAbilities
trait to your class.
Note the
ResourceCollection
namespace! Also, please be aware that you MUST extend ourAgilePixels\ResourceAbilities\ResourceCollection
class. This class makes sure nested ResourceCollections are also wrapped. If nested resource collections wouldn't be wrapped, the collection actions couldn't be added to the response.
use AgilePixels\ResourceAbilities\ResourceCollection\ProcessesAbilities;
use AgilePixels\ResourceAbilities\ResourceCollection;
class PostCollection extends ResourceCollection
{
use ProcessesAbilities;
}
Laravel provides two primary ways of authorizing actions: gates and policies. Therefore, the available gates and policies have to be defined first in the API resource.
Policies, like controllers, group logic around a particular model or resource. Therefore, we prefer to add abilities
to our API resources using policies. To check the current model against an entire policy, provide a policy in the
abilities()
method. This package will scan the provided PostPolicy
class for available actions and add all available
actions from the policy to the API resource.
public function toArray($request): array
{
return [
'abilities' => $this->abilities(PostPolicy::class)
];
}
To add an ability using gate check to your API resource, provide a gate in the abilities()
method. The
given action will be checked using the model that is available in the resource. As an example, in a PostResource
, the
ability view
will be checked using the action view
and the available Post
model. If you were to check this
action by hand, the result would look like Gate::check('view', $post)
.
public function toArray($request): array
{
return [
'abilities' => $this->abilities('view')
];
}
It may be the case that you want to add a policy but also some other gates. This may be achieved by calling the add()
method after the abilities()
method.
public function toArray($request): array
{
return [
'abilities' => $this->abilities('view')
->add('update')
->add('delete')
];
}
Some action checks are model specific. For instance, the actions view
, update
or delete
require a specific model to
determine whether the user is granted that ability or not. However, some actions don't need a model, such as
viewAny
or create
. In the Laravel docs, these actions are referred to as methods without models.
You might need these abilities when a collection is empty. That's why it doesn't make sense to include these
abilities on model level, but instead add them to the collection meta. Like when working with resources, these
"collection abilities" can be added using both policies and gates. To do so use the collectionAbilities()
method in
your JsonResource
class.
Since the collection has no "resource" available to authorize against, you have to provide the model class name to the
collectionAbilities()
method.
public static function collection($resource): AnonymousResourceCollection
{
return parent::collection($resource)->additional([
'abilities' => self::collectionAbilities($resource, PostPolicy::class, Post::class)
]);
}
The most used way to add abilities will probably be using a policy as described above. However, you can also check a single action for a given model class using a gate check.
public static function collection($resource): AnonymousResourceCollection
{
return parent::collection($resource)->additional([
'abilities' => self::collectionAbilities($resource, 'viewAny', Post::class)
]);
}
Like adding multiple abilities for a model, it may also be the case that you
want the same behaviour on collection level. This may be achieved by calling the add()
method after the
collectionAbilities()
method.
public static function collection($resource): AnonymousResourceCollection
{
return parent::collection($resource)->additional([
'abilities' => self::collectionAbilities($resource, 'viewAny', Post::class)
->add('create)
]);
}
If you're using a dedicated resource collection class, you don't have to use the static
collectionAbilities()
method. You can use the abilities()
in always the same way as you would in a normal
JsonResource
. However, the tiny difference is that you MUST provide the model class as second argument.
public function toArray($request): array
{
return [
'data' => $this->collection,
'abilities' => $this->abilities(PostPolicy::class, Post::class)
];
}