I'm trying to make a generic Laravel authorization policy since its repetitive to write checking for a permission in the corresponding format:
- {model}_view
- {model}_store
- {model}_update
- {model}_delete
- {model}_restore
- {model}_force_delete
This is what my PermissionService is returning.
The only thing that I'm struggling with is extending it and having proper typehinting for the model being checked without using more docblocks (in the implementation class).
<?php
namespace App/Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;
use Illuminate\Database\Eloquent\Model;
use App\Services\PermissionService;
/** @template TModel of Model */
abstract class BasePolicy
{
use HandlesAuthorization;
public function viewAny(User $auth): Response|bool
{
return $auth->can(PermissionService::viewPermission($this->model()));
}
/** @param TModel $model */
public function view(User $auth, $model): Response|bool
{
return $auth->can(PermissionService::viewPermission($this->model()));
}
public function create(User $auth): Response|bool
{
return $auth->can(PermissionService::createPermission($this->model()));
}
/** @param TModel $model */
public function update(User $auth, $model): Response|bool
{
return $auth->can(PermissionService::updatePermission($this->model()));
}
/** @param TModel $model */
public function delete(User $auth, $model): Response|bool
{
return $auth->can(PermissionService::deletePermission($this->model()));
}
/** @param TModel $model */
public function restore(User $auth, $model): Response|bool
{
return $auth->can(PermissionService::restorePermission($this->model()));
}
/** @param TModel $model */
public function forceDelete(User $auth, $model): Response|bool
{
return $auth->can(PermissionService::forceDeletePermission($this->model()));
}
/** @return class-string<TModel> */
abstract public function model(): string;
}
So I've tried a generic called TModel in the docblocks but when using it in the implementation class shown below, it would still think it's a default Eloquent Model.
<?php
namespace App\Policies;
use App\Models\User;
/** @template TModel of User */
class UserPolicy extends BasePolicy
{
/** {@inheritdoc} */
public function view(User $auth, $model): Response|bool
{
// When hovering/click on $model, it still remains an Eloquent model instead of User
return parent::view($auth, $model);
}
/** {@inheritdoc} */
public function model(): string
{
return User::class;
}
}
Am I doing anything wrong in overwriting/defining the TModel generic?
Or are there any totally different suggestions? Possibly for allowing the parameter type natively (best solution)?
If it helps, the IDE that I'm using is PHPStorm (newest version).