Form requests in Laravel are pretty cool stuff, right?


We create a custom request class and move all our form validation logic from controller to the form request class. All we need to do then is type-hint this request on the controller method and voilà! The incoming form request is validated even before it hits the controller.

But sometimes when we create multiple form requests, we end up duplicating code. For example, consider a simple form for writing blogs. Say the form contains title , category_id , short_overview and content fields. So to validate these fields, we create a new form request, say StoreBlogPostFormRequest and define these rules:

 
class StoreBlogPostFormRequest extends FormRequest
{
    public function rules()
    {
        return [
            'title' => 'required|max:255',
            'category_id' => 'required',
            'short_overview' => 'required|max:200',
            'content' => 'required',
        ];
    }
}

Now when we need to edit a post, say we introduce a new text field in the edit post form, edit_summary , which will contain what changes we made to the original article. So we create a new form request, e.g. UpdateBlogPostFormRequest , that includes validation logic for this extra field.

class UpdateBlogPostFormRequest extends FormRequest
{
    public function rules()
    {
        return [
            'title' => 'required|max:255',
            'category_id' => 'required',
            'short_overview' => 'required|max:200',
            'content' => 'required',
            'edit_summary' => 'required|max:300'
        ];
    }
}

See the problem here? We are unnecessarily duplicating the validation logic for title , category_id , short_overview and content fields, thus violating DRY Principle. This code duplication increases as we introduce custom error messages on each form requests.


So how do we reuse the same code and add only the extra fields when necessary? ¿ⓧ_ⓧﮌ


There is an easy way. In our UpdateBlogPostFormRequest class, we can extend the StoreBlogPostFormRequest class and include only the extra field in the extended class.

 
<?php
 
namespace App\Http\Requests;
 
use App\Http\Requests\StoreBlogPostFormRequest;
 
class UpdateBlogPostFormRequest extends StoreBlogPostFormRequest
{
    public function rules()
    {
        return array_merge(parent::rules(), [
            'edit_summary' => 'required|max:300'
        ]);
    }
}

parent::rules() will return all the rules that we defined in StoreBlogPostFormRequest which are common to our UpdateBlogPostFormRequest class. We then merge the extra field edit_summary and return the new array as our set of rules for update form request.

Similarly, if we have a messages() method on our StoreBlogPostFormRequest class for displaying custom error messages, we can reuse them for the same fields and include the new custom message for the extra field on our update form request.


<?php
 
namespace App\Http\Requests;
 
use App\Http\Requests\StoreBlogPostFormRequest;
 
class UpdateBlogPostFormRequest extends StoreBlogPostFormRequest
{
    public function rules()
    {
        return array_merge(parent::rules(), [
            'edit_summary' => 'required|max:300'
        ]);
    }
 
    public function messages()
    {
        return array_merge(parent::messages(), [
            'edit_summary.required' => 'Please provide a summary of your changes',
            'edit_summary.max' => 'Please keep the summary less than 300 characters',
        ]);
    }
}

That’s all we need to DRY up our validation logic.


Note that extending a form request class will override the rules() and messages() method on the parent class. Therefore, if we don’t have a extra custom message to be displayed, for example, let’s say in this case we do not want to show custom messages for edit_summary field, we should make sure to grab the messages from the parent class:

public function messages()
{
    return parent::messages();
}

Otherwise we will overwrite the messages from parent class.

ヽ(´▽`)/