【问题标题】:Laravel: how to invalidate an update if an unknown field is passedLaravel:如果传递了未知字段,如何使更新无效
【发布时间】:2019-10-22 01:52:39
【问题描述】:

我有一个自定义验证器:

    $validator = Validator::make($request->all(), [
        'name' => 'sometimes|unique:stock.containers|max:255',
    ]);

如果我这样做,我想抛出一个错误:

 PUT:localhost/my/model?description=foobar

因为在这种情况下我只想接受name。然后我会确保我的$validator->valid() 只包含接受的字段。

这是我的控制器:

class ContainerController extends Controller
{
    public function update($id, Request $request) {
        $container = Container::find($id);

        $rules = ['name' => 'max:255'];

        $validator = Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);  //i'm not getting any
        }

        $container->update($validator->valid());
    }
}

通过上述请求,我到达了$container->update。我想将该领域限制在我的规则中提到的领域。

【问题讨论】:

  • 你试过什么?我最近注意到你提出了很多 Laravel 问题,这很好,但你需要展示你为解决问题所做的尝试,以及你遇到的错误。
  • 例如,这可能就像循环 $request 中的值一样简单,与已定义的已接受变量数组进行比较,如果遇到类似 description(或更好声明,不是 name)。
  • 所以 很少 个问题是 很多 Laravel 问题 根据你:) 我修改了我的问题以包含我尝试过的内容。
  • @TimLewis,是的,我可以很容易地解决这个问题是一些低级循环,但框架的目的是使用已经制作的功能。将模型更新限制为预定义字段列表看起来任何人都会使用,所以我期待一个明显的开箱即用功能
  • 我在过去 2 天内收到了 4 次您的邮件。与大多数用户相比,这 很多问题 :) 但我的意思不是消极的。无论如何,继续前进。是的,Laravel 是一个框架,但是串联使用自定义代码并没有错。是否有一个开箱即用的功能可以做到这一点?我不知道;可能是?那是你的问题吗?也可能,但不是我解释它的方式。

标签: php laravel validation


【解决方案1】:

您可以使用控制器的内置validate 方法,而不是创建一个新的Validator 实例。

public function update($id, Request $request) {
    $valid = $this->validate($request, [
        'name' => 'max:255',
    ]);

    dd($valid);
}

所以即使有人提交了其他不包含在规则中的参数,也不会被包含在内。

在我们的例子中,如果您执行上述 curl 请求,$valid 将返回一个空数组。

然后你可以检查数组是否为空:

if (empty($valid)) {
    // Do what you want
}

旁注

我注意到您使用的是Container::find($id);,但您也可以在路由文件中使用内置模型绑定:

Route::put('your-path/{container}', 'ContainerController@update');

而不是

Route::put('your-path/{id}', 'ContainerController@update');

然后在你的控制器中允许这样做:

public function update(Container $container, Request $request)
{
    // $container would be the Container instance already
}

更新

如果你还想创建一个新的 Validator 实例,你可以这样做:

$validator = \Validator::make($request->all(), $rules);


if ($validator->fails()) {
    // ...
}

if (! $valid = $validator->validated()) {
    // Nothing has been validated
}

基本上您应该使用$validator->validated() 而不是$validator->valid() 来仅从您的规则中检索字段。

【讨论】:

  • 我可以在这个内置验证器上使用after 吗?
  • @nowox 你想用after做什么?
  • 感谢您向我展示内置模型绑定,但它是否适用于 resource 路由?
【解决方案2】:

您可以做一种请求类型,过滤掉您不想要的参数,这样您就可以将它传递给您的控制器,例如:private function myfunction(MyCustomRequest $request),所以当它到达您的验证器时,无效参数已被删除。

在您的MyCustomRequest 中,您可以有一个有效参数列表,如下所示:

 $validParameters = ["name"]; // add as many as you need

所以您现在想检查请求中的内容,您可以使用$request->all() 查看。您可以遍历您的有效参数,并且只传回与您的自定义列表匹配的请求值。

 $requestData = $request->all();

 $goodRequestData = [];

 foreach ($validParameters as $validParameter) {
      if (array_key_exists($validParameter, $requestData) {
           $goodRequestData[] = $requestData[$validParameter];
      }
 }

 return $goodRequestData;

您可以在此处阅读有关 Laravel 文档中自定义请求的更多信息:https://laravel.com/docs/5.8/validation#creating-form-requests

【讨论】:

  • 是的,我不想考虑表单请求,因为我觉得功能分散到许多文件中。要更新我的数据库,我需要:1. 模型,2. 视图,3. 控制器,4. 一些规则,5. 一些请求。由于我的验证规则和请求都非常简单且特定于我的每个路由资源,因此我更喜欢将 API 控制器、规则和请求合并在一起。
  • @nowox 有时我们喜欢的东西并不是最好的。单一责任原则的存在是有原因的。扩展FormRequest 是将所有与请求相关的内容(如验证、清理/类型转换等)封装到单独的类中的好方法。然后您的控制器操作可以在其参数中引用这些表单请求,并且框架会将所有这些例程委托给它们。这样你的控制器就不必担心传入的数据是否有效——这不再是他们的责任。扩展和利用FormRequest 正是您所需要的。
【解决方案3】:

您可以简单地使用->only() 方法:

class ContainerController extends Controller
{
    public function update($id, Request $request) {
        $container = Container::find($id);

        $rules = ['name' => 'max:255'];

        $validator = Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);  //i'm not getting any
        }

        $container->update($request->only(['name']));
    }
}

来自文档:

唯一的方法返回您请求的所有键/值对;但是,它不会返回请求中不存在的键/值对。

【讨论】:

  • 在这种情况下,如果我尝试使用?mispelled_field=42 更新我的模型,我将不会出错,而且我会花很长时间来理解我的错误。我认为如果我尝试更新不允许的字段,我应该会收到验证错误。这是错的吗?
  • 没错,但似乎没有必要,因为您可以使用only 方法阻止这些字段被更新。
  • 我同意你的观点,但如果你想更健壮,最好不要忽略不支持的东西
  • 所以我认为您可以使用 foreach 或其他方式遍历您的 $request 键,并在找到一个或多个不允许的字段时向用户返回一些消息。
猜你喜欢
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 2016-03-05
相关资源
最近更新 更多