【问题标题】:Yii2: ActiveForm: combine rules / multiple validation on one fieldYii2:ActiveForm:在一个字段上组合规则/多重验证
【发布时间】:2015-10-12 19:40:12
【问题描述】:

登录表单:

public function rules()
{
    return [
        // username and password are both required
        [['username', 'password'], 'required'],
        // username should be a number and of 8 digits
        [['username'], 'number', 'message'=>'{attribute} must be a number'],
        [['username'], 'string', 'length' => 8],
        // password is validated by validatePassword()
        ['password', 'validatePassword'],
    ];
}

/**
 * Validates the password.
 * This method serves as the inline validation for password.
 *
 * @param string $attribute the attribute currently being validated
 * @param array $params the additional name-value pairs given in the rule
 */
public function validatePassword($attribute, $params)
{
    if (!$this->hasErrors()) {
        $user = $this->getUser();
        if (!$user || !$user->validatePassword($this->password)) {
            $this->addError($attribute, 'Incorrect username or password.');
        }
    }
}

如上所示,我为同一个字段设置了 2 条规则:

[['username'], 'number', 'message'=>'{attribute} must be a number'],
[['username'], 'string', 'length' => 8],

我希望表单针对以下 3 个场景 情况显示不同的错误消息:

  1. 提供的值既不是数字,也不是 8 个字符(数字)。
  2. 提供的值是一个数字,但不是 8 个字符(数字)。
  3. 提供的值不是数字,而是 8 个字符(数字)。

我的问题是 2 倍:

A.有没有办法以任何标准组合这些规则,Yii2 方式。
B. In my previous question 我试图设置一个自定义验证器(解决这个问题的明显方法),但它被简单地忽略了。我可以使它验证的唯一方法是如果我将username 字段添加到场景中。但是,一旦我也添加了password,它又被忽略了。你能想到什么原因吗? 编辑skipOnError = false 在这种行为中没有任何改变。

所以,当您回答时,请确保您最好在yii2/advanced 中进行测试;我几乎没有碰过默认设置,所以应该很容易测试。

编辑:为清楚起见,我只想允许 8 个字符(数字)的数字,因此它们可能有一个前导 0,例如。 0000000100000000 就此而言。这就是为什么它必须是一个数字字符串。

【问题讨论】:

  • 默认情况下,如果值为空,Yii2 会忽略验证器(与 Yii1 不同)。要对空属性强制执行验证,请设置 skipOnEmpty = false (与您的 B. 部分相关 - 忽略自定义验证器)。
  • @lubosdz 抱歉,但这并没有改变任何行为;我在用户名中添加了skipOnEmpty = false,无论该字段是否为空,只有当场景中的唯一字段是username 时才会启动(当然,在这种情况下,validatePassword 验证器没有启动在)...
  • skipOnError 怎么样,也许这就是验证器被跳过的原因?
  • @Beowulfenator 在另一个问题中提出了建议,但不幸的是它没有改变任何事情......我将编辑我的问题以包含它。
  • 据我所知,您无法使用现有的 yii2 验证器解决此问题。但是,我认为您的自定义验证器的问题在于它在前端不起作用。因此,如果任何前端检查失败,您的表单永远不会被提交,因此您的自定义验证器没有机会运行。尝试开启 ajax 验证。

标签: php yii2 yii2-advanced-app


【解决方案1】:

结合规则并针对不同情况显示自定义错误消息的最佳方法是创建自定义验证器。现在,如果您希望它也可以在客户端工作(这是我在上面的问题 B 中详述的问题之一,感谢@Beowulfenator 对此的领导),您必须创建一个实际的自定义从 yii2 原生验证器类扩展而来的验证器类。

这是一个例子:

CustomValidator.php

<?php

namespace app\components\validators;

use Yii;
use yii\validators\Validator;

class CustomValidator extends Validator
{
    public function init() {
        parent::init();
    }

    public function validateAttribute($model, $attribute) {
        $model->addError($attribute, $attribute.' message');
    }

    public function clientValidateAttribute($model, $attribute, $view)
    {
return <<<JS
messages.push('$attribute message');
JS;
    }
}

LoginForm.php

<?php
namespace common\models;

use Yii;
use yii\base\Model;
use app\components\validators\CustomValidator;

/**
 * Login form
 */
class LoginForm extends Model
{
    public $username;
    public $password;
    public $custom;

    private $_user;


    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            // username and password are both required
            [['username', 'password'], 'required'],
            // username should be a number and of 8 digits
            [['username'], 'number', 'message'=>'{attribute} must be a number'],
            [['username'], 'string', 'length' => 8],
            // password is validated by validatePassword()
            ['password', 'validatePassword'],
            ['custom', CustomValidator::className()],
        ];
    }

    // ...

登录.php

<?php

/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model \common\models\LoginForm */

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;

$this->title = 'Login';
?>
<div class="site-login text-center">
    <h1><?php echo Yii::$app->name; ?></h1>

    <?php $form = ActiveForm::begin([
        'id' => 'login-form',
        'fieldConfig' => ['template' => "{label}\n{input}"],
        'enableClientValidation' => true,
        'validateOnSubmit' => true,
    ]); ?>

    <?= $form->errorSummary($model, ['header'=>'']) ?>

    <div class="row">
        <div class="col-lg-4 col-lg-offset-4">
            <div class="col-lg-10 col-lg-offset-1">

                    <div style="margin-top:40px">
                        <?= $form->field($model, 'username') ?>
                    </div>

                    <div>
                        <?= $form->field($model, 'password')->passwordInput() ?>
                    </div>

                    <div>
                        <?= $form->field($model, 'custom') ?>
                    </div>

                    <div class="form-group" style="margin-top:40px">
                        <?= Html::submitButton('Login', ['class' => 'btn btn-default', 'name' => 'login-button']) ?>
                    </div>

            </div>
        </div>
    </div>

    <?php ActiveForm::end(); ?>

</div>

【讨论】:

    【解决方案2】:

    最后你需要这个:

    • 该值是必需的
    • 值必须是 8 个字符的字符串
    • 值必须只包含数字

    所以你应该尝试一下:

    ['username', 'required'],
    ['username', 'string', 'min' => 8, 'max' => 8],
    ['username', 'match', 'pattern' => '/^[0-9]{8}$/', 'message'=>'{attribute} must be a number'],
    

    【讨论】:

    • 这只会显示一条错误消息...我的目标是为每个场景设置单独的消息,如我的问题中所示...
    • 这里有 3 条错误消息,但与您所要求的不完全一致(并非真正需要)。
    • 好的,需要忽略,我不需要为此提供不同的消息...但是如果我添加一个例如 3 个字符的字符串,我只会收到该值的消息应该是一个数字,没有什么,它也应该是 8 个字符......如果设置自定义验证器确实有效(并且击败我为什么它没有 - 请参阅我的原始问题中的问题 B ) ,我可以通过针对不同情况使用if 语句来解决这个问题...
    • 我不会在没有测试的情况下这么说,但我只是为你再做了一次,就像我说的:我在用户名字段中输入了 3 个字母,我得到的唯一消息是 ...must contains only digits , 什么都不是,它应该是一个数字。
    • 我可能不是很清楚:我希望错误消息能够适应这种情况并给出“组合”消息,即如果不满足多个条件,然后显示与仅缺少一个条件时的不同消息...
    【解决方案3】:

    Yii2 忽略您的验证规则可能是因为您不仅复制了属性,还复制了类型。 通过数字验证,我认为您应该使用 min/max 选项来验证数字长度。

    对于这种情况:

    'min'=>10000000,'max'=>99999999
    

    【讨论】:

    • 抱歉,这将不允许像00000001 这样的数字。正如我的问题所示,它必须是一个数字并且是 8 个字符(数字)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多