Laravel 5 表单请求数据预处理
Laravel 5 Form Request data pre-manipulation
我正在处理一个用户可以更新其出生日期的表单。该表单为用户提供了 day
、month
和 year
的 3 个单独字段。在服务器端,我当然想将这 3 个单独的字段视为一个值,即 yyyy-mm-dd
.
因此,在验证和更新我的数据库之前,我想通过将 year
、month
和 day
与 -
个字符来创建我需要的日期格式(并且可能取消设置原来的 3 个字段)。
用我的控制器手动实现这个不是问题。我可以简单地获取输入,将字段连接在一起,用 -
个字符分隔并取消设置。然后我可以手动验证,然后传递给命令来处理处理。
但是,我更愿意使用 FormRequest
来处理验证并将其注入到我的控制器方法中。因此,我需要一种在执行验证之前实际修改表单请求的方法。
我确实发现了以下类似的问题:
它建议覆盖表单请求上的 all
方法以包含在验证之前处理数据的逻辑。
<?php namespace App\Http\Requests;
class UpdateSettingsRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
public function all()
{
$data = parent::all();
$data['date_of_birth'] = 'test';
return $data;
}
这对于验证来说一切都很好,但是重写 all
方法实际上并没有修改表单请求对象上的数据。所以在执行命令时,表单请求包含原始未修改的数据。除非我使用现在覆盖的 all
方法来提取数据。
我正在寻找一种更具体的方法来修改我的表单请求中的数据,不需要调用特定方法。
干杯
您仍然覆盖 all()
方法 - 但像这样尝试
public function all()
{
$input = $this->all();
$input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
$this->replace($input);
return $this->all();
}
那么您实际上并没有自己调用该方法 - 它会在执行规则时由验证器本身调用。
注意: 这个问题和答案都是在 Laravel 5.1 发布之前发布的,并且都是针对 5.0.对于 5.1 及更高版本,请参阅@BenSampo 的 by @Julia Shestakova or 以获得更现代的解决方案。
经过一番折腾,我得出了以下结论:
app/Http/Requests/Request.php
<?php namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest {
/**
* Override the initialize method called from the constructor to give subclasses
* an opportunity to modify the input before anything happens.
*
* @param array $query
* @param array $request
* @param array $attributes
* @param array $cookies
* @param array $files
* @param array $server
* @param null $content
*/
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
{
parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);
// Grab the input
$data = $this->getInputSource()->all();
// Pass it off to modifyInput function
$data = $this->modifyInput($data);
// Replace modified data back into input.
$this->getInputSource()->replace($data);
}
/**
* Function that can be overridden to manipulate the input data before anything
* happens with it.
*
* @param array $data The original data.
* @return array The new modified data.
*/
public function modifyInput(array $data)
{
return $data;
}
}
然后在扩展 类 时,您可以像这样覆盖 modifyInput
方法:
app/Http/Requests/TestRequest.php
<?php namespace App\Http\Requests;
class TestRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
/**
* Modify the input.
*/
public function modifyInput(array $data)
{
$data['date_of_birth'] = 'something';
// Make sure to return it.
return $data;
}
}
这似乎符合我的需要。我不确定这样做有什么缺点所以我欢迎任何 comments/criticism.
上面的 Shift Exchange 给出的答案也可以正常工作。
我也需要一种快速而肮脏的方法来完成它。我想使用 Shift Exchanges 解决方案,但由于对 $this
的调用创建了一个无限递归循环,所以它不起作用。快速更改为引用父方法将解决此问题:
public function all()
{
$input = parent::all();
$input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
$this->replace($input);
return parent::all();
}
HTH 其他有需要的人。
在 laravel 5.1 你可以做到这一点
<?php namespace App\Http\Requests;
class UpdateSettingsRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
protected function getValidatorInstance()
{
$data = $this->all();
$data['date_of_birth'] = 'test';
$this->getInputSource()->replace($data);
/*modify data before send to validator*/
return parent::getValidatorInstance();
}
我对 Julia Logvina 采取了类似的方法,但我认为这种方法在验证前 add/modify 字段稍微更优雅 (Laravel 5.1)
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class UpdateSettingsRequest extends Request
{
/**
* 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 [];
}
/**
* Extend the default getValidatorInstance method
* so fields can be modified or added before validation
*
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function getValidatorInstance()
{
// Add new data field before it gets sent to the validator
$this->merge(array('date_of_birth' => 'test'));
// OR: Replace ALL data fields before they're sent to the validator
// $this->replace(array('date_of_birth' => 'test'));
// Fire the parent getValidatorInstance method
return parent::getValidatorInstance();
}
}
这将扩展默认值 getValidatorInstance
,因此我们可以在请求到达验证器之前修改请求中的输入值(防止它使用原始未修改的数据)。修改数据后,它会触发原始 getValidatorInstance
然后一切照常进行。
您可以在请求中使用 $this->replace(array())
或 $this->merge(array())
新字段。我在上面的代码片段中包含了一个如何执行这两项操作的示例。
replace()
将用您提供的数组替换所有字段。
merge()
将在您的请求中添加一个新字段。
我认为这是最好的方法:Laravel 5.1 Modify input before form request validation
在 Laravel 5.4+ 中有一个专门的方法来处理这样的事情,所以请使用它:prepareForValidation
从 Laravel 5.4 开始,您可以在 FormRequest 类.
上使用 prepareForValidation
方法
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|max:200',
'body' => 'required',
'tags' => 'required|array|max:10',
'is_published' => 'required|boolean',
'author_name' => 'required',
];
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'title' => fix_typos($this->title),
'body' => filter_malicious_content($this->body),
'tags' => convert_comma_separated_values_to_array($this->tags),
'is_published' => (bool) $this->is_published,
]);
}
}
这里有一篇更详细的文章:
https://sampo.co.uk/blog/manipulating-request-data-before-performing-validation-in-laravel
我正在处理一个用户可以更新其出生日期的表单。该表单为用户提供了 day
、month
和 year
的 3 个单独字段。在服务器端,我当然想将这 3 个单独的字段视为一个值,即 yyyy-mm-dd
.
因此,在验证和更新我的数据库之前,我想通过将 year
、month
和 day
与 -
个字符来创建我需要的日期格式(并且可能取消设置原来的 3 个字段)。
用我的控制器手动实现这个不是问题。我可以简单地获取输入,将字段连接在一起,用 -
个字符分隔并取消设置。然后我可以手动验证,然后传递给命令来处理处理。
但是,我更愿意使用 FormRequest
来处理验证并将其注入到我的控制器方法中。因此,我需要一种在执行验证之前实际修改表单请求的方法。
我确实发现了以下类似的问题:
它建议覆盖表单请求上的 all
方法以包含在验证之前处理数据的逻辑。
<?php namespace App\Http\Requests;
class UpdateSettingsRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
public function all()
{
$data = parent::all();
$data['date_of_birth'] = 'test';
return $data;
}
这对于验证来说一切都很好,但是重写 all
方法实际上并没有修改表单请求对象上的数据。所以在执行命令时,表单请求包含原始未修改的数据。除非我使用现在覆盖的 all
方法来提取数据。
我正在寻找一种更具体的方法来修改我的表单请求中的数据,不需要调用特定方法。
干杯
您仍然覆盖 all()
方法 - 但像这样尝试
public function all()
{
$input = $this->all();
$input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
$this->replace($input);
return $this->all();
}
那么您实际上并没有自己调用该方法 - 它会在执行规则时由验证器本身调用。
注意: 这个问题和答案都是在 Laravel 5.1 发布之前发布的,并且都是针对 5.0.对于 5.1 及更高版本,请参阅@BenSampo 的
经过一番折腾,我得出了以下结论:
app/Http/Requests/Request.php
<?php namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest {
/**
* Override the initialize method called from the constructor to give subclasses
* an opportunity to modify the input before anything happens.
*
* @param array $query
* @param array $request
* @param array $attributes
* @param array $cookies
* @param array $files
* @param array $server
* @param null $content
*/
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
{
parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);
// Grab the input
$data = $this->getInputSource()->all();
// Pass it off to modifyInput function
$data = $this->modifyInput($data);
// Replace modified data back into input.
$this->getInputSource()->replace($data);
}
/**
* Function that can be overridden to manipulate the input data before anything
* happens with it.
*
* @param array $data The original data.
* @return array The new modified data.
*/
public function modifyInput(array $data)
{
return $data;
}
}
然后在扩展 类 时,您可以像这样覆盖 modifyInput
方法:
app/Http/Requests/TestRequest.php
<?php namespace App\Http\Requests;
class TestRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
/**
* Modify the input.
*/
public function modifyInput(array $data)
{
$data['date_of_birth'] = 'something';
// Make sure to return it.
return $data;
}
}
这似乎符合我的需要。我不确定这样做有什么缺点所以我欢迎任何 comments/criticism.
上面的 Shift Exchange 给出的答案也可以正常工作。
我也需要一种快速而肮脏的方法来完成它。我想使用 Shift Exchanges 解决方案,但由于对 $this
的调用创建了一个无限递归循环,所以它不起作用。快速更改为引用父方法将解决此问题:
public function all()
{
$input = parent::all();
$input['date_of_birth'] = $input['year'].'-'.$input['month'].'-'.$input['day'];
$this->replace($input);
return parent::all();
}
HTH 其他有需要的人。
在 laravel 5.1 你可以做到这一点
<?php namespace App\Http\Requests;
class UpdateSettingsRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
protected function getValidatorInstance()
{
$data = $this->all();
$data['date_of_birth'] = 'test';
$this->getInputSource()->replace($data);
/*modify data before send to validator*/
return parent::getValidatorInstance();
}
我对 Julia Logvina 采取了类似的方法,但我认为这种方法在验证前 add/modify 字段稍微更优雅 (Laravel 5.1)
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class UpdateSettingsRequest extends Request
{
/**
* 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 [];
}
/**
* Extend the default getValidatorInstance method
* so fields can be modified or added before validation
*
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function getValidatorInstance()
{
// Add new data field before it gets sent to the validator
$this->merge(array('date_of_birth' => 'test'));
// OR: Replace ALL data fields before they're sent to the validator
// $this->replace(array('date_of_birth' => 'test'));
// Fire the parent getValidatorInstance method
return parent::getValidatorInstance();
}
}
这将扩展默认值 getValidatorInstance
,因此我们可以在请求到达验证器之前修改请求中的输入值(防止它使用原始未修改的数据)。修改数据后,它会触发原始 getValidatorInstance
然后一切照常进行。
您可以在请求中使用 $this->replace(array())
或 $this->merge(array())
新字段。我在上面的代码片段中包含了一个如何执行这两项操作的示例。
replace()
将用您提供的数组替换所有字段。
merge()
将在您的请求中添加一个新字段。
我认为这是最好的方法:Laravel 5.1 Modify input before form request validation
在 Laravel 5.4+ 中有一个专门的方法来处理这样的事情,所以请使用它:prepareForValidation
从 Laravel 5.4 开始,您可以在 FormRequest 类.
上使用prepareForValidation
方法
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|max:200',
'body' => 'required',
'tags' => 'required|array|max:10',
'is_published' => 'required|boolean',
'author_name' => 'required',
];
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'title' => fix_typos($this->title),
'body' => filter_malicious_content($this->body),
'tags' => convert_comma_separated_values_to_array($this->tags),
'is_published' => (bool) $this->is_published,
]);
}
}
这里有一篇更详细的文章: https://sampo.co.uk/blog/manipulating-request-data-before-performing-validation-in-laravel