Laravel 8 Form Validation

Why we need to perform form validation?

General rule of thumb is to perform validation on input request. You can perform client and server side validation to make sure you are adding safe data to your database.

It is very crucial to perform form validation to avoid different types of hacking for example:

  • cross-site scripting
  • database injections etc..

Using laravel framework form validation is so much easier. You can write your own custom validator as well as you can use laravel's in-build form validators.

How does form validation work?

For example, if you have a blog website where your user can login and register. You create login and registration form now when user enters form details and submit the request to the backend server.

This request in laravel goes throw different stage. Let's checkout the request flow:

Create contact us form using laravel and validate the data

In order to understand how laravel validation works we would have to create a sample form and than validate the form. Let's say that you have a contact us form on your website.

You want to create create a page where you want to display contact us form and then perform laravel backend validation using laravel request class. In order to create a contact us page we would have to follow instructions below:

  • Define GET /contact-us troute to show our form
  • Define POST /contact-us route to validate submit form request
  • Create ContactUsController with create and store methods

Define routes for our new page

Let's open routes/web.php file and add following routes:

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::namespace('App\Http\Controllers')->group(function () {

    // Route to show post form
    Route::get('/contact-us', 'ContactUsController@create')->name('contact-us');

    // Route to submit form request
    Route::post('/contact-us', 'ContactUsController@store')->name('contact-us');
});

Now that we decided what would be the routes for our contact-us page we need to point route to proper controller methods.

When user submits the contact us form it will go to controller store method this is where we need to perform our form validation. Therefore, we would create a seperate validation request class for our method.

Open terminal window and let's create a new controller using following command:

# create controller for our routes
php artisan make:controller ContactUsController

# create request validation class for our submit method
php artisan make:request ContactFormRequest​

Let's open our controller and add following code:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Response;
use Illuminate\Http\RedirectResponse;
use App\Http\Requests\ContactFormRequest;

class ContactUsController extends Controller
{
    public function create(): Response
    {
        return response()->view('contact-us');
    }

    public function store(ContactFormRequest $request): RedirectResponse
    {
        // get validated form data
        $validatedData = $request->validated();
        
        return response()
            ->redirectToRoute('contact-us')   // redirect user to GET /contact-us page
            ->withErrors($request)            // pass all validation errors  
            ->withInput();                    // pass form data 
    }
}

Let's understand what is going on in each method:

  • GET /contact-us page points to ContactUsController@create method
    • we would just display form using our contact-us view
  • POST /contact-us page points to ContactUsController@store method
    • ContactFormRequest is injected using dependecy injection to our method
    • Laravel calls the ContactFormRequest class and perform form validation based on rules defined in this class
    • Laravel also calls authorize method before it perform the validation to make sure user has access to view this page
    • This method basically does following thing
      • performs the validation
      • redirect user to contact-us form page with any form errors or previously submitted form data

Finally, we need to create a view for our contact us form. Let's create a file called contact-us.blade.php under resources/views with following contents.

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body {font-family: Arial, Helvetica, sans-serif;}
        * {box-sizing: border-box;}

        input[type=text], textarea {
            width: 100%;
            padding: 12px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
            margin-top: 6px;
            margin-bottom: 16px;
            resize: vertical;
        }

        input[type=submit] {
            background-color: #04AA6D;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        input[type=submit]:hover {
            background-color: #45a049;
        }

        .container {
            border-radius: 5px;
            background-color: #f2f2f2;
            padding: 20px;
            margin: 0 auto;
            width: 50%;
        }
    </style>
</head>
<body>


<div class="container">
    <h3>Contact Form</h3>
    <br>

    <form method="POST" action="{{ route('contact-us') }}">
        @csrf

        @if ($errors->any())
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
        @endif

        <label for="email">Email</label>
        <input type="text" id="email" name="email" placeholder="Your email address.." value="{{ old('email') }}">

        <label for="subject">Subject</label>
        <input type="text" id="subject" name="subject" placeholder="Enter Subject for contacting" value="{{ old('subject') }}">

        <label for="comments">Comments</label>
        <textarea id="comments" name="comments" placeholder="Write something.." style="height:200px">{{ old('comments') }}</textarea>

        <input type="submit" value="Submit">
    </form>
</div>

</body>
</html>

ContactFormRequst class

Now, we would open newly created file under: app/Http/Requests/ContactFormRequest.php class and add following rules:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactFormRequest 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 [
            'email' => 'required|email',
            'comments' => 'required|string|min:10',
            'subject' => 'required|string|min:5|max:45',
        ];
    }
}

Tesing our changes

Now, that we have valid route that points to valid controller methods and also we have created seperate form validator calss its time to test out our changes. Open browser and hit http://localhost/contact-us page you will see following page.

Alright, you will see a form like above. Now, when you hit the submit button  without filling your form you will see following errors.

What did we learn today?

  • how to create new route
  • how to tie a route to controller method
  • how to create seperate validation class
  • validation class
    • authorize method - this method is best place to check if user is allowed to access the form or not
    • rules method - shows list of form fields with rules to check their validation
  • how to pre-populate form data with old request form data

Repopulating Forms

Laravel also provides a global old helper. If you are displaying old input within a Blade template, it is more convenient to use the old helper to repopulate the form.

The old method will pull the previously flashed input data from the session:

<label for="email">Email</label>
<input type="text" id="email" name="email" placeholder="Your email address.." value="{{ old('email') }}">

Laravel default form validation methods

If you want to explore what rules are available that you can use to perform form validation use following link:

Laravel form Validation methods