Laravel Validation: How To Add Form Validation In Laravel

Laravel Validation: How To Add Form Validation In Laravel

 

Laravel Validation: How To Add Form Validation In Laravel



Laravel provides us the several different methods to validate our application’s data. Out of the box, Laravel’s base controller class uses the ValidatesRequests trait, which provides a convenient method to validate n incoming HTTP requests with a variety of robust validation rules.

Laravel Validation

Laravel provides several different approaches to validate your application’s incoming data. By default, Laravel’s base controller class uses a ValidatesRequests trait that provides a convenient method to validate incoming HTTP requests with a variety of powerful validation rules.

Our first step is to install Laravel. If you are new to Laravel, then check out my Laravel 7 CRUD tutorial on this blog. Right now, Laravel is the latest version. In the future, you may need to specify the version while installing Laravel.

So, install the Laravel using the following command.

composer create-project --prefer-dist laravel/laravel8

// or

laravel new laravel8

Create the FormController.php file.

php artisan make:controller FormController

Add two methods inside the FormController.php file.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class FormController extends Controller
{
    public function create()
    {

    }

    public function store(Request $request)
    {
        
    }
}

Now, write the two routes inside the routes >> web.php file, which handles the URI of our application.

// web.php

Route::get('form', 'FormController@create')->name('form.create');
Route::post('form', 'FormController@store')->name('form.store');

Now, create the model and migration file using the following command.

php artisan make:model Form -m

Write the following code inside the create_forms_table.php file.

public function up()
{
        Schema::create('forms', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('item_name');
            $table->string('sku_no');
            $table->integer('price');
            $table->timestamps();
        });
}

Now, create the table using the following command.

php artisan migrate

Also, we can prevent mass assignment exceptions, add the $fillable property.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Form extends Model
{
    protected $fillable = ['item_name', 'sku_no', 'price'];
}

Inside the views folder, create a layout file called layout.blade.php file and add the following code.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Laravel 6 Validation Example</title>
  <link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css" />
</head>
<body>
  <div class="container">
    @yield('content')
  </div>
  <script src="{{ asset('js/app.js') }}" type="text/js"></script>
</body>
</html>

Now, in the same views folder, create a file called create.blade.php and add the following code.

@extends('layout')

@section('content')
<style>
  .uper {
    margin-top: 40px;
  }
</style>
<div class="card uper">
  <div class="card-header">
    Add Item
  </div>
  <div class="card-body">
      <form method="post" action="{{ route('form.store') }}">
          <div class="form-group">
              @csrf
              <label for="name">Item Name:</label>
              <input type="text" class="form-control" name="item_name"/>
          </div>
          <div class="form-group">
              <label for="price">SKU Number :</label>
              <input type="text" class="form-control" name="sku_no"/>
          </div>
          <div class="form-group">
              <label for="quantity">Item Price :</label>
              <input type="text" class="form-control" name="price"/>
          </div>
          <button type="submit" class="btn btn-primary">Create Item</button>
      </form>
  </div>
</div>
@endsection

Now, write the FormController’s create() function.

// FormController.php

public function create()
{
    return view('create');
}

Now, you can see the form on this URL: http://localhost:8000/form.

Writing A Validation Logic

Write the validation logic inside the FormController’s store() function.

public function store(Request $request)
{
        $validatedData = $request->validate([
            'item_name' => 'required|max:255',
            'sku_no' => 'required|alpha_num',
            'price' => 'required|numeric',
        ]);
        \App\Form::create($validatedData);

        return response()->json('Form is successfully validated and data has been saved');
}

Now, go to the form and try to submit the form. It won’t send, but you do not see any errors.

Displaying Validation Errors

Okay, so now, we need to write the following snippet inside the create.blade.php file.

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

If the incoming request parameters do not pass the given validation rules, then as mentioned previously, Laravel will automatically redirect a user back to their previous location.

All the validation errors will automatically be flashed to a session.

One thing to notice here is that we did not have to explicitly bind all the error messages to a view in the GET route.

It is because Laravel will check for the errors in the session data, and automatically attach them to a view if they are available.

The $errors variable will be the instance of Illuminate\Support\MessageBag.

So, the final create.blade.php file is the following.

@extends('layout')

@section('content')
<style>
  .uper {
    margin-top: 40px;
  }
</style>
<div class="card uper">
  <div class="card-header">
    Add Item
  </div>
  <div class="card-body">
    @if ($errors->any())
      <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
              <li>{{ $error }}</li>
            @endforeach
        </ul>
      </div><br />
    @endif
      <form method="post" action="{{ route('form.store') }}">
          <div class="form-group">
              @csrf
              <label for="name">Item Name:</label>
              <input type="text" class="form-control" name="item_name"/>
          </div>
          <div class="form-group">
              <label for="price">SKU Number :</label>
              <input type="text" class="form-control" name="sku_no"/>
          </div>
          <div class="form-group">
              <label for="quantity">Item Price :</label>
              <input type="text" class="form-control" name="price"/>
          </div>
          <button type="submit" class="btn btn-primary">Create Item</button>
      </form>
  </div>
</div>
@endsection

The $errors variable is bound to a view by the Illuminate\View\Middleware\ShareErrorsFromSession middleware, which is provided by a web middleware group.

When this middleware is applied, the $errors variable will always be available in the views, allowing us to conveniently assume the $errors variable is always defined and can be safely used inside your HTML code.

The @error Directive

You can also use the @error Blade directive to quickly check if the validation error messages exist for a given attribute.

Within the @error Directive, you may echo the $message variable to display the error message:

<div class="form-group">
   @csrf
   <label for="name">Item Name:</label>
   <input type="text" class="form-control" name="item_name"/>
    @error('item_name')
          <div class="alert alert-danger">{{ $message }}</div>
    @enderror
</div>

Optional Fields

Out of the box, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your app’s global middleware array.

This middleware are included in the stack by an App\Http\Kernel class.

Because of this middleware, you will often need to mark your “optional” request fields as nullable if you do not want a validator to consider the null values as invalid.

For instance:

$request->validate([
    'item_name' => 'required|max:255',
    'sku_no' => 'required|alpha_num',
    'price' => 'required|numeric',
    'publish_at' => 'nullable|date',
]);

In this example, we are specifying that a publish_at field may be either null or the valid date representation.

If a nullable modifier is not added to the rule definition, a validator would consider null the invalid date.

AJAX Requests & Validation

In this example, we used the traditional form to send data to an app.

However, many applications use AJAX requests.

When using the validate() method during the AJAX request, Laravel will not generate the redirect response.

Instead, Laravel generates the JSON response containing all of the validation errors. That JSON response will be sent with a 422 HTTP status code.

Form Request Validation In Laravel

For more complex validation cases, you may wish to create the “form request”.

Form requests are custom request classes that contain all the validation logic.

If we need to create the form request class, use the make: request Artisan CLI command:

php artisan make:request ValidateRequest

The generated class will be placed in an app/Http/Requests directory.

If the directory does not exist, it will be generated when you run the make: request command.

Let’s add the few validation rules to the rules method:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ValidateRequest 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 [
            'item_name' => 'required|max:255',
            'sku_no' => 'required|alpha_num',
            'price' => 'required|numeric',
        ];
    }
}

So, how are the validation rules evaluated?

All you need to do is type-hint a request on your controller method.

An incoming form request is validated before the controller method is called, meaning we do not need to clutter the controller with any validation logic.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests\ValidateRequest;

class FormController extends Controller
{
    public function create()
    {
        return view('create');
    }

    public function store(ValidateRequest $request)
    {
        $validatedData = $request->validated();
        \App\Form::create($validatedData);

        return response()->json('Form is successfully validated and data has been saved');
    }
}

Manually Creating Validators

If we do not want to use the validate() method on the request, you may create the validator object manually using the Validator facade.

The make method on a facade generates the new validator instance.

See the following function inside the FormController.php file.

public function store(ValidateRequest $request)
{
        $validator = \Validator::make($request->all(), [
            'item_name' => 'required|max:255',
            'sku_no' => 'required|alpha_num',
            'price' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            return redirect('form')
                        ->withErrors($validator)
                        ->withInput();
        }

        \App\Form::create([
            'item_name' => $request->item_name, 
            'sku_no' => $request->sku_no,
            'price' => $request->sku_no
        ]);

        return response()->json('Form is successfully validated and data has been saved');
}

The first argument passed to a make method is the data under validation.

The second argument is the validation rules that should be applied to the data.

After checking if a request validation failed, you may use the with error method to flash the error messages to a session.

When using that method, the $errors variable will automatically be shared with your views after redirection, allowing us to display them back to a user easily.

The with errors method accepts the validator, the MessageBag, or a PHP array.

Named Error Bags

If you have multiple forms on a single page, you may wish to name the MessageBag of errors, allowing us to retrieve the error messages for the particular form.

Pass the name as the second argument to with errors:

return redirect('register')
            ->withErrors($validator, 'login');

You may then access the named MessageBag object from the $errors variable.

{{ $errors->login->first('email') }}

Working With The Error Messages

After calling the errors method on a Validator instance, you will receive the Illuminate\Support\MessageBag instance, which has a variety of convenient methods for working with error messages.

The $errors variable which are automatically made available to all the views is also the instance of the MessageBag class.

Retrieving The First Error Message For The Field

If we want to retrieve the first error message for the given field, use the first method:

$errors = $validator->errors();

echo $errors->first('email');

Retrieving All Error Messages For A Field

If you need to retrieve the array of all of the messages for the given field, use the get method.

foreach ($errors->get('email') as $message) {
    //
}

If you are validating the array form field, you may retrieve all the messages for each of the array items using the * character.

foreach ($errors->get('attachments.*') as $message) {
    //
}

So, we have lots of options to add validation in the form in Laravel.

Finally, the Laravel Validation Example is over.

Reactions

Post a Comment

0 Comments

close