facebook
George Anderson
Frontend and backend development guru, lover of all things computer... and cats! Hopes to make your coder life a breeze by sharing some tips and tricks of the trade.
Posted on Oct 11th 2018

Request input validation is an important aspect of building any application, ensuring that the input matches values expected to complete a given operation. Laravel is a PHP web framework, following the MVC architectural pattern. It provides several built-in methods, which help in handling request input validation.  In this article, we will be looking at some of these methods.

We will be considering four different methods that we can use to perform validation in Laravel, as well as how to create custom validation rules.

Configuring the Development Environment

For this tutorial, I will be using the Eclipse IDE with the CodeMix plugin installed. To install CodeMix into your Eclipse environment, please follow the installation instructions on this page, or get it from the Eclipse marketplace. You can install the Laravel extension using the CodeMix extension browser. For this tutorial, we are using Laravel artisan and Laravel blade snippets extensions respectively. Click the image below to see a recording.

In order to proceed with this tutorial, you must have the following installed:

  • PHP can be installed in several ways, like using the PHP installer or an all-in-one package, such as XAMPP, WAMP and so on (which gives added functionalities, for instance, setting up Apache, phpMyAdmin etc.)
  • You also need to install the PHP dependency manager, Composer, which will be used to install the various dependencies needed by Laravel.
  • Finally, the Laravel installer is required to create a new project; it can be installed globally using Composer in the terminal, with the command below:
    composer global require "laravel/installer"
CodeMix 2 is here to further improve your new amazing Eclipse IDE experience with the best of VS Code tech and add-on extensions built for Code OSS. Enjoy its ready-to-go technology packs and get superb support for JavaScript, TypeScript, PHP, Python, and other languages.

Getting Started

Now, open the integrated Terminal+ in CodeMix 2.0. alternatively, it can be opened using the command `Ctrl + Shift + P`) as shown below.

Finally, the Laravel installer is required to create a new project; it can be installed using Composer in the Terminal+, with the command below which installs Laravel for global usage. In the opened Terminal+ panel enter the following command:

composer global require "laravel/installer"

Now again in the opened Terminal+, we will create the Laravel Project using the following command:

laravel new project_name

Development

In order to perform validation, we need inputs. To provide input, we would create a form which would receive user inputs and post it to the server. The form would also provide a way for us to give feedback to the user on invalid inputs. We create this form in a new file called `user_form.blade.php` in the `resource/views` directory. The file should contain the code below:

    @extends('layouts.app')
    
    @section('content')
    <div class="container">
      <form method="POST" action="{{ route('create_user') }}">
      {{ csrf_field() }}
      <div>
        <label>Name</label>
        <input name="name" type="text" 
            class="form-control{{ $errors->has('name') ? ' is-invalid' : '' }}" 
            value="{{ old('name') }}"
        />
        @if ($errors->has('name'))
          <span class="invalid-feedback" role="alert">
            <strong>{{ $errors->first('name') }}</strong>
          </span>
        @endif
      </div>
      <div>
        <label>email</label>
        <input name="email" type="text"  
            class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" 
            value="{{ old('email') }}"
        />
        @if ($errors->has('email'))
          <span class="invalid-feedback" role="alert">
            <strong>{{ $errors->first('email') }}</strong>
          </span>
        @endif
      </div>
      <div>
        <label>Username</label>
        <input name="username" type="text"  
            class="form-control{{ $errors->has('username') ? ' is-invalid' : '' }}" 
            value="{{ old('username') }}"
        />
        @if ($errors->has('username'))
          <span class="invalid-feedback" role="alert">
            <strong>{{ $errors->first('username') }}</strong>
          </span>
        @endif
      </div>
      <div>
        <label>Password</label>
        <input name="password" type="password"  
            class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}"
        />
        @if ($errors->has('password'))
          <span class="invalid-feedback" role="alert">
            <strong>{{ $errors->first('password') }}</strong>
          </span>
        @endif
      </div>
      <div>
        <label>Confirm Password</label>
        <input name="password_confirmation" type="password"  
            class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" 
        />
      </div>
      <div>
        <label>Image</label>
        <input name="images[]" type="file"  multiple
            class="form-control{{ $errors->has('images.*') ? ' is-invalid' : '' }}"
        />
        @if ($errors->has('images.*'))
        
          @foreach( $errors->get('images.*') as $err)
            <span class="invalid-feedback" role="alert">
              <strong>{{ $err[0] }}</strong>
            </span>
          @endforeach
        @endif
      </div>
      <br>
      <button type="submit" class="btn btn-success">submit</button>
    </form>
    </div>
    @endsection

In the code snippet above, we provided a form where all input has been conditionally styled to include the class name `is invalid` if there was an error whose name is equal to that of the input field, as well as render a span containing the error message for that input.

The form posts to a named route which we would define in the `routes/web.php` file, where we would also create a route to show the form, as demonstrated below: 

Next, we need to create the controller that we referenced in the routes file. We do this using the following artisan command in the opened Terminal+:

php artisan make:controller ControllerName

Now we need to create a function to render the form in the view we had created, as well as a function that receives the inputs and validates them. We do this by navigating to the `app/Http/Controllers/UserFormController.php` file we had created, and edit it as shown below:

Validation Methods

  • Using the in controller validator
    The most common method of validating in Laravel, is the validator in the controller (which is available through the ValidatesRequests trait used by the base controller in Laravel).  Custom error messages could be passed as the final optional parameter.
        public function store(Request $request)
        {
          $this->validate($request, [
              'name' => 'required',
              'email' => 'required|email|unique:users|max:255',
              'age' => 'required|integer|between:1,200',
              'username' => 'required|unique:users|max:255',
              'password' => 'required|string|min:6|confirmed',
              'images.*' => 'mimes:jpg,jpeg,png,gif',
            ], [
              'name' => 'please enter your name!',
              'email.unique' => 'This email address has alredy been used!'
            ]);
            
            // only if validation passes
            dd($request->all());
        }
    

    Here we pass the request input to the validate method of controller with an array of rules for each input, with the key of each element in the array matching the name of the input file. The name input validation fails if the name input value is empty. The email input validation fails if the input isn’t a valid email, or if there is an entry in the user table email column with the same value, or if the length of the string is more than 255 characters. The password entry passes if there is another field with that name (in this case `password` ) with a suffix `_confirmation` (i.e. `password_confirmation`) and if their values match, but fails otherwise.
    The `images.* key` accepts an array of files, with the only permitted file extensions listed, using the `mimes` (which takes a comma separated parameters) validations rule. In validation, arrays are indexed using dots (.) (for example `images[1]` would be written as `images.1` or `files[‘new’]` as `files.new`). The asterisk (*) is used as a wildcard i.e. to match every file in the files array.

    If validation fails, the request is automatically redirected back along with the errors and old values, which are then rendered in the view, just like we did in the previous view snippet.

  • Using the in-request validator
    This is very similar to the previously discussed method. It can be found in the request object injected into the function by Laravel (using dependency injection). Below is how we would use this method:
    public function store(Request $request)
    {
      $request->validate([
          'name' => 'required',
          'email' => 'required|email|unique:users|max:255',
          'age' => 'required|integer|between:1,200',
          'username' => 'required|unique:users|max:255',
          'password' => 'required|string|min:6|confirmed',
          'files.*' => 'mimes:jpg,jpeg,png,gif'
        ], [
          'name' => 'please enter your name!',
          'email.unique' => 'This email address has alredy been used!'
        ]);
        
        //if validation passes
        dd($request->all());
    }
  • Manually create a validator
    In this case, validator objects are manually instantiated (created). This gives us more control over what to do when the error fails. We could choose to redirect the user to a different route or perform several other operations before deciding to redirect the user. We can also decide to just perform the redirection back by calling the `validate` method on the object.  Custom error message can be passed as an optional third parameter.
    public function store(Request $request)
    {
      $validator = Validator::make($request->all(), [
          'name' => 'required',
          'email' => 'required|email|unique:users|max:255',
          'age' => 'required|integer|between:1,200',
          'username' => 'required|unique:users|max:255',
          'password' => 'required|string|min:6|confirmed',
          'images.*' => 'mimes:jpg,jpeg,png,gif'
        ], [
          'name' => 'please enter your name!',
          'email.unique' => 'This email address has alredy been used!'
        ]);
        if ($validator->fails()) {
            // perform other failure related task here
            return back()->withErrors($validator)->withInput();
        }    
        // only if validation passes
        dd($request->all());
    }
  • Using form request
    This is done by creating a class which extends the `Illuminate\Foundation\Http\FormRequest` class and then specifying the rules, as well as how to determine who can make the request. This is a good way to abstract the validation process, especially for forms with a large number of entries. We can also specify the error message for each field. We can generate the class file using the artisan command below:
    php artsian make:request UserFormRequest

     This generates a file in the `app/Http/Requests` directory called `UserFormRequest`, which we would edit to look like this:

    <?php
    
    namespace App\Http\Requests;
    use Illuminate\Foundation\Http\FormRequest;
    
    class UserFormRequest extends FormRequest
    {
      /**
      * Determine if the user is authorized to make this request.
      *
      * @return bool
      */
      public function authorize()
      {
        // here we would check to see if the user meets the requirements
        // for instance we would check if the user is authenticated
        // or is the user create a post he is tried to update.
        // it should return a boolean value.
         return true;
      }
    
      /**
      * Get the validation rules that apply to the request.
      *
      * @return array
      */
      public function rules()
      {
        return [
          'name' => 'required',
          'email' => 'required|email|unique:users|max:255',
          'age' => 'required|integer|between:1,200',
          'username' => 'required|unique:users|max:255',
          'password' => 'required|string|min:6|confirmed',
          'images.*' => 'mimes:jpg,jpeg,png,gif'
        ];
      }
      
      public function messages()
      {
        return [
          'name' => 'please enter your name!',
          'email.unique' => 'This email address has alredy been used!'
        ];
      }
    }

    The `UserFormRequest` class is then used instead of the `Request` class in the controller, as shown below:

    ...
    use App\Http\Request\UserFormRequest;
    ...
    ...
    public function store(UserFormRequest $request)
    {
        // only if validation passes
        dd($request->all());
    }

Creating Custom Validation Rules

Laravel provides several validation rules; however, we sometimes need to validate inputs in a way unique to the current application we are building. For instance, in building a staff management system, we may want to ensure that the staff ID conforms to a particular pattern, for example, three alphabetic characters followed by five numeric characters. In such cases, we would need to create a custom validation rule. Laravel provides ways to do just that. We can either create new rules or directly register them in the `app/Providers/AppServiceProvider.php` boot function.

We can create a rule class using the artisan command below:

php artisan make:rule StaffId

Which will create a file `StaffId.php` in the `app/Rules` directory. We can apply the rule created by passing an instance of the rule as part of a rules array for the input, for example, given the rule definition below:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class StaffId implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return preg_match('/^[A-Za-z]{3}[0-9]{5}$/', $value);
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return ':attribute must have 3 letter at the begining 
                followed by 5 numbers to end it.';
    }
}

Which will ensure that the value of the input starts with three alphabetic characters, followed by five digits, which brings the length to a total of eight characters.

Tip: Press `Ctrl + P` to use Quick Open to open any file by its name, as shown below:

It is then applied as shown below:

...
...
use App/Rules/StaffId
...
...
public function store(Request $request)
{
  $request->validate([
      'name' => 'required',
      'email' => 'required|email|unique:users|max:255',
      'age' => 'required|integer|between:1,200',
      'username' => ['required', 'unique:users', 'max:255', new StaffId],
      'password' => 'required|string|min:6|confirmed',
      'images.*' => 'mimes:jpg,jpeg,png,gif'
    ], [
      'name' => 'please enter your name!',
      'email.unique' => 'This email address has alredy been used!'
    ]);
    
    //if validation passes
    dd($request->all());
}

The other way to create a new rule is to enter it in the `AppServiceProvider.php` file using the `Validator::extend` method. Also, customizing the error message for this method is done by using the `Validator::replacer` method. To achieve the same end result as the previously illustrated custom rule, we proceed as shown below:

//AppServiceProvider.php - register method
...
//this adds the new rule to the list of available rules
Validator::extend('staff_id', function($attribute, $value, $parameters, $validator){
  return preg_match('/^[A-Za-z]{3}[0-9]{5}$/', $value);
});

//tj
Validator::replacer('staff_id', function ($message, $attribute, $rule, $parameters) {
  return "$attribute must have 3 letter at the begining 
                followed by 5 numbers to end it.";
});

This can be applied as part of the pipe `|` (i.e. `rule_one|rule_two:parameter|…|new_rule`) separated string of rules in every method previously discussed, for example:

public function store(Request $request)
{
  $request->validate([
      'name' => 'required',
      'email' => 'required|email|unique:users|max:255',
      'age' => 'required|integer|between:1,200',
      'username' => 'required|unique:users|max:255|staff_id',
      'password' => 'required|string|min:6|confirmed',
      'files.*' => 'mimes:jpg,jpeg,png,gif'
    ], [
      'name' => 'please enter your name!',
      'email.unique' => 'This email address has alredy been used!'
    ]);
    
    //if validation passes
    dd($request->all());
}

Conclusion

Validation is a critical part of web development. Poor validation is a major cause of system breakdown due to invalid input, and it usually results in developers handling multiple exceptions, ultimately leading to complex and less readable code. In Laravel, there are many validation rules (too many for us to cover here, but refer to the Laravel documentation to check them out) that aid in quick development, which is made even more efficient with CodeMix. There are also multiple ways of expanding the rules set, as well as applying them. This helps us write robust applications, as we can work on input without having to worry about exceptions due to invalid user inputs.