1

I'm trying to add some custom validation rules to user sign up like this:

Event::on(
  User::class, Element::EVENT_DEFINE_RULES, static function(DefineRulesEvent $event) {
    $event->rules[] = [['fullName', 'email'], 'required'];
    $event->rules[] = [['password'], 'string', 'min' => 10, 'tooShort' => Craft::t('yii','Password is too short')];
    $event->rules[] = ['password', 'compare', 'compareAttribute' => 'confirmPassword', 'message' => Craft::t('yii','Passwords do not match')];
  }
);

But I still get 'New Password should contain at least 6 characters.' instead of 10 and no error shows for the password mis-match. The fields on my registration form are:

{% macro errorList(errors) %}
  {% if errors %}
    {{ ul(errors, {class: 'errors'}) }}
  {% endif %}
{% endmacro %}

<input name="password" type="password">
{{ user ? _self.errorList(user.getErrors('password')) }}

<input name="confirmPassword" type="password">
{{ user ? _self.errorList(user.getErrors('confirmPassword')) }}

Can anyone help me learn why the error won't show?

1 Answer 1

4
+50

The User class already defines a password rule on the newPassword attribute.

        $rules[] = [
            ['newPassword'],
            UserPasswordValidator::class,
            'forceDifferent' => $this->passwordResetRequired,
            'currentPassword' => $currentPassword,
        ];

Source: https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/elements/User.php#L859-L864

And the UserPasswordValidator class has a hard-coded minimum password length of 6.

    public const MIN_PASSWORD_LENGTH = 6;

    public function __construct(array $config = [])
    {
        // Default min
        if (!isset($config['min'])) {
            $config['min'] = self::MIN_PASSWORD_LENGTH;
        }

        // Default max
        if (!isset($config['max'])) {
            $config['max'] = self::MAX_PASSWORD_LENGTH;
        }

        parent::__construct($config);
    }

Source: https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/validators/UserPasswordValidator.php#L49-L62

Since your rule is added to the password attribute, it has no effect on the newPassword attribute.

Here’s how you might replace the default rule with your own:

Event::on(
    User::class,
    User::EVENT_DEFINE_RULES,
    function(DefineRulesEvent $event) {
        // Remove the `newPassword` rule
        foreach ($event->rules as $key => $rule) {
            if (isset($rule[0]) && $rule[0] === ['newPassword']) {
                unset($event->rules[$key]);
            }
        }
        
        // Add your own `newPassword` rules
        $event->rules[] = [['newPassword'], 'string', 'min' => 10, 'tooShort' => Craft::t('yii','Password is too short')];
    }
);
8
  • That makes sense, thank you. So is EVENT_DEFINE_RULES the right event? I was using EVENT_BEFORE_VALIDATE before but ran into some issues there.
    – supazu
    Commented Feb 28, 2023 at 0:28
  • Yes, you're attaching the rules correctly, just using the wrong attribute name.
    – Ben Croker
    Commented Feb 28, 2023 at 15:04
  • Sorry, password is incorrect? I don’t have a newPassword input, just confirmPassword.
    – supazu
    Commented Feb 28, 2023 at 23:47
  • Right, but newPassword is the name of the attribute on the User element: github.com/craftcms/cms/blob/…
    – Ben Croker
    Commented Feb 28, 2023 at 23:53
  • 1
    That's because you've added an additional rule, rather than removing the old one. I've updated my answer to show how you might replace the rule.
    – Ben Croker
    Commented Mar 1, 2023 at 17:03

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.