Photo by Danny Lines on Unsplash
Demystifying Gates in Laravel
If you find the concept of "gates" in Laravel a bit confusing, don't worry. You're not alone.
I found gates a bit confusing for quite some time. I just ignored them for the first couple of years developing Laravel applications. I was confused by the naming and wasn't sure exactly what they were.
Let me get this out of the way:
Gates are permissions.
That should clarify a lot of the confusion. They're simply portable logic you can check for across your app. For example, you can define a gate in a service provider. This example is from the docs:
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
Now, we can check for this in several different places in our app. For example, our controller (another example from the docs):
class PostController extends Controller
{
public function update(Request $request, Post $post)
{
if (! Gate::allows('update-post', $post)) {
abort(403);
}
// Update the post...
}
}
You can also reference it in things like a blade file:
@can('update-post')
<a href="{{ route('posts.edit', ['post' => $post]) }}">Update</a>
@endcan
Use Policies Instead
Now that you get an idea of what gates are, my strong suggestion is to use policies instead.
Policies are classes with related methods around a particular model or idea. When creating a policy for a model, you can pass the --model=Post
flag which will create a policy with authorization logic around each CRUD (create, read, update, delete) operation on your model.
Here's an example of a model policy class:
class PostPolicy {
public function view(User $user, Post $post)
{
// ...
}
public function create(User $user)
{
// ...
}
public function update(User $user, Post $post)
{
// ...
}
public function delete(User $user, Post $post)
{
// ...
}
}
You don't need to manually write various gates in your service provider. You can simply create a model policy, and Laravel provides an easy API throughout the app to use this policy.
This is an example from the docs of what a check looks like in a policy:
class PostPolicy
{
// ...
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
Now we can easily check against this logic in places like our routes file:
Route::get('/posts/{post}/edit', [PostsController::class, 'update'])->middleware('can:update,post');
The cool part about the snippet above is ->middleware('can:update,post');
method.
In a single line of code, it creates a middleware that will automatically return an 403
if it fails the update
method in our policy above.
So that's all gates are! Permissions. Nothing scary. But these days I exclusively use Policy classes, as well as Spatie's Laravel Permissions package.
Happy coding 🥳