Clean Controllers: Master Laravel Form Requests
Overview
Controllers often become bloated with validation rules and authorization checks that distract from the primary business logic.
Prerequisites
To follow this guide, you should be comfortable with basic required and min.
Key Libraries & Tools
- Artisan CLI: The command-line interface used to scaffold new classes.
- FormRequest Class: The base Laravel class that provides methods for authorization and validation.
- Validator: The underlying engine that processes data against defined rules.
Code Walkthrough
First, generate your request class using
php artisan make:request StorePostRequest
This creates a file in app/Http/Requests. Inside, you’ll find two primary methods. The authorize method returns a boolean to determine if the user can proceed. Unlike manual controller checks, failing this automatically triggers a 403 response.
public function authorize(): bool
{
return $this->user()->can('create', Post::class);
}
The rules method defines your data constraints. By moving these here, you can reuse the same request across different controllers or API endpoints.
public function rules(): array
{
return [
'title' => 'required|max:255',
'status' => 'required|in:draft,published',
'text' => 'required',
];
}
Finally, type-hint the request in your controller. $request->validated() to retrieve only the safe data.
Advanced Logic with the After Hook
Sometimes validation depends on external state, like checking if a user has exceeded a post limit. The after method allows you to register closures or invokable classes that run after standard rules pass. This keeps complex, conditional logic out of your controller flow.
public function after(): array
{
return [
function ($validator) {
if ($this->user()->posts()->count() > 1) {
$validator->errors()->add('title', 'Limit reached.');
}
}
];
}
Tips & Gotchas
- Automatic Redirects: If validation fails, Laravelautomatically redirects the user back to their previous location with error messages in the session.
- Initial False: New Form Requests default
authorizetofalse. Always remember to update this totrueor add your logic, otherwise, you will face constant 403 errors.
