Laravel / 嵌套验证

Laravel / nested validation

我正在为基本的页面生成器系统构建一个组件驱动的 API,但在验证方面遇到了障碍。

首先,我想解释一下用例。

如果我们在 /components/ProfileCard.vue

中有一个组件(例如在 Vue 中)
<script>
export default {
    props: {
        name: String,
        age: Number,
        avatar: String
    }
}
</script>

我正在后端创建一个组件components.php 配置:


<?php

return [
    'profile' => [
        'component' => 'ProfileCard',
        'rules' => [
            'name' => [
                'required',
            ],
            'age' => [
                'required',
                'number',
            ],
            'avatar' => [
                'required',
            ]
        ],
    ],
];

每次提交个人资料卡组件时都会检查和验证。

为组件创建自定义验证规则,我可以说 "the ProfileCard component is not valid" 但我无法合并/嵌套验证规则:

Component.php

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Validator;

class Component implements Rule 
{
    protected $validator = null;

    public function passes($attribute, $value)
    {
        $components = config('components');
        $component = $value['component'];

        if (isset($components[$component])) {
            return false;
        }

        $c = $components[$component];
        $this->validator = Validator::make($value['data'], $c['rules'], $c['messages'] ?? '');
        return $this->validator->passes();
    }

    public function message() 
    {
        if (is_null($this->validator)) {
            return 'The component does not exist';
        }
        return $this->validator->errors();
    }
}

有没有人有过做这样的事情的经验,或者有人能指出我正确的解决方案方向吗?

理想情况下,我正在寻找一种在使用 Laravel 的 FormRequest 验证时适用的解决方案,如下所示:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Unique;
use App\Rules\Component;

class CreateUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'email' => [
                'required',
                'email',
                new Unique('users', 'email'),
            ],
            'profile' => [
                'required',
                new Component(),
            ]
        ];
    }
}

数据会像这样进来:

{
    "email": "test@example.com",
    "profile": {
        "component": "ProfileCard",
        "data": {
           "name": "Test",
           "age": 49,
           "avatar": "https://example.com/avatar.png"
        }
    }
}

我已经用我自己取得的进展更新了问题,你可以在规则的 messages 方法中 return a MessageBag,但是,这会产生一个小问题,响应返回如下:


    "message": "The given data was invalid.",
    "errors": {
        "profile": [
            {
                "name": [
                    "The name field is required."
                ],
                "age": [
                    "The age field is required."
                ],
                "avatar": [
                    "The avatar field is required."
                ],
            },
            ":message"
        ]
    }

显然这是一个改进,但它仍然不可用,我们没有“:message”并且验证错误嵌套在 "profile" 数组中的一个对象中。

你的方法似乎把一个简单的问题复杂化了。我永远不会在验证规则中进行验证。相反,执行依赖于 component 的规则,并在表单请求中相应地调整它。您可以像这样轻松地执行嵌套规则。

[
    'profile.name' => 'string',
]

执行表单请求中的其余逻辑。该策略是根据您已经尝试过的请求输入和您的配置文件制定规则。

public function rules()
{
    // i do not know how you determine this key
    $componentKey = 'profile';

    $rules = [
        ...,
        $componentKey => [
            'required',
        ]
    ];

    $inputComponent= $this->input('profile')['component'];
    $components = config('components');

    // based on your data this seems wrong, but basically fetch the correct config entry
    $component = $components[$inputComponent];

    foreach ($component['rules'] as $key => $value) {
            $rules[$componentKey  . '.' . $key] => $value;
    }

    return $rules;
}

你的代码中有些部分我无法弄清楚你的数据是什么意思,我不知道你是如何获得组件密钥配置文件的,你的代码基于配置和组件字段似乎是错误的,应该而是使用 where 条件进行循环。我认为这可以让您朝着正确的方向前进,此解决方案将解决您的消息问题并且更加简单。