Yii2 - 验证嵌套对象

时间:2018-06-06 13:41:00

标签: yii yii2

这是一个关于我一直在考虑的话题的问题。

在Yii2中,建议通常为您的请求创建表单模型。将规则添加到这些模型以验证输入。一个例子是Yii2指南中的EntryForm

<?php

namespace app\models;

use Yii;
use yii\base\Model;

class EntryForm extends Model
{
    public $name;
    public $email;

    public function rules()
    {
        return [
            [['name', 'email'], 'required'],
            ['email', 'email'],
        ];
    }
}

我的问题是,当我们有嵌套对象时。一个示例是使用多个分支创建客户的表单。如果客户分支是两个单独的模型,但两者都以一种形式提交,那么验证来自此类嵌套表单的输入的最佳选项是什么。请记住,输入是嵌套的。示例:

{
  "name": "customer",
  "vat_no": "12345678",
  "time_zone": 277,
  "category": 1,
  "email": "customer@mycustomer.com",
  "stores":[
    {
        "name": "store1",
        "phone": 1234567
    },
    {
        "name": "store2",
        "phone": 2345678
    }
]
}

1 个答案:

答案 0 :(得分:1)

对于简单的情况,您可以在表单模型中使用一个模型和自定义验证器:

public function rules() {
    return [
        // ...
        ['stores', 'validateStores'],
    ];
}

public function validateStores() {
    $phoneValidator = new StringValidator(); // use real validators
    $nameValidator = new StringValidator(); // use real validators
    foreach ($this->stores as $store) {
        if (!$phoneValidator->validate($store['phone'], $error)) {
            $this->addError('stores', $error);
            return; // stop on first error
        }
        if (!$nameValidator->validate($store['name'], $error)) {
            $this->addError('stores', $error);
            return; // end on first error
        }
    }
}
可以提取

validateStores()以分隔验证者类,然后您也可以使用EachValidator代替foreach

对于更复杂的嵌套模型,您可能应该为商店创建单独的StoreForm模型(因此您将拥有嵌套的表单模型),并在子项上调用validate()

/**
 * @var StoreForm[]
 */
public $stores;

public function rules() {
    return [
        // ...
        ['stores', 'validateStores'],
    ];
}

public function validateStores() {
    foreach ($this->stores as $store) {
        if (!$store->validate()) {
            $this->addError('stores', 'Stores config is incorrect.');
            return;
        }
    }
}