1

I'm trying to add some rules for users signing up. The first two (fullName and email) work fine. However, the password rules are triggered no matter what. Even if the passwords match and are over 8 characters, it still fails.

Event::on(User::class, Model::EVENT_BEFORE_VALIDATE, static function (Event $event) {
  // If a user is already logged in we are not on the public registration page
  if (Craft::$app->getUser()->getIdentity()) {
    return;
  }
  $user = $event->sender;

  // Do the custom validation
  if (!$user->fullName) {
    $user->addError('fullName', Craft::t('yii', 'Please enter your name.'));
    $event->isValid = false;
  }

  if (!$user->email) {
    $user->addError('email', Craft::t('yii', 'Please enter a valid email.'));
    $event->isValid = false;
  }

  if (mb_strlen($user->password) < 8) {
    $user->addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event->isValid = false;
  }

  if ($user->password != $user-> confirmPassword) {
    $user->addError('confirmPassword', Craft::t('yii', 'Passwords do not match'));
    $event->isValid = false;
  }
});
<label for="password">Password</label>
<input id="password" name="password" type="password">
{{ user ? forms.errorsList(user.getErrors('password')) }}

<label for="confirmPassword">Confirm Password</label>
<input id="confirmPassword" name="confirmPassword" type="password">
    {{ user ? forms.errorsList(user.getErrors('confirmPassword')) }}
</div>

Can anyone spot what I'm missing?

1 Answer 1

1

When setting a password during front end registration using the core users/save-user action, Craft actually sets the newPassword attribute on the user model under the hood, not the password attribute.

This means that you need to test the length for the newPassword attribute, not the password attribute, i.e.:

if (mb_strlen($user->newPassword) < 8) {
    $user->addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event->isValid = false;
  }

Another issue with your code is the if ($user->password != $user->confirmPassword) { conditional.

The user model doesn't actually have a confirmPassword attribute, so it's odd if you're not seeing an exception thrown here (are you using devMode during development?). But regardless, the code is not going to work as intended.

Note that you also can't do $user->addError('confirmPassword', ...) – again, since the user model doesn't actually have that attribute; the addError() method only works with actual attributes.

Assuming confirmPassword is the name for an input in your registration form, you'll need to change your code to something like this (personally I think an if/else statement makes sense here, since you can't set separate errors on the model for the password and the "confirm password"):

if (mb_strlen($user->newPassword) < 8) {
    $user->addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event->isValid = false;
  } else if ($user->newPassword !== Craft::$app->getRequest()->getBodyParam('confirmPassword')) {
    $user->addError('password', Craft::t('yii', 'Passwords do not match'));
}

Beyond this, while doing custom validation in an EVENT_BEFORE_VALIDATE event handler should work, the recommended way to do custom validation in Craft is to add Yii validation rules via the Element::EVENT_DEFINE_RULES event. Check out this page in the official docs.

1
  • 1
    Wow, thanks for the detailed answer! My code was kind of hacked together from some old questions on here - shows I still have so much to learn. Thank you.
    – supazu
    Commented Jan 15, 2023 at 0:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.