2

In the rules() of my RegisterForm model:

[ 'user_username', 'unique', 'targetClass' => 'app\models\User', 'message' => 'This username is already been taken.' ],

In my controller:

$model = new RegisterForm();
if ( $model->load( Yii::$app->request->post() ) ) {
    if ( $user = $model->register() ) {
        return $this->redirect( [ '/login' ] );
    }
}

In RegisterForm:

public function register() {  
    $user = new User();
    $user->user_firstname = $this->user_firstname;
    $user->user_lastname = $this->user_lastname;
    $user->user_username = $this->user_username;
    $user->user_email = $this->user_email;
    $user->setPassword( $this->user_password );

    if ( !$user->validate() ) {
        return null;
    }    

    if ( $user->save() ) {
        return $user;   
    }

    return null;
}

Form:

<?php $form = ActiveForm::begin(); ?>

<?= $form->field( $model, 'user_firstname' )->textInput( [ 'maxlength' => true ] ) ?>

<?= $form->field( $model, 'user_lastname' )->textInput( [ 'maxlength' => true ] ) ?>

<?= $form->field( $model, 'user_username' )->textInput( [ 'maxlength' => true ] ) ?>

<?= $form->field( $model, 'user_email' )->textInput( [ 'maxlength' => true ] ) ?>

<?= $form->field( $model, 'user_password' )->passwordInput() ?>

<?= $form->field( $model, 'user_password_repeat' )->passwordInput() ?>

<?= Html::submitButton( 'Register', [ 'class' => 'btn btn-primary', 'name' => 'register-button' ] ) ?>

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

Yet when I enter a username that I know already exists, the error never comes up and the record tries to save, though I get: Integrity constraint violation: 1062 Duplicate entry ...

EDIT: if I add the unique rule to the User model itself the form will not submit if I input a username that exists, the errors just don't show up

keeg
  • 3,990
  • 8
  • 49
  • 97

1 Answers1

3

Like I have suspected, you are not checking for unique user_username attribute in client side. The reason why it's not working it's because you are not sending Ajax requests to check the results from database. Unlike other rules, unique rule requires additional Ajax requests to server since it would be pretty bad thing if Javascript would retrieve all currently registered username and store somewhere in Client side.

To solve you problem, in form write something like this:

$form = ActiveForm::begin([
    'enableAjaxValidation' => true,
    'validationUrl' => [<URL HERE>],
]);

Now you have to create a method (action) in controller that returns validation (not just unique, all of them) back to ActiveForm. So it could be something like this:

public function actionAjaxValidation()
{
    $post = Yii::$app->request->post();
    $model = new YourClass();

    if (!$model->load($post)) {
        throw new HttpException(403, 'Cannot load model');
    }

    $array = ActiveForm::validate($model);

    return json_encode($array);
}
Gynteniuxas
  • 7,035
  • 18
  • 38
  • 54
  • Right but if someone doesn't have JS enabled, this will fail. Shouldn't it be handled on server side? I shouldn't get far enough to be able to try to insert into DB and get a constraint error – keeg Dec 18 '16 at 08:00
  • Unfortunately, JS is required to be able to work with `unique` validator. :/ This actually goes to other validators as well (like `length`, `integer`, etc.), since if JS is disabled, user will not get any errors even if he enters incorrect data. Only when submitting the form he will see those errors. – Gynteniuxas Dec 18 '16 at 08:04
  • Strange. It's not mentioned anywhere in the documentation... http://www.yiiframework.com/doc-2.0/yii-validators-uniquevalidator.html I swear I've used it before without having to use Ajax... seems almost pointless to have it if you are basically writing a custom validator – keeg Dec 18 '16 at 08:10
  • Yii2 build validation for Client side by writing JS/jQuery functions/events that are retrieved from `rules()`. It is set as default (since it's possible to disable). A little more information: [Client side validation](http://www.yiiframework.com/doc-2.0/guide-input-validation.html#client-side-validation) – Gynteniuxas Dec 18 '16 at 08:19