Captcha + Ajax validation

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Captcha + Ajax validation

Сообщение Drugpunker »

Здравствуйте.
Возможно тема облизана 100 раз, но нормального решения я не вижу.

Если включена ajax-валидация в форме, то валидация поля капчи всегда выдаёт: "Введён неверный проверочный код".

Поделитесь опытом пожалуйста.

Включена ajax валидация.

Код: Выделить всё

<?php $form = ActiveForm::begin([
                'id' => 'form-signup',
                'enableAjaxValidation' => true,
            ]); ?>
Экшн в контроллере:

Код: Выделить всё

public function actionSignup()
    {
        $model = new SignupForm();

        if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {

            Yii::$app->response->format = Response::FORMAT_JSON;
            return ActiveForm::validate($model);
        }

        if($model->load(Yii::$app->request->post())) {

            if ($user = $model->signup()) {

                if (Yii::$app->getUser()->login($user)) {
                    return $this->goHome();
                }
            }
        }
Понимаю, что из-за ajax код (новый) высылается повторно и поэтому валидацию не проходит.
Но не понимаю как реализовать.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Captcha + Ajax validation

Сообщение Drugpunker »

Неужели никто не сталкивался?
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Captcha + Ajax validation

Сообщение Dominus »

Пробуйте так.

Модель:

Код: Выделить всё


//...
use yii\captcha\CaptchaAction;

class SignupForm extends Model
{
    //...
    public $verifyCode;


    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            //...
            ['verifyCode', 'required'],
            ['verifyCode', 'validateCode'],
        ];
    }
    
    /**
     * Своя валидация для капчи
     */
    public function validateCode($attribute)
    {
        // тут экшен captcha по умолчанию, site/captcha
        $captcha = new CaptchaAction('captcha', Yii::$app->controller);
        if ($this->$attribute) {
            $code = $captcha->getVerifyCode();
            if ($this->$attribute !== $code) {
                $this->addError($attribute, 'The verification code is incorrect.');
            }
        }
    }
    
    //...
}
Форма обычная, с капчей:

Код: Выделить всё

<?php 
//...
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;
?>

<?php $form = ActiveForm::begin([
        'id' => 'form-signup',
        'enableAjaxValidation' => true
    ]); ?>

    <!-- другие поля --->

    <?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
        'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>'
    ]) ?>
    
    <!-- другие поля --->
    
<?php ActiveForm::end(); ?>
SiteController:

Код: Выделить всё

    //...

    /**
     * {@inheritdoc}
     */
    public function actions()
    {
        return [
           //...
            'captcha' => [
                'class' => 'yii\captcha\CaptchaAction',
                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
            ],
        ];
    }
    
    //...
    
    /**
     * Signs user up.
     *
     * @return array|string|Response
     */
    public function actionSignup()
    {
        $model = new SignupForm();

        if ($model->load(Yii::$app->request->post())) {

            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ActiveForm::validate($model);
            }

            if ($model->validate() && $model->signup()) {

                // После успешной регистрации, обновляем капчу
                $captcha = new \yii\captcha\CaptchaAction('captcha', $this);
                $captcha->getVerifyCode(true);

                Yii::$app->session->setFlash('success', 'Thank you for registration. Please check your inbox for verification email.');
                return $this->goHome();
            }
        }

        return $this->render('signup', [
            'model' => $model,
        ]);
    }
    
    //...
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Captcha + Ajax validation

Сообщение Drugpunker »

Dominus писал(а): 2020.06.24, 03:23 Пробуйте так.

Модель:

Код: Выделить всё


//...
use yii\captcha\CaptchaAction;

class SignupForm extends Model
{
    //...
    public $verifyCode;


    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            //...
            ['verifyCode', 'required'],
            ['verifyCode', 'validateCode'],
        ];
    }
    
    /**
     * Своя валидация для капчи
     */
    public function validateCode($attribute)
    {
        // тут экшен captcha по умолчанию, site/captcha
        $captcha = new CaptchaAction('captcha', Yii::$app->controller);
        if ($this->$attribute) {
            $code = $captcha->getVerifyCode();
            if ($this->$attribute !== $code) {
                $this->addError($attribute, 'The verification code is incorrect.');
            }
        }
    }
    
    //...
}
Форма обычная, с капчей:

Код: Выделить всё

<?php 
//...
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;
?>

<?php $form = ActiveForm::begin([
        'id' => 'form-signup',
        'enableAjaxValidation' => true
    ]); ?>

    <!-- другие поля --->

    <?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
        'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>'
    ]) ?>
    
    <!-- другие поля --->
    
<?php ActiveForm::end(); ?>
SiteController:

Код: Выделить всё

    //...

    /**
     * {@inheritdoc}
     */
    public function actions()
    {
        return [
           //...
            'captcha' => [
                'class' => 'yii\captcha\CaptchaAction',
                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
            ],
        ];
    }
    
    //...
    
    /**
     * Signs user up.
     *
     * @return array|string|Response
     */
    public function actionSignup()
    {
        $model = new SignupForm();

        if ($model->load(Yii::$app->request->post())) {

            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ActiveForm::validate($model);
            }

            if ($model->validate() && $model->signup()) {

                // После успешной регистрации, обновляем капчу
                $captcha = new \yii\captcha\CaptchaAction('captcha', $this);
                $captcha->getVerifyCode(true);

                Yii::$app->session->setFlash('success', 'Thank you for registration. Please check your inbox for verification email.');
                return $this->goHome();
            }
        }

        return $this->render('signup', [
            'model' => $model,
        ]);
    }
    
    //...

Я в итоге сделал с помощью сценариев.
Но там пришлось придушить немного метод $model->save(false), убрав повторную валидацию.
Короче невкусно и некрасиво вышло, но работоспособно.

Спасибо огромное.
Всё работает как надо и реализация продуманная.
Конечно же затёр свой подход.
Собственный валидатор - это отличнейшая и самая правильная реализация.
Ответить