Is there a way to modify input fields inside a form request class before the validation takes place?
I want to modify some input date fields as follows but it doesn
I took an alternative approach to this, as I want to be able to use $model->fill($validated);
in my controllers. As such, I need to ensure that checkboxes have been included as false
where they would otherwise be excluded from the array.
So, I created a trait, in app\Traits\ConvertBoolean.php, as follows:
<?php
namespace App\Traits;
trait ConvertBoolean
{
// protected $boolean_attributes = [];
/**
* Override the FormRequest prepareForValidation() method to
* add boolean attributes specified to the request data, setting
* their value to the presence of the data in the original request.
*
* @return void
*/
protected function prepareForValidation() {
if (isset($this->boolean_attributes) && is_array($this->boolean_attributes)) {
$attrs_to_add = [];
foreach ($this->boolean_attributes as $attribute) {
$attrs_to_add[$attribute] = $this->has($attribute);
}
$this->merge($attrs_to_add);
}
}
}
This trait looks for the existence of an array $this->boolean_attributes
in the request. If it finds it, it goes through each one and adds the attribute to the request data with the value set to the presence of the attribute in the original request data.
It disregards the value of the HTML form's checkbox value. In most cases, this won't be a problem, but you could change the logic in the trait to look for specific values, if required.
Now that I have this trait, I can then use it in any request, like so:
use App\Traits\ConvertBoolean;
class MyUpdateRequest extends FormRequest
{
use ConvertBoolean;
protected $boolean_attributes = ['my_checkbox'];
// ... other class code
public function rules()
{
// Note that the data is added to the request data,
// so you still need a validation rule for it, in
// order to receive it in the validated data.
return [
'my_checkbox' => 'boolean',
// other rules
];
}
}
If you want to use $this->prepareForValidation()
in your request, this is still possible.
Change MyRequest, as follows:
use App\Traits\ConvertBoolean;
class MyUpdateRequest extends FormRequest
{
use ConvertBoolean {
prepareForValidation as traitPrepareForValidation;
}
protected function prepareForValidation() {
// the stuff you want to do in MyRequest
// ...
$this->traitPrepareForValidation();
}
// ...
}
The FormRequest has a method validationData() that return the data to validate, so i'm overriding it in my form request:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyClassRequest extends FormRequest
{
...
/**
* Get data to be validated from the request.
*
* @return array
*/
public function validationData() {
return array_merge(
$this->all(),
[
'number' => preg_replace("/[^0-9]/", "", $this->number)
]
);
}
...
}
It work fine i'm using Laravel 5.4 :)
Try these steps:
first of all you should create a middleware in app/Http/Middleware
:
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TransformsRequest;
class DateTimeMiddleware extends TransformsRequest
{
protected $fields = [
'birth_date' => 'toGregorian',
'created_at' => 'toDateTime',
];
protected function transform($key, $value)
{
if (!array_key_exists($key, $this->fields)) {
return $value;
}
$function = $this->fields[$key];
return call_user_func($function, $value);
}
}
with this middleware you can define fields that you want to manipulate them before calling validation and call a specific function to manipulate them.
note: i defined toGregorian
and toDateTime
in my own helper functions. you can handle it with your own functions
then modify Http/Kernel.php
like bellow:
protected $middlewareGroups = [
'web' => [
...
\App\Http\Middleware\EnglishStrings::class,
],
'api' => [
...
],
];
As of laravel 5.4 you can override the prepareForValidation
method of the ValidatesWhenResolvedTrait
to modify any input. Something similar should be possible for laravel 5.1.
Example in your Request
/**
* Modify the input values
*
* @return void
*/
protected function prepareForValidation() {
// get the input
$input = array_map('trim', $this->all());
// check newsletter
if (!isset($input['newsletter'])) {
$input['newsletter'] = false;
}
// replace old input with new input
$this->replace($input);
}
You can do something like the following:
public function rules(Request $request)
{
if ($request->has('start_dt')){
$request->replace('start_dt', Carbon::createFromFormat('d M Y H:i:s', $request->start_dt . ' ' . $request->start_hr . ':'. $request->start_min . ':00'));
}
if ($request->has('end_dt')){
$request->replace('end_dt' ,Carbon::createFromFormat('d M Y H:i:s', $request->end_dt . ' ' . $request->end_hr . ':'. $request->end_min . ':00'));
}
return [
'start_dt' => 'required|date|after:yesterday',
'end_dt' => 'required|date|after:start_dt|before:' . Carbon::parse($request->start_dt)->addDays(30)
];
}