I have a method in a policy which checks whether a user can access a page. The page's name along with the current user are the parameters of the policy's method:
public function pageAllowed(User $user, string $page)
{
return $this->allGranted($user) || $user->hasPermission(self::PREFIX_PAGE . '.' . $page);
}
The problem is that I can't normally check the policy from blade, if I do
@can('page-allowed', [Auth::user(),'page.name'])
<li ng-class="{ active: properties.isActive('/feedback')}"><a href="#/feedback">Feedback</a></li>
@endcan
then Laravel duplicates the user param when invoking the policy's method because of the way it invokes the method, see \Illuminate\Auth\Access\Gate::resolvePolicyCallback
, line 388:
return call_user_func_array(
[$instance, $ability], array_merge([$user], $arguments)
);
As you can see it merges the resolved user (it additionally resolves it itself) with the passed parameters. The first passed parameter is the current user. The second one is the page's name. It ends up with the following parameters passed to the policy's method: User, User, 'page.name'
. The first two parameters are identical and I want to get rid of this duplication.
I would be happy not to pass the user from blade, but in this case Laravel can't resolve the policy, since it looks up the policy by the first passed parameter! See \Illuminate\Auth\Access\Gate::firstArgumentCorrespondsToPolicy
, line 346:
return is_string($arguments[0]) && isset($this->policies[$arguments[0]]);
So if I don't pass the user as the first param, it tries to resolve the policy by the page name. I'm totally confused, please help.
UPDATE
I've found a clumsy solution, use the blade @if statement with the policy() helper
@if(policy(Auth::user())->pageAllowed(Auth::user(),'feedback'))
<li ng-class="{ active: properties.isActive('/feedback')}"><a href="#/feedback">Feedback</a></li>
@endif
instead of the @can statement. But I'm wondering what I'm doing wrong.
Okay, seems I've understood the logical reason of duplication the User model - Laravel passes the current user by default to all policies as the first parameter. I created a policy for the user model and I must pass the model when checking the policy. That's why the duplication happens - the first model instance is passed by the framework, the second by me. If it was a Post model, the parameters would be: User, Post, ... without any duplication.