Php Laravel 5表单请求数据预处理

Php Laravel 5表单请求数据预处理,php,validation,laravel,laravel-5,Php,Validation,Laravel,Laravel 5,我正在处理一个表单,用户可以更新他们的出生日期。该表单为用户提供了3个单独的字段,分别是天、月和年。当然,在服务器端,我希望将这3个单独的字段视为一个值,即yyyy-mm-dd 因此,在验证和更新数据库之前,我想更改表单请求,通过将年、月和日与-字符串联,创建一个出生日期字段,以创建我需要的日期格式(并可能取消设置原始3个字段) 用我的控制器手动实现这一点不是问题。我可以简单地获取输入,将由-字符分隔的字段连接在一起,然后取消设置它们。然后,我可以在传递命令处理处理处理之前手动验证 然而,我更愿

我正在处理一个表单,用户可以更新他们的出生日期。该表单为用户提供了3个单独的字段,分别是
。当然,在服务器端,我希望将这3个单独的字段视为一个值,即
yyyy-mm-dd

因此,在验证和更新数据库之前,我想更改表单请求,通过将
-
字符串联,创建一个
出生日期
字段,以创建我需要的日期格式(并可能取消设置原始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()
方法,但请像这样尝试

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及以上版本,请参见@Julia Shestakova或@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;
    }

}
<?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;
    }

}
这似乎适合我的需要。我不确定这样做有什么缺点,所以我欢迎任何评论/批评


上面的轮班交换给出的答案也很好。

我也需要一种快速而肮脏的方法来完成这项工作。我想使用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采取了类似的方法,但我认为这种方法是在验证之前添加/修改字段的一种稍微优雅的方法(Laravel 5.1)


我认为这是最好的方法:


在Laravel5.4+中,有一个专门的方法来处理类似的内容,所以请使用它:
prepareForValidation
由于Laravel5.4,您可以对FormRequest类使用
prepareForValidation
方法


谢谢您的回复。难道没有一种“一次性”的清洁方法吗?它感觉非常脏,每次请求数据时都必须对数据进行操作。通过查看代码,似乎每次请求数据时都会调用
all()
函数(即从
input
,除了
等)。这是一种非常干净的方法,因为它在FormRequest对象内部被整洁地处理。这意味着控制器和应用程序的其他方面不知道发生了什么。每次调用
all()。专注于编写好的、干净的、可维护的代码会有更好的结果:)是的,在这种情况下,这绝对是微不足道的。但从理论上讲,如果这里有很多事情要做,那可能是另一回事。我更喜欢尽可能地编写最佳代码。我会把这种方法比作获得我们在每次迭代中循环通过的数组的长度。这是可行的,优化可能是微不足道的,但一切都在增加。我试图寻找其他方法来覆盖,并得出结论,在
Symfony\Component\HttpFoundation\Request
中找到的
initialize
方法可能是一种可行的方法。有什么想法吗?它是从构造函数调用的。问题是,
all()
方法已经在每次迭代中执行数组循环了。如果您查看原始的
all()
方法,就是这样:
returnarray\u replace\u recursive($this->input(),$this->files->all())
。因此,进行此修改不会对性能产生任何影响。你正在尝试优化一个不需要优化的过程…+1这实际上是一个非常好的方法,我喜欢。尽管我会通过
$source=$this->getInputSource()缓存sourceInput当然,在5.4中,这无疑是问题的最佳解决方案。但是,对于5.4之前的版本(这个问题是在2015年3月提出的,当时的版本是5.0),下面给出的其他答案更合适,例如@Julia Logvina针对5.1给出的答案,这是一个长期支持(LTS)版本JEP,但是,像我这样的人如果在5.x上查找一般主题,仍然会发现这一点,因此我认为提及5.4+;)的解决方案是有效的。)谢谢@Thomas Venturini!使用5.5确实有帮助+1尽管在我提出这个问题时(2015年3月),Laravel 5.1尚未发布(于2015年6月发布),但我会接受这个答案。有关Laravel 5.0,请参阅其他一些答案。谢谢你,朱莉娅!是否有方法更改FormRequest重定向到的位置,或者只有在出现错误时才重定向回?是否有方法更改FormRequest重定向到的位置,或者只有在出现错误时才重定向回?为什么直到版本6.x才记录此方法-/
<?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();

    }

}