Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / PHP

How to Create Custom Form Request Validations in Laravel Projects

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
15 Jan 2021CPOL3 min read 25.4K   2
This tutorial describes how to create and use custom Form Request validation in your Laravel (5.8 or 6+) projects.
There are few ways to validate form submission data in Laravel. We'll review the main points of creating forms validation, paying attention on creating testable code.

Introduction

This tutorial describes how to create and use custom Form Request validation in your Laravel (5.8 or 6+) projects. There are a few ways to validate form submission data in Laravel.

Direct Validation in Controller

The standard way is to use Validator facade directly in the beginning of your controller. Let's see the example:

PHP
/**
 * Store a newly created resource in storage.
 *
 * @param \Illuminate\Http\Request $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $validator = Validator::make($request--->all(), [
        "title"  => "required|min:5|max:200",
        "body_content"=> "required|min:10",
        "blog_tag_id" => "nullable",
    ],[
        "title.required" => "Please write a title",
        "title.min" => "The title has to have at least :min characters.",
        "title.max" => "The title has to have no more than :max characters.",
        "body_content.required" => "Please write some content",
        "body_content.min" => "The content has to have at least :min characters",
    ]);

    // ... next part of code after validation
}

As you may see in this example, we perform validation inside the controller's action. It looks nice enough until you want to use the same code in other places: when you create a post in Backend or if you want to add a Unit tests. In such cases, you will copy-paste the same pieces of your code, that is not good, because you have to support all of them and such style of programming breaks DRY principle (Don't Repeat Yourself).

Using Custom Validator

So... what is the better way to implement such validation? Laravel allows us to create our own Request class, instead of using a standard \Illuminate\Http\Request and use as a function parameter. Let's see how we can do that.

The first thing you have to do it to create such a class. Run the following command:

PHP
$ php artisan make:request App\Http\Requests\MyOwnRequest

This command will create MyOwnRequest request class in App\Http\Requests\ directory. By default, it will be as follows:

PHP
namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;

class MyOwnRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }
}

Now you can move there your validation rules and replace Request parameter in store() method with MyOwnRequest.

Your controller store() method will be like below:

PHP
/**
 * Store a newly created resource in storage.
 *
 * @param \Illuminate\Http\MyOwnRequest $request
 * @return \Illuminate\Http\Response
 */
public function store(MyOwnRequest $request)
{
 
    // ... next part of code after validation
}

MyOwnRequest class will be as follows:
(Remember to turn return value of authorize() method to TRUE!)

PHP
namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;

class MyOwnRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
           "title"  => "required|min:5|max:200",
           "body_content"=> "required|min:10",
           "blog_tag_id" => "nullable",
        ];
    }
}

Looks much better, right?

Customization of Request Class

Custom Messages

Now, what if you want to specify custom validate messages? It's easy to implement with messages() method of your validator class. You simply have to define an array, where the key is a field name and the value is the custom message you want to show.

PHP
namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;

class MyOwnRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            "title"  => "required|min:5|max:200",
            "body_content"=> "required|min:10",
            "blog_tag_id" => "nullable",
        ];
    }

    /**
     * Custom message for validation
     *
     * @return array
     */
    public function messages()
    {
        return [
            "title.required" => "Please write a title",
            "title.min" => "The title has to have at least :min characters.",
            "title.max" => "The title has to have no more than :max characters.",
            "body_content.required" => "Please write some content",
            "body_content.min" => "The content has to have at least :min characters",
        ];
    }
}

Validation Set of Fields

Ok, now it looks better. But what to do if you need to validate a set of fields, let's say: few checkboxes or few file fields? In this case, you may use asterisk * to prepare validation rules. Check below how we define validation rules for set of fields. I hope it's clear and understandable enough.

PHP
public function rules(): array
{
   return [
      "files.*" => "required|image|mimes:jpg,jpeg,png",
      "attrs.*.from" => "nullable|numeric",
      "attrs.*.to" => "nullable|numeric",
   ];
}

Special Naming for Attributes

As you know, Laravel creates validation messages automatically, so sometimes you will need to provide special names to your fields. You may use the following language lines to swap attribute place-holders with something more reader friendly such as E-Mail Address instead of "email" or indexes in array. This simply helps us make messages a little cleaner.

PHP
public function attributes(): array
{
   return [
      "receivers" => "Nice name",
      "subject" => "Like name",
      "body" => "Another Name",
      "notify.blog.*" => "Blog Notification value",
   ];
}

Add Your Own Validation

Now, if you want to perform your own validation, you may use the withValidator() method. It's useful when you need to perform additional or very complicated validation, after the main validation was passed (or not). In the example below, we check if an email presents in a list of pre-approved emails. Take into account that there are some methods you may use:

$validator->after()
$validator->fails()
etc.

PHP
/**
* @param  \Illuminate\Validation\Validator  $validator
* @return void
*/
public function withValidator(Validator $validator)
{
   $email = $validator->getData()['email'] ?? '';
   $validator->after(
      function ($validator) use ($email) {
         if (is_null(\DB::table('pre_approved')->where('email',$email)->first())) {
            $validator->errors()->add(
               'email',
               'This email does not exist on our pre-approved email list'
            );
         }
      }
   );                            
}

Don't Forget Authorization

As mentioned before, the form request class also contains an authorize method. You may check if the authenticated user actually has the authority to change a given resource. Let's see an example when user actually owns a blog comment and attempts to update it:

PHP
/**
 * Check if the user is authorized to make this request.
 * @return bool
 */
public function authorize()
{
   $comment = Comment::find($this->route('comment'));
   return $comment && $this->user()->can('update', $comment);
}

Custom Redirecting

And the last thing, if you want to redefine a route if validation fails, you may do that by redefining $redirectRoute property:

PHP
// The named route to redirect to if validation fails.
protected $redirectRoute = 'home';

History

  • 15th January, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO ApPHP
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMessage Closed Pin
12-Jan-22 22:56
madisondade12312-Jan-22 22:56 
QuestionHow do I validate array of object? Pin
Member 1407496114-Jun-21 3:49
Member 1407496114-Jun-21 3:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.