验证或删除 laravel 中的额外字段


Validate or remove for extra fields in laravel

是否可以

使用其他字段的规则验证请求,或者从请求中删除该字段?

简单的例子,我有带有规则的 FormRequest 对象:

public function rules() {
        return [
            'id' => 'required|integer',
            'company_name' => 'required|max:255',
        ];
    }

当我收到带有任何其他字段的 post 请求时,我想在控制器中获取错误/异常,或者我只想获取 id 和 company_name 字段,而没有任何其他字段。它存在于 laravel 中的任何功能,或者我必须以我的方式制作它?

要在 Laravel 中的请求中删除密钥,请使用:

$request->request->remove('key')

您使用 laravel 的帖子请求不仅仅是您的表单输入,因此您需要检查请求以查看里面的内容。

要仅获取所需的字段,您可以使用:

$request->only(['fieldname1', 'fieldname2', 'fieldname3']);

$request->except(['fieldnameYouDontWant1', 'fieldnameYouDontWant2', 'fieldnameYouDontWant3']);

以排除您不想要的那些。

从 Laravel 5.5 开始,您可以在控制器中执行此操作:

public function store(StoreCompanyRequest $request)
{
    Company::create($request->validated());
}

validated(( 函数仅返回已验证的字段,并删除其他所有字段。

从 Laravel 5.5 开始,您可以直接调用validate方法Request

例如
class YourController extends Controller
{
    public function store(Request $request) {
      $cleanData = $request->validate([
        'id' => 'required|integer',
        'company_name' => 'required|max:255',
      ]);
      // Now you may safely pass $cleanData right to your model
      // because it ONLY contains fields that in your rules e.g
      $yourModel->create($cleanData);
  }
}

不幸的是,这里的大多数答案都错过了原始问题的重点。也就是说,您希望在 FormRequest 类中指定需要验证的字段,然后在控制器中执行以下操作:

Something::create($request->validated());

但是,您可能希望验证特定字段,但不将其传递给控制器中的 create 方法。 执行$request->only()$request->except()的问题在于,您必须重复 FormRequest 类中的字段,或者在模型的 $guarded 属性中重复这些字段。

不幸的是,我发现做你想做的唯一方法如下:

Something::create(collect($request->validated())->forget('field_you_dont_want')->toArray());

编辑2020年10月

感谢Laravel论坛上的人们,在Laravel7中,请求类是可宏的。 因此,更好的答案是编辑app/Providers/AppServiceProvider.php,在boot()方法中,您可以添加:

// Extend the validated() method
Request::macro('validatedExcept', function($except = []) {
    return Arr::except($this->validated(), $except);
});

您需要添加

use Illuminate'Support'Arr;

app/Providers/AppServiceProvider.php的顶端。

然后,您可以使用:

$request->validatedExcept(['field_to_ignore', 'another_field_to_ignore']);

编辑 2022 年 2 月

Laravel现在有safe()方法,可以让你做到这一点:

$request->safe()->except(['field_to_ignore'])

或者正如GWidgery在他的回答中指出的那样,您可以使用exclude规则:

public function rules() {
    return [
        'id' => 'required|integer',
        'company_name' => 'required|max:255',
        'field_to_ignore' => 'required|exclude',
    ];
}

您可以使用 except 请求方法,它将为您提供除给定字段之外的字段

$request = $request->except('your_field');

如果要从请求中删除多个字段,可以传递字段数组

$request = $request->except(['field_1','field_2',...])

参考:拉拉维尔请求

当您开始进入嵌套数组元素验证时,事情会变得更加棘手,尤其是在涉及通配符的情况下。 将其放入自定义Request类中,并将其注入控制器方法。 应涵盖所有情况。

public function authorize()
{
    //Dot notation makes it possible to parse nested values without recursion
    $original = array_dot($this->all());
    $filtered = [];
    $rules = collect($this->rules());
    $keys = $rules->keys();
    $rules->each(function ($rules, $key) use ($original, $keys, &$filtered) {
        //Allow for array or pipe-delimited rule-sets
        if (is_string($rules)) {
            $rules = explode('|', $rules);
        }
        //In case a rule requires an element to be an array, look for nested rules
        $nestedRules = $keys->filter(function ($otherKey) use ($key) {
            return (strpos($otherKey, "$key.") === 0);
        });
        //If the input must be an array, default missing nested rules to a wildcard
        if (in_array('array', $rules) && $nestedRules->isEmpty()) {
            $key .= ".*";
        }
        foreach ($original as $dotIndex => $element) {
            //fnmatch respects wildcard asterisks
            if (fnmatch($key, $dotIndex)) {
                //array_set respects dot-notation, building out a normal array
                array_set($filtered, $dotIndex, $element);
            }
        }
    });
    //Replace all input values with the filtered set
    $this->replace($filtered);
    //If field changes were attempted, but non were permitted, send back a 403
    return (empty($original) || !empty($this->all()));
}

我有一个新的解决方案,在你的表单请求类中创建一个新函数:

public function onlyInRules()
{
    return $this->only(array_keys($this->rules()));
}

然后在控制器中,调用 $request->onlyInRules() 而不是$request->all()

这是我猜的最好的方法

$this->offsetUnset('field_1');

在表单请求验证中,您可以像这样使用

protected function prepareForValidation()
{
    $this->offsetUnset('field_1');
}

我通过在FormRequest类中覆盖方法validate((做到了这一点。

abstract class MyFormRequest extends FormRequest {
    public function validate() {
        foreach ($this->request->all() as $key => $value) {
            if (!array_key_exists($key, $this->rules())) {
                throw new ValidationException("Field " . $key . " is not allowed.");
            }
        }
        parent::validate();
    }
}

我认为这不是最好的方法,但它是有效的。我应该升级它以立即显示有关所有错误字段的信息:)

Laravel有一个"排除"验证规则:验证:排除

表格请求

public function rules()
{
    return [
        'second_hand_smoke' => 'required|boolean',
        'flu_vaccination' => 'required|boolean',
        'provided' => 'required|boolean|exclude',
    ];
}

控制器

$request->validated();

返回

array:2[
    "second_hand_smoke" => 1
    "flu_vaccination" => 1
]

您可以通过控制器执行此操作。您只能将两个或某些字段发送到数据库。使用$request->only()而不是$request->all()并传递要保存在数据库中的数据数组。 controllerstore()方法应如下所示:

public function store(Request $request)
{
    ModelName::create($request->only(['id','company_name']));
    return redirect('RouteName');
}
$request->validated(); 

将仅返回经过验证的数据。

在控制器方法中:

public function myController(ValidationRequest $request) {
    $data = $request->validated();
}

由于没有人从"测试"的角度回答这个问题,您可以做的是重置请求查询。

request()->query = new 'Symfony'Component'HttpFoundation'InputBag();

还有一种方法,仅适用于Laravel 8,具有更多的功能和冗长:

$request->safe()->all()

另外,它可以很容易地用于搜索和替换$request->all()