Laravel provides several different approaches to validate your application’s incoming data. It is most common to use the validate method available on all incoming HTTP requests. However, in this topic, we will use Form Requests in different ways.
First of all, I don’t think using a small validation in the controller will harm your code readability but on the other hand, if you are willing to handle more complex validation scenarios, you may wish to create a “Form Request“.
Form requests are custom request classes that encapsulate their own validation and authorization logic.
Let’s create our own form request class, all you need is to run this command:
php artisan make:request StoreUserRequest
A new StoreUserRequest
class will be generated under "\App\Http\Requests" namespace containing a rules() & authorize() methods.
Let’s add some quick validation under rules() method
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|min:3|max:50',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
//... more validation
];
}
After that, we will inject our new Form request in the controller store() method
/**
* Store a new user.
*
* @param \App\Http\Requests\StoreUserRequest $request
* @return Illuminate\Http\Response
*/
public function store(StoreUserRequest $request)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validatedData = $request->validated();
}
So far so good, if the validation is valid we will get our validated data from Form request otherwise a Validation Exception will be thrown.
Now, what about the update, clearly we need to use another form request UpdateUserRequest
with its rules and inject it in the controller update() method.
So this is the first and the simple approach used so far.
The second approach is using one class to handle the store and update rules, so, we will run the command again and create new Form Request by naming it UserRequest
.
We create store() and update() functions and call them in rules() function by using isMethod() we're checking the HTTP request method if is it a POST or other than that, you may be specific and check if it is a PUT/PATCH.
As you may notice we can also share validations used in both methods and concatenate it with the proper validation function.
public function rules()
{
return ['name' => 'required|min:3|max:50']
+
($this->isMethod('POST') ? $this->store() : $this->update());
}
protected function store()
{
return [
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
//… more validation
];
}
protected function update()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user()->id,
'logo' => 'nullable|image|max:1024',
'bio' => 'nullable|max:300',
'github_url' => 'nullable|url'
//… more validation
];
}
After that, we will inject UserRequest
in both store() and update() methods.
Now, we have one class that serve different validation depends on HTTP request.
/**
* Store a new user.
*/
public function store(UserRequest $request)
{
$validated = $request->validated();
}
/**
* Update user.
*/
public function update(UserRequest $request)
{
$validated = $request->validated();
}
I will name the third approach “ResourceFormRequest” and it will be a little bit different from the others.
First I’ll create a BaseFormRequest
that contains all resourceful methods, feel free to use your own naming just be careful when you name your methods to not end up overriding Request class methods.
After that, create UserRequest
and extends BaseFormRequest
, and override existing methods with your rules, finally inject the UserRequest inside your controller methods.
<?php | |
namespace App\Http\Requests; | |
use Illuminate\Foundation\Http\FormRequest; | |
class BaseFormRequest 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 match($this->method()){ | |
'POST' => $this->store(), | |
'PUT', 'PATCH' => $this->update(), | |
'DELETE' => $this->destroy(), | |
default => $this->view() | |
} | |
} | |
/** | |
* Get the validation rules that apply to the get request. | |
* | |
* @return array | |
*/ | |
public function view() | |
{ | |
return [ | |
// | |
]; | |
} | |
/** | |
* Get the validation rules that apply to the post request. | |
* | |
* @return array | |
*/ | |
public function store() | |
{ | |
return [ | |
// | |
]; | |
} | |
/** | |
* Get the validation rules that apply to the put/patch request. | |
* | |
* @return array | |
*/ | |
public function update() | |
{ | |
return [ | |
// | |
]; | |
} | |
/** | |
* Get the validation rules that apply to the delete request. | |
* | |
* @return array | |
*/ | |
public function destroy() | |
{ | |
return [ | |
// | |
]; | |
} | |
} |
<?php | |
class UserController extends Controller | |
{ | |
public function store(UserRequest $request) | |
{ | |
//.... | |
} | |
public function update(UserRequest $request) | |
{ | |
//.... | |
} | |
// just for demonstration to use the form request with destroy | |
public function destroy(UserRequest $request) | |
{ | |
//.... | |
} | |
} |
<?php | |
namespace App\Http\Requests; | |
class UserRequest extends BaseFormRequest | |
{ | |
/** | |
* Get the validation rules that apply to the post request. | |
* | |
* @return array | |
*/ | |
public function store() | |
{ | |
return [ | |
'name' => 'required', | |
'email' => 'required|email|unique:users', | |
'password' => 'required|confirmed|min:8', | |
//… more validation | |
]; | |
} | |
/** | |
* Get the validation rules that apply to the put/patch request. | |
* | |
* @return array | |
*/ | |
public function update() | |
{ | |
return [ | |
'name' => 'required', | |
'email' => 'required|email|unique:users,email,' . $this->user()->id, | |
'logo' => 'nullable|image|max:1024', | |
'bio' => 'nullable|max:300', | |
'github_url' => 'nullable|url' | |
//… more validation | |
]; | |
} | |
/** | |
* Get the validation rules that apply to the delete request. | |
* | |
* @return array | |
*/ | |
public function destroy() | |
{ | |
return [ | |
'id' => 'required|integer|exists:users,id' | |
]; | |
} | |
} |
Our Resource Form Request can handle now a Controller resource and you end up with one file that manage all validations of specific Model instead of separate files which personally I don't like it.
I think there's a lot of approaches that we can follow and feel free to share your best approach or other approaches you have.
Finally, if you are reading this line I think the topic was interesting for you.
Thank you
Top comments (13)
Not bad, but i guess it's a little bit over-engineered
I prefer to create another form request class for the update method.
+1 to this. I've created two classes both extending the FormRequest class for this. Alternatively you could create a super class in between for inheritance. While the proposed method in this article isn't bad, I prefer this method personally
I extend the store method request in the update request.
It just depend on how you want to structure your project.
This!...
Thank you Othmane, this is really good writeup for me to understand, maybe just some little typos in 1st & 3rd pictures, I think
It's my pleasure that was helpful for you.. and thank you for pointing the typos :)
(y)
what about authorize()? for the store(), update(), destroy(), view() ?
Why this does not work inside form request?
$this->input('notification_type_id', null) // Always returns null
ok, thats good. i want to call
$controller->store()
manually. how can i create request forstore
method ???Thanks to share this idea. It's different approach to learn.
Such a great article, but I was wondering how to pass data like route parameters into the form request, I tried many techniques as per Laravel docs but unluckily did not work for the form request.