Actually this article is about form validation using a single
middleware
. Well,
Laravel
peovided us many ways for validating our user inputs and my favorite way is using
Form Request
class which is just awesome. Chexk it
here if you are not already aware of that. Using a form request class we can validate the incoming request before the coresponding controller method's code gets executed and to implement this we need to make/create form request class for each controller as per method basis and we declare only one method in that form request class which is the
rules()
to declare validation rules for validating the incoming request.
Well, nothing bad in it but I just want to keep my validation rules inside my model and also want to use only a single class for validating all of my models. So, to achieve this, I've replaced the form request class using a single middleware and here is how I did it.
At first let's create the middleware:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\JsonResponse;
class InputValidator
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next, $fullyQualifiedNameOfModel)
{
$model = app($fullyQualifiedNameOfModel);
$validator = app('validator')->make($request->input(), $model->rules($request));
if ($validator->fails()) {
return $this->response($request, $validator->errors());
}
return $next($request);
}
protected function response($request, $errors)
{
if($request->ajax()) {
return new JsonResponse($errors, 422);
}
return redirect()->back()->withErrors($errors)->withInput();
}
}
Now, we need to add this
middleware
in the
$routeMiddleware
array in the
App\Http\Kernel.php
class, for example, the
$routeMiddleware
is given below:
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
'acl' => 'App\Http\Middleware\CheckPermission',
'validator' => 'App\Http\Middleware\InputValidator', // <-- This One
];
Now, to use this
middleware
as form validator for our every model we may use this
middleware
in the route declaration as given below:
$router->get('create', [
'uses' => 'TagController@create',
'as' => 'admin.tag.create',
'permission' => 'manage_tag',
'middleware' => 'validator:App\Eloquent\Tag' // Pass the model name (including namespace)
]);
Here, the
Validator
is the middleware (alias of original middleware (App\Http\Middleware\InputValidator) class) and the parameter passed into the middleware is
App\Eloquent\Tag
to tell the middleware which model to use to get the validation rules so let's create the model with
rules()
method, for example, my models are saved in
app/Eloquent
directory and
namespace
is
App\Eloquent
so fully qualified name of the model class was passed as the middleware parameter so we can obtain an instance of that model easily.Let's check out the model now:
'required|unique:tags,tag_title,'.$request->route()->parameter('id'),
'tag_slug' => 'required|unique:tags,tag_slug,'.$request->route()->parameter('id'),
];
}
}
That's it. Now, I can validate the request inputs (Submitted Form Inputs) using the middleware and this way I can keep my validation rules inside the model it self and most importantly I can now use only this single middleware to validate all of my models instead of using an individual
FormRequest
class for each model. This way still my validation service is out of my controller which runs before the controller method gets called and everything goes very well. That's it.