Модель:
Код: Выделить всё
public const SCENARIO_STEP_1 = 1;
public const SCENARIO_STEP_2 = 2;
public const SCENARIO_STEP_3 = 3;
public function scenarios(): array
{
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_STEP_1] = ['email'];
$scenarios[self::SCENARIO_STEP_2] = ['username', 'password'];
$scenarios[self::SCENARIO_STEP_3] = ['firstname', 'lastname', 'organization'];
return $scenarios;
}
public function rules(): array
{
return [
['step', 'number'],
['username', 'trim'],
['username', 'required'],
[
'username',
'unique',
'targetClass' => Users::class,
'message' => 'This username has already been taken.',
],
['username', 'string', 'min' => 2, 'max' => 255],
['email', 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'string', 'max' => 255],
[
'email',
'unique',
'targetClass' => '\common\entity\Users',
'message' => 'This email address has already been taken.',
],
['password', 'required'],
['password', 'validatePassword'],
[['firstname', 'lastname'], 'required'],
];
}
Код: Выделить всё
$model = new SignupForm();
$result = [
'status' => 'success',
'cur_step' => 0,
'next_step' => 1,
'final_step' => false,
];
$session = Yii::$app->session;
$session_signup_form = $session->get(self::SIGNUP_FORM);
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
switch ($model->step) {
case SignupForm::SCENARIO_STEP_1:
$model->setScenario(SignupForm::SCENARIO_STEP_1);
break;
case SignupForm::SCENARIO_STEP_2:
$model->setScenario(SignupForm::SCENARIO_STEP_2);
break;
case SignupForm::SCENARIO_STEP_3:
$model->setScenario(SignupForm::SCENARIO_STEP_3);
break;
default:
$model->setScenario(SignupForm::SCENARIO_STEP_1);
}
if (Yii::$app->request->get('validate')) {
return ActiveForm::validate($model);
}
if ($model->validate()) {
$session_model = new SignupForm();
if ((int)$model->step === SignupForm::SCENARIO_STEP_1) {
$session->set(self::SIGNUP_FORM, $model->getAttributes());
$result['cur_step'] = SignupForm::SCENARIO_STEP_1;
$result['next_step'] = SignupForm::SCENARIO_STEP_2;
}
if ((int)$model->step === SignupForm::SCENARIO_STEP_2) {
$session_model->setAttributes($session_signup_form, false);
$session_model->step = (int)$model->step;
$session_model->username = $model->username;
$session_model->password = $model->password;
$model->setAttributes($session_signup_form, false);
$session->set(self::SIGNUP_FORM, $session_model->getAttributes());
$result['cur_step'] = SignupForm::SCENARIO_STEP_2;
$result['next_step'] = SignupForm::SCENARIO_STEP_3;
}
if ((int)$model->step === SignupForm::SCENARIO_STEP_3) {
$session_model->setAttributes($session_signup_form);
$session_model->step = (int)$model->step;
$session_model->firstname = $model->firstname;
$session_model->lastname = $model->lastname;
$session_model->organization = $model->organization;
$model->setAttributes($session_model->getAttributes(), false);
$session->set(self::SIGNUP_FORM, $session_model->getAttributes());
$result['cur_step'] = SignupForm::SCENARIO_STEP_3;
$result['final_step'] = true;
if ($model->signup()) {
$session->remove(self::SIGNUP_FORM);
Yii::$app->session->setFlash(
'success',
'Thank you for registration. Please check your inbox for verification email.'
);
}
}
return $result;
}
}
Код: Выделить всё
<?php
$form = ActiveForm::begin([
'id' => 'form-signup',
'enableAjaxValidation' => true,
'enableClientValidation' => false,
'validateOnSubmit' => true,
'validateOnChange' => false,
'validateOnBlur' => false,
'validationUrl' => Url::to(['/signup-steps', 'validate' => '1']),
'action' => ['/signup-steps']
]); ?>
<ul id="form-signup-steps" class=" uk-switcher uk-margin">
<li>
<div class="uk-width-1-1 uk-margin">
<?= $form->field($model, 'email', [
'inputOptions' => [
'placeholder' => 'Enter email address',
'type' => 'email',
'autocomplete' => 'email',
]
])->label(false) ?>
</div>
<div class="uk-width-1-1 uk-text-center">
<a id="btn-nextstep1" class="uk-button uk-button-text uk-button-large">Next</a>
</div>
</li>
<li>
<div class="uk-width-1-1 uk-margin">
<?= $form->field($model, 'username', [
'inputOptions' => [
'placeholder' => 'Enter username',
'type' => 'text',
'autocomplete' => 'username',
]
])->label(false) ?>
</div>
<div class="uk-width-1-1 uk-margin">
<?= $form->field($model, 'password', [
'inputOptions' => [
'placeholder' => 'Enter password',
'type' => 'password',
'autocomplete' => 'new-password',
'uk-tooltip' => Yii::t('app', 'At least 8 characters of letters, numbers and special characters'),
]
])->label(false) ?>
</div>
<div class="uk-width-1-1 uk-text-center">
<a id="btn-nextstep2" class="uk-button uk-button-text uk-button-large">Next</a>
</div>
</li>
<li>
<div class="uk-width-1-1 uk-margin">
<?= $form->field($model, 'firstname', [
'inputOptions' => [
'placeholder' => 'Enter firstname',
'type' => 'text'
]
])->label(false) ?>
</div>
<div class="uk-width-1-1 uk-margin">
<?= $form->field($model, 'lastname', [
'inputOptions' => [
'placeholder' => 'Enter lastname',
'type' => 'text'
]
])->label(false) ?>
</div>
<div class="uk-width-1-1 uk-margin">
<?= $form->field($model, 'organization', [
'inputOptions' => [
'placeholder' => 'Enter organization (optional)',
'type' => 'text'
]
])->label(false) ?>
</div>
<div class="uk-width-1-1 uk-text-center">
<a id="btn-nextstep3" class="uk-button uk-button-primary uk-button-large"><?= Yii::t('app', 'Signup') ?></a>
</div>
<?= $form->field($model, 'step', ['inputOptions' => [
'value' => SignupForm::SCENARIO_STEP_1,
]])->label(false)->hiddenInput() ?>
<div hidden class="uk-width-1-1 uk-text-center">
<button class="uk-button uk-button-primary uk-button-large">Sign up</button>
</div>
<div class="uk-width-1-1 uk-margin uk-text-center">
<p class="uk-text-small uk-margin-remove">By signing up you agree to our <a class="uk-link-border" href="#">terms</a> of service.</p>
</div>
</li>
</ul>
<?php ActiveForm::end(); ?>
Код: Выделить всё
$form.on('afterValidate', function (event, messages, deferreds) {
console.log(event);
console.log(messages);
console.log(deferreds);
switchIconSpin();
}).on('beforeSubmit', function (event, messages, deferreds) {
console.log(event);
console.log(messages);
console.log(deferreds);
$.ajax({
url: $form.attr('action'),
type: 'POST',
data: $form.serialize(),
/** @param {{status: string, cur_step: number, next_step: number, final_step: boolean}} data */
success: function (data) {
console.log(data);
if (data) {
if (data.status && !data.final_step) {
activeCurrentStep(data.next_step)
}
if (data.final_step) {
activeCurrentStep(data.cur_step + 1);
window.location.href = '/login';
}
}
},
error: function (jqXHR, errMsg) {
alert(errMsg);
}
});
return false; // prevent default submit
});
Второй шаг регистрации:
Получается следующее:
Мы проходим первый шаг регистрации, где по сценарию проверяется только почта. Валидация корректная, сообщение с ошибкой выводится.
Далее переходим ко второму шагу регистрации, где по сценарию логин и пароль. Вот тут валидация в модели проходит корректно, но почему-то в JS в событии AfterValidate в deferreds не возвращается текст сообщений об ошибках, который должен выводиться в форме. Хотя в параметре messages, эти сообщения об ошибках есть.
Как это исправить? Понимаю, что можно это всё обрабатывать вручную, но хотелось бы использовать валидацию из под коробки.