首页 > 解决方案 > Laravel / 嵌套验证

问题描述

我正在为一个基本的页面构建器系统构建一个组件驱动的 API,并且在验证方面遇到了一个绊脚石。

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

如果我们有一个组件(例如在 Vue 中)/components/ProfileCard.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',
            ]
        ],
    ],
];

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

为组件创建自定义验证规则,我可以说“ProfileCard 组件无效”但我无法合并/嵌套验证规则:

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"
        }
    }
}

我已经根据自己的进度更新了问题,您可以在规则MessageBagmessages方法中返回 a ,但是,这会产生一个小问题,响应如下:


    "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" 数组中的一个对象中。

标签: phplaravelvalidationlaravel-validation

解决方案


您的方法似乎使一个简单的问题复杂化了。我永远不会在验证规则中进行验证。而是做依赖于的规则,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 条件。我认为这可以使您朝着正确的方向前进,该解决方案将解决您的消息问题并且变得更简单。


推荐阅读