php - Form request validation in Laravel: required depending on the method (POST, PUT or DELETE)
I am using form requests in Laravel for validation. I have noticed a pattern that emerges all the time and I couldn't find a solution for it on SE (or at least googling it didn't help me).
Let's say we are creating an API and we are using Laravel's apiResource to create the usual CRUD methods: store
, update
and delete
Obviously, when we are storing a new record, the field id
is not required, but the rest of the fields might be required (and in most cases are). But when we are updating a record, we face the opposite situation. id
is required while other fields are no longer required.
Is it possible to handle this situation with one form request in Laravel? Can we use Laravel's required_if
in an intelligent way to avoid code duplication?
Edit: it doesn't have to be necessarily a Laravel solution. A solution that uses PHP would be fine too (as long as it is clean and follows SOLID principles).
Answer
Solution:
I faced this problem lots of times and I understand your frustration...
From my point of view and professional experience, the best solution was all the time to have specific FormRequest
s for each case:
- One for
store
with its own rules - Other for
update
with similar rules but not same asstore
- And last one for
delete
(for sure way less rules than the others and no duplication)
I know you said "no code duplication", but as it is right now, that is not possible (but you should not have code duplication as I stated before).
You said "as long as it is clean and follows SOLID principles", remember SOLID, S = Single Responsability, so if you want to solve this issue with a single FormRequest
you are already breaking S
. I cannot image a FormRequest
with 10 or 15 inputs and those depends on if it is store
, update
, or delete
. That is going to not be clean and for sure will not follow SOLID principles.
Answer
Solution:
What about checking the method and then returning a set of rules based on that method? For instance, I have an InvoiceFormRequest with the following rules. So I'm able to use one form request for two different methods.
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
if ($this->isMethod('post')) {
return [
'template' => 'required',
'due_by_date' => 'required',
'description' => 'required',
'charge_items' => 'required',
];
}
if ($this->isMethod('put')) {
return [
'due_by_date' => 'required',
'description' => 'required',
'charge_items' => 'required',
];
}
}
Answer
Solution:
Here are two possible solutions that I came up with
- Use the controller method for returning the proper validation rules:
public function rules()
{
$method = $this->route()->getActionMethod();
switch($method){
case 'store':
return [
\\ validation rules
]
...
}
}
- Use
$this->getMethod()
instead of$this->route()->getActionMethod()
and validate by HTTP methods instead.
You could also store your validation rules in an array and manipulate it to reduce code duplication.
This resolves the issue of code duplication to a good extent, I think.
Source