问题
LoginForm:
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.');
}
}
}
I have set up 2 rules for the same field as you can see above:
[['username'], 'number', 'message'=>'{attribute} must be a number'],
[['username'], 'string', 'length' => 8],
I would like the form to display different error messages for the following 3 scenarios situations:
- The provided value is neither a number, nor 8 characters (digits).
- The provided value is a number, but is not of 8 characters (digits).
- The provided value is not a number, but is of 8 characters (digits).
My question is 2 fold:
A. Is there a way to combine these rules in any standard, Yii2
way.
B. In my previous question I have tried to set up a custom validator (the obvious way to solve this), but it was very simply ignored. The only way I could make it validate was if I added the username
field to a scenario. However, once I added password
too, it was again ignored. Any reason's for this that you can think of? EDIT: skipOnError = false
changed nothing at all in this behaviour.
So please, when you answer, make sure you test it preferably in yii2/advanced
; I barely touched the default set up, so it should be easy to test.
EDIT: for clarity, I would like to only allow numbers that are of 8 characters (digits), so they can potentially have a leading 0
, eg. 00000001
, or 00000000
for that matter. This is why it has to be a numeric string.
回答1:
The best way to combine rules and display custom error messages for different situations is to create a custom validator. Now if you want that to work on client-side too (it was one of my problems detailed in question B above, thanks to @Beowulfenator for the lead on this), you have to create an actual custom validator class extended from the yii2 native validator class.
Here is an example:
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()],
];
}
// ...
login.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:
Finally you need this :
- the value is required
- the value must be a string of 8 chars
- the value must contains only digits
So you should simply try :
['username', 'required'],
['username', 'string', 'min' => 8, 'max' => 8],
['username', 'match', 'pattern' => '/^[0-9]{8}$/', 'message'=>'{attribute} must be a number'],
回答3:
Yii2 ignores your validation rules may because you duplicated not only attribue but also types. With number validation, i think you should use min/max option to validate number length.
For this case:
'min'=>10000000,'max'=>99999999
来源:https://stackoverflow.com/questions/33088935/yii2-activeform-combine-rules-multiple-validation-on-one-field