Laravel comes with request validations out of the box and this makes it a whole lot easier to validate user inputs when receiving form submissions. In this short post, I will be explaining the form request class, its default methods, and how to utilize this form request to match more than one HTTP method.
Just to point out, Laravel also has a validation factory (Illuminate\Validation\Factory) class, which in my opinion, is more often used by developers than the form request class.
The validation factory class seems to be the default validation method Laravel ships out with the controller and this validation factory can be accessed in the controller without any user setup via:
$this->validate($request,$rules,$messages,$customAttributes).
The $messages and $customAttributes arrays are optional and the function can be called without them, like this:
$this->validate($request, $rules).
This method works pretty fine but when the validation logic grows, it is often advised to move it to its own class, hence the Form Request Class.
The form request class can be created using Laravel’s artisan command:
php artisan make:request RequestClassName
This command will create a Requests folder in the app\Http directory of your Laravel application and create a FormRequest Class, using the class name you passed when creating the FormRequest Class, in our case requestClassName.
To briefly explain the content of the FormRequest class, the class comes with two methods: authorize and rules.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CreateNewRequest extends FormRequest
{
_/\*\*
\* Determine if the user is authorized to make this request.
\*
\*_ **_@return_** _bool
\*/_ public function authorize()
{
return false;
}
_/\*\*
\* Get the validation rules that apply to the request.
\*
\*_ **_@return_** _array
\*/_ public function rules()
{
return [
//
];
}
}
The authorize method checks if a user is authorized to make a request, so an example use case here can be a blogging system where only a post creator can edit his/her post. Assuming the blog post has a column user_id that tracks which user made the post, the authorize function can look like this:
_/\*\*
\* Determine if the user is authorized to make this request.
\*
\*_ **_@return_** _bool
\*/_ public function authorize()
{
return $blogPost->user\_id === auth()->id();
}
So this returns true and then moves to process the edit request only when the blog post edit request is made by the blog post owner, else it will return false and throw an exception back to the user, moving to the next method.
The rules method contains the validation logic of any form that utilizes the FormRequest class.
The FormRequest class can be injected into any method in which you want the FormRequest validation logic to hold true, and this cleans up your controller.
Having explained the concepts surrounding the readily available validate method and the user-created form request class, let me move to the main problem that this post aims to shed light on.
Ideally, creating and updating a model’s record might require differing validations for the model’s column, to make an example, let us continue using the blog analogy.
To create a blog, we might decide that an image is required, the blog post name is required, same as the blog post content, but on updating the post, the blog post image would necessarily not be required, it becomes an optional validation.
_/\*\*
\* Get the validation rules that apply to the request.
\*
\*_ **_@return_** _array
\*/_ public function rules()
{
//blog post creation rules
return [
'name' => 'string | required',
'content' => 'string | required',
'image' => 'image | required'
];
}
_/\*\*
\* Get the validation rules that apply to the request.
\*
\*_ **_@return_** _array
\*/_ public function rules()
{
//blog post update rules
return [
'name' => 'string | required',
'content' => 'string | required',
'image' => 'image'
];
}
The above two rules are different and if I want to stick to the Form Request class way of validation I might have to make more form requests classes should I have differing validation logic for POST, PUT, PATCH and DELETE. To solve this with only one form class, it is possible to edit the form request to make it more versatile such that it serves different rules for different HTTP verbs. See code sample below:
protected $rules = [
];
_/\*\*
\* Get the validation rules that apply to the request.
\*
\*_ **_@return_** _array
\*/_ public function rules()
{
$method = $this->method();
if (null !== $this->get('\_method', null)) {
$method = $this->get('\_method');
}
$this->offsetUnset('\_method');
switch ($method) {
case 'DELETE':
case 'GET':
$this->rules = [];
break;
case 'POST':
break;
// in case of edit
case 'PUT':
case 'PATCH':
break;
default:
break;
}
return $this->rules;
}
Explanation:
$method = $this->method();
The code snippet above retrieves the HTTP method from the request object and stores it to a variable, $method, next.
if (null !== $this->get('\_method', null)) {
$method = $this->get('\_method');
}
Knowing that Laravel has a way of masking or changing the original request method using the @method() directive, the code tests to see if a method is specified in the request object, if it is, then it updates the method variable with it.
$this->offsetUnset('\_method');
This removes the “_method” attribute from the request object, and as such we have realized the type of HTTP request that is been sent to our application and can then serve differing rules for each request type.
switch ($method) {
case 'DELETE':
$this->rules = [//rules here for delete request];
break;
case 'GET':
$this->rules = [//rules here for get request];
break;
case 'POST':
$this->rules = [//rules here for post request];
break;
case 'PUT':
$this->rules = [//rules here for put request];
break;
case 'PATCH':
$this->rules = [//rules here for patch request];
break;
default:
break;
}
return $this->rules;
The above switch statement updates the rules array with appropriate validation logic for each request type and helps you have them all in one request class.
Thank you for reading until the end 🙂
Top comments (0)