Database driver: pgsql
Models location: app/Models
I defined a gate named view as below in AuthServiceProvider.php:
Gate::define('view', function (User $user, User $requestedUser) {
return $user->id == $requestedUser->id;
});
If I use this gate in my routes file api.php as below:
Route::group(['middleware' => ['auth:api', 'can:view,user']], function () {
Route::get('users/{user}', 'UserController@show');
});
FYI UserController@show:
public function show(Request $request, $user)
{
return response()->json($user, 200);
}
Then I get this error:
FatalThrowableError in AuthServiceProvider.php line 38:
Type error: Argument 2 passed to ApiProvidersAuthServiceProvider::ApiProviders{closure}() must be an instance of ApiModelsUser, string given, called in /path-to-project/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 274
The line 38 matches the line where the view gate is defined.
And I don't get any errors if I explicitly bind the {user} parameter to the User model:
Route::model('user', \Api\Models\User::class);
So I am pretty sure there is an implicit route model binding problem.
But everything works fine if I retrieve the user as below (closure):
Route::group(['middleware' => ['auth:api', 'can:view,user']], function () {
Route::get('/users/{user}', function (\Api\Models\User $user) {
return $user;
});
});
I cannot understand why the implicit route model binding does not work when calling a method instead of using a closure. Am I doing something wrong or is it a bug?
That makes sense, as far as laravel knows {user} stores a string so it passes it to the gate, you need to explicitly tell laravel that this URL segment should be converted to a model.
It is not that simple :
You have to typehint the user on your controller method.
Most helpful comment
You have to typehint the user on your controller method.