«

yii2 场景验证的使用

时间:2024-2-28 16:08     作者:韩俊     分类: PHP


场景的意义

模型可能在多个场景下使用,例如 User 模块可能会在收集用户登录输入, 也可能会在用户注册时使用。在不同的场景下, 模型可能会使用不同的业务规则和逻辑, 例如 email 属性在注册时强制要求有,但在登陆时不需要。(目前我的理解是场景主要用来做参数验证的)

使用示例(本示例以用户模型在注册,登录两个场景下的使用方法分析):

// 场景作为属性来设置
$model = new User;
$model->scenario = 'login';

// 场景通过构造初始化配置来设置
$model = new User(['scenario' => 'login']);

默认情况下,模型支持的场景由模型中申明的 验证规则 来决定, 但你可以通过覆盖yii\base\Model::scenarios()方法来自定义行为, 如下所示:

namespace app\models;

use yii\db\ActiveRecord;

class User extends ActiveRecord
{

    public function scenarios()
    {
        return [
            'login' => ['username', 'password'],
            'register' => ['username', 'email', 'password'],
        ];
    }
}

Info:在上述和下述的例子中,模型类都是继承 yii\db\ActiveRecord, 因为多场景的使用通常发生在 Active Record 类中。

scenarios() 方法返回一个数组,数组的键为场景名,值为对应的 active attributes 活动属性。 活动属性可被块赋值并遵循验证规则 在上述例子中,username 和 password 在login场景中启用,在 register 场景中, 除了 username and password 外 email 也被启用。

scenarios() 方法默认实现会返回所有 yii\base\Model::rules() 方法申明的验证规则中的场景, 当覆盖 scenarios() 时,如果你想在默认场景外使用新场景, 可以编写类似如下代码:

namespace app\models;

use yii\db\ActiveRecord;

class User extends ActiveRecord
{

    public function scenarios()
    {
        $scenarios = parent::scenarios();
        'login' = ['username', 'password'];
        'register' = ['username', 'email', 'password'];
        return $scenarios;
    }
}

场景特性主要在验证 和 属性块赋值 中使用。 你也可以用于其他目的, 例如可基于不同的场景定义不同的 属性标签。

验证规则

当模型接收到终端用户输入的数据, 数据应当满足某种规则(称为 验证规则, 也称为 业务规则)。 例如假定 ContactForm 模型,你可能想确保所有属性不为空且 email 属性包含一个有效的邮箱地址, 如果某个属性的值不满足对应的业务规则, 相应的错误信息应显示,以帮助用户修正错误。

可调用 yii\base\Model::validate() 来验证接收到的数据, 该方法使用 yii\base\Model::rules() 申明的验证规则来验证每个相关属性, 如果没有找到错误,会返回 true, 否则它会将错误保存在 yii\base\Model::errors 属性中并返回 false,例如:

$model = new \app\models\ContactForm;

// 用户输入数据赋值到模型属性
$model->attributes = \Yii::$app->request->post('ContactForm');

if ($model->validate()) {
    // 所有输入数据都有效 all inputs are valid
} else {
    // 验证失败:$errors 是一个包含错误信息的数组
    $errors = $model->errors;
}

通过覆盖 yii\base\Model::rules() 方法指定模型 属性应该满足的规则来申明模型相关验证规则。 下述例子显示 ContactForm 模型申明的验证规则:

public function rules()
{
    return [
        // name, email, subject 和 body 属性必须有值
        [['name', 'email', 'subject', 'body'], 'required'],

        // email 属性必须是一个有效的电子邮箱地址
        ['email', 'email'],
    ];
}

一条规则可用来验证一个或多个属性,一个属性可对应一条或多条规则。 更多关于如何申明验证规则的详情请参考 验证输入 一节.

有时你想一条规则只在某个 场景 下应用,为此你可以指定规则的 on 属性, 如下所示:

public function rules()
{
    return [
        // 在"register" 场景下 username, email 和 password 必须有值
        [['username', 'email', 'password'], 'required', 'on' => 'register'],

        // 在 "login" 场景下 username 和 password 必须有值
        [['username', 'password'], 'required', 'on' => 'login'],
    ];
}

如果没有指定 on 属性,规则会在所有场景下应用, 在当前 yii\base\Model::scenario 下应用的规则称之为 active rule 活动规则。

一个属性只会属于 scenarios() 中定义的活动属性且在 rules() 申明对应一条或多条活动规则的情况下被验证。

下面是一个本人在具体的业务中写的一个 model 类,可供参考:

<?php

namespace common\models\qifaCn\invoice;

use common\helpers\Utils;
use Yii;
use yii\helpers\HtmlPurifier;

/**
 * This is the model class for table "qifacn.qifacn_member_invoice_titles".
 *
 * 订单的电子发票的模型文件类
 * @property int $invoice_title_id 发票抬头ID
 * @property int $member_id 会员ID
 * @property int $title_type 抬头类型;0 - 个人/非企业性单位;1 - 公司
 * @property string $title 抬头名称
 * @property string $taxpayer_id 纳税人识别号
 * @property string $despoist_bank 开户银行(选填)
 * @property string $bank_account 银行账号(选填)
 * @property string $registered_address 注册地址(选填)
 * @property string $registered_phone 注册电话(选填)
 * @property string $created_at 创建时间
 * @property string $updated_at 最后更新时间
 */
class QifacnMemberInvoiceTitles extends QifaCnActiveRecord {

    public $order_no;
    public $agree_type;
    public $invoice_type;

    const TITLE_TYPE_PERSONAL = 0;
    const TITLE_TYPE_COMPANY = 1;

    /**
     * {@inheritdoc}
     */
    public static function tableName(): string {
        return 'qifacn.qifacn_member_invoice_titles';
    }

    /**
     * {@inheritdoc}
     */
    public function rules(): array {
        return [
            [['member_id', 'title_type'], 'integer'],
            [['title_type', 'title'], 'required'],
            [['taxpayer_id'], 'required', 'when' => function ($model) {
                return $model->title_type == self::TITLE_TYPE_COMPANY;
            }],
            [['created_at', 'updated_at'], 'safe'],
            [['title', 'despoist_bank', 'bank_account', 'registered_phone'], 'string', 'max' => 50],
            [['taxpayer_id'], 'string', 'min' => 7, 'max' => 20, 'tooShort' => '{attribute}至少需要 {min} 个字', 'tooLong' => '{attribute}最多只能包含 {max} 个字'],
            [['registered_phone'], 'string', 'max' => 20, 'tooLong' => '{attribute}最多只能包含 {max} 个字'],
            ['taxpayer_id', 'match', 'pattern' => '/^[a-zA-Z0-9]+$/', 'message' => '{attribute}仅允许输入数字或英文字符'],
            ['registered_phone', 'match', 'pattern' => '/^[0-9\-]+$/', 'message' => '{attribute}仅允许输入数字或中划线'],
            [['order_no', 'invoice_type'], 'required', 'on' => ['apply']],
            [['order_no'], 'each', 'rule' => ['integer'], 'on' => 'apply'],//on 的值可以是字符串也可以是数组
            [['title_type', 'invoice_type'], 'in', 'range' => [self::TITLE_TYPE_PERSONAL, self::TITLE_TYPE_COMPANY]],
            [['agree_type'], 'in', 'range' => [0, 1, 2], 'on' => 'electronic-invoice-list'],
            [['registered_address'], 'string', 'max' => 200],
            [['title', 'despoist_bank', 'bank_account', 'registered_phone', 'registered_address', 'taxpayer_id'], 'filter', 'filter' => function ($value) {
                return trim(htmlentities(strip_tags($value), ENT_QUOTES, 'UTF-8'));
            }],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels(): array {
        return [
            'invoice_title_id' => '订单电子发票抬头ID',
            'member_id' => Yii::t('app', 'member_id'),
            'title_type' => '抬头类型',
            'title' => '抬头名称',
            'taxpayer_id' => '发票税号',
            'despoist_bank' => '开户银行',
            'bank_account' => '银行账号',
            'registered_address' => '注册地址',
            'registered_phone' => '注册电话',
            'created_at' => Yii::t('app', 'created_at'),
            'updated_at' => Yii::t('app', 'updated_at'),
        ];
    }

    /**
     * @return \string[][]
     */
    public function scenarios(): array {
        return array_merge(parent::scenarios(), [
            'apply' => ['order_no', 'invoice_type', 'title_type', 'title', 'taxpayer_id', 'despoist_bank', 'bank_account', 'registered_address', 'registered_phone', 'member_id'],//申请电子发票场景
            'header-save' => ['title_type', 'title', 'taxpayer_id', 'despoist_bank', 'bank_account', 'registered_address', 'registered_phone', 'member_id'],//保存电子发票抬头场景
            'default' => ['title_type', 'title', 'taxpayer_id', 'despoist_bank', 'bank_account', 'registered_address', 'registered_phone'],
            'electronic-invoice-list' => ['agree_type']//获取电子发票列表场景
        ]);
    }

    /**
     * @param int $member_id
     * @param int $titleType
     * @return array|\yii\db\ActiveRecord[]
     */
    public static function getListByMemberId($member_id, $titleType = -1) {
        $query = self::find()->where(['member_id' => $member_id]);
        $titleType >= 0 && $query->andWhere(['title_type' => $titleType]);
        return $query->asArray()->all();
    }
}

标签: php php教程

热门推荐