Extend FormRequest to Allow More Functionality in Laravel (v5.3+)

- the main reason i made this is to have the same freedom the Custom Validation offer and include what it doesnt “getting the request payload with the validation class”

Update
in the latest release v5.3.19 a new method was add for the after hook “about time if you ask me” which does exactly the same as below but with only one exception,
with the below you can have more than one method for different arrays validation “single responsibility”, so unless you need the array validation you are better off with the original form request.

  • controllers/PostController.php
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreValidation;

class PostController extends Controller
{
  public function store(StoreValidation $request, $id)
  {
    // if validation failed, it will automaticlly redirect back
    // https://laravel.com/docs/5.3/validation#form-request-validation

    // $request->all()
  }
}
  • Requests\StoreValidation
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
use Illuminate\Contracts\Validation\Validator as ValidatorContract;

class StoreValidation extends FormRequest
{
  protected $error_container = [];


  // ...


  // 1- we call the native validate method
  // and attach any extra checking method before 
  // the validation fail/pass check.
  public function validate()
  {
    $instance = $this->getValidatorInstance();

    $this->validateExtra($instance);

    if ( ! $this->passesAuthorization()) {
      $this->failedAuthorization();
    } elseif ( ! $instance->passes()) {
      $this->failedValidation($instance);
    }
  }


  // 2- then we replace the original rule array with the new array
  // from the extra validation, so we can use the same syntax 
  // to get the errors whether its single or multi
  protected function failedValidation(ValidatorContract $contract)
  {
    throw new ValidationException(
      $contract,
      $this->response(
        array_replace_recursive(
          $this->formatErrors($contract),
          $this->error_container
        )
      )
    );
  }


  // 3- the extra validation logic
  // you can change the method name to anything you want
  // you can even make more than one for each input extra validation
  // then add it to the 'validate()' method above.
  protected function validateExtra($instance)
  {
    $request = $this->instance();

    $instance->after(function ($instance) use ($request) {

      // add any extra validation you want to do in here
      // something like https://ctf0.wordpress.com/2016/10/01/multifile-upload-validation-in-laravel-v5-3/

    });
  }

}

# v5.3.19 Changes

// ...

class StoreValidation extends FormRequest
{
  protected $error_container = [];


  // ...


  // 1- replace the original rule array with the new array
  // from the withValidator(), so we can use the same syntax 
  // to get the errors whether its single or multi
  protected function failedValidation(ValidatorContract $contract)
  {
    throw new ValidationException(
      $contract,
      $this->response(
        array_replace_recursive(
          $this->formatErrors($contract),
          $this->error_container
        )
      )
    );
  }


  // the extra validation logic
  protected function withValidator($validator)
  {
    $request = $this->instance();

    $validator->after(function ($validator) use ($request) {

      // add any extra validation you want to do in here
      // something like https://ctf0.wordpress.com/2016/10/01/multifile-upload-validation-in-laravel-v5-3/

    });
  }

}

# v5.5 Changes

failedValidation has changed to

protected function failedValidation(Validator $validator)
{
    throw (new ValidationException($validator))
             ->errorBag($this->errorBag)
             ->redirectTo($this->getRedirectUrl());
}

and this basicly fucked the whole thing,

so to fix it

  • dont include the failedValidation method anymore
  • use withValidator method as b4 but change the below

from

// 8- only add items to the messageBag if we 
// actually have any validation errors
if (!empty($this->error_container)) {
  $validator->errors()->add($input_name, $this->error_container[$input_name]);
}

to

if (!empty($this->error_container)) {
  $res = array_replace_recursive(
    $validator->getMessageBag()->toArray(),
    $this->error_container
  );

  $validator->errors()->merge($res);
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s