Laravel 5.1 在表单请求验证之前修改输入

7
有没有一种方法可以在验证之前修改表单请求类中的输入字段?
我想按以下方式修改一些输入日期字段,但似乎不起作用。
当我将$this->start_dt输入字段设置为2016-02-06 12:00:00,并将$this->end_dt设置为2016-02-06 13:00:00时,仍然会出现验证错误“end_dt必须在start_dt之后”。这意味着在rules()函数内更新$this->start_dt和$this->end_dt时,输入请求值没有被更改。
public function rules()
{
    if ($this->start_dt){
        $this->start_dt = Carbon::createFromFormat('d M Y H:i:s', $this->start_dt . ' ' . $this->start_hr . ':'. $this->start_min . ':00');
    }

    if ($this->end_dt){
        $this->end_dt = Carbon::createFromFormat('d M Y H:i:s', $this->end_dt . ' ' . $this->end_hr . ':'. $this->end_min . ':00');
    }

    return [
        'start_dt' => 'required|date|after:yesterday',
        'end_dt' => 'required|date|after:start_dt|before:' . Carbon::parse($this->start_dt)->addDays(30)            
    ];
}

注意:start_dtend_dt是日期选择器字段,而start_hrstart_min是下拉菜单字段。因此,我需要将所有字段组合起来创建一个日期时间,以便进行比较。


另请参阅:https://dev59.com/2F4b5IYBdhLWcg3wpzHv - Jonathon
5个回答

19

从 Laravel 5.4 开始,您可以覆盖 ValidatesWhenResolvedTraitprepareForValidation 方法以修改任何输入。Laravel 5.1 应该也有类似的功能。

在您的请求中的示例:

/**
 * 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);
}

1
这个有文档记录吗?否则它可能会像其他解决方案一样,在小版本升级时悄悄出现问题。 - Enkay

6

FormRequest类有一个validationData()方法,用于返回需要验证的数据。因此,我在我的表单请求中重写了该方法:

<?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)
            ]
        );
    }
    ...
}

它工作得很好,我正在使用Laravel 5.4 :)


嗨,FabulousCo,你能给我展示一下你的FormRequest以及你使用它的控制器方法吗? - Yassine Khachlek
嗨,Yassine,Thomas做的例子很好!无论如何还是谢谢 :) - FabienChn
如果你在这行代码 $this->replace($data) 中加入 $this->replace($data) 就能让这个程序正常运行:public function validationData() { $data = array_merge( $this->all(), [ 'number' => preg_replace("/[^0-9]/", "", $this->number) ] ); **$this->replace($data);** return $data; } - Jaime

2

请尝试以下步骤:

1- 中间件

首先,您应该在 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);
    }
}

使用这个中间件,您可以定义要在调用验证之前操作的字段,并调用特定函数来操作它们。
注意:我在自己的助手函数中定义了toGregorian和toDateTime。您可以使用自己的函数处理它。
2-内核
然后像下面这样修改Http / Kernel.php:
protected $middlewareGroups = [
    'web' => [
        ...

        \App\Http\Middleware\EnglishStrings::class,
    ],

    'api' => [
        ...
    ],
];

1
您可以尝试以下操作:

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)            
    ];
}

0
我采用了一种替代方法,因为我想在我的控制器中使用$model->fill($validated);。因此,我需要确保复选框已被包含为false,否则它们将从数组中排除。
因此,我创建了一个trait,在app\Traits\ConvertBoolean.php中,如下所示:
<?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);
        }
    }
}

这个 trait 查找请求中是否存在一个数组 $this->boolean_attributes。如果找到了,它会遍历每一个属性,并将该属性添加到请求数据中,其值设置为原始请求数据中该属性的存在性。

它忽略 HTML 表单复选框值的值。在大多数情况下,这不会是一个问题,但如果需要,您可以更改 trait 中的逻辑以查找特定值。

现在我有了这个 trait,我可以在任何请求中使用它,如下所示:

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

如果你想在请求中使用$this->prepareForValidation(),这仍然是可能的。

按照以下方式更改MyRequest:

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();
    }

    // ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接