<p>The <code>User</code> class already defines a password rule on the <code>newPassword</code> attribute.</p>
<pre class="lang-php prettyprint-override"><code>        $rules[] = [
            ['newPassword'],
            UserPasswordValidator::class,
            'forceDifferent' =&gt; $this-&gt;passwordResetRequired,
            'currentPassword' =&gt; $currentPassword,
        ];
</code></pre>
<p>Source: <a href="https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/elements/User.php#L859-L864" rel="nofollow noreferrer">https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/elements/User.php#L859-L864</a></p>
<p>And the <code>UserPasswordValidator</code> class has a hard-coded minimum password length of <code>6</code>.</p>
<pre class="lang-php prettyprint-override"><code>    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);
    }
</code></pre>
<p>Source: <a href="https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/validators/UserPasswordValidator.php#L49-L62" rel="nofollow noreferrer">https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/validators/UserPasswordValidator.php#L49-L62</a></p>
<p>Since your rule is added to the <code>password</code> attribute, it has no effect on the <code>newPassword</code> attribute.</p>
<p>Here’s how you might replace the default rule with your own:</p>
<pre class="lang-php prettyprint-override"><code>Event::on(
    User::class,
    User::EVENT_DEFINE_RULES,
    function(DefineRulesEvent $event) {
        // Remove the `newPassword` rule
        foreach ($event-&gt;rules as $key =&gt; $rule) {
            if (isset($rule[0]) &amp;&amp; $rule[0] === ['newPassword']) {
                unset($event-&gt;rules[$key]);
            }
        }
        
        // Add your own `newPassword` rules
        $event-&gt;rules[] = [['newPassword'], 'string', 'min' =&gt; 10, 'tooShort' =&gt; Craft::t('yii','Password is too short')];
    }
);
</code></pre>

CC BY-SA 4.0
2023-02-28T00:28:55.833Z
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
CC BY-SA 4.0
2023-02-28T15:04:34.570Z
Yes, you're attaching the rules correctly, just using the wrong attribute name.
Ben Croker
CC BY-SA 4.0
2023-02-28T23:47:31.700Z
Sorry, `password` is incorrect? I don’t have a `newPassword` input, just `confirmPassword`.
supazu
CC BY-SA 4.0
2023-02-28T23:53:04.517Z
Right, but `newPassword` is the name of the attribute on the `User` element:
https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/controllers/UsersController.php#L1313
Ben Croker
CC BY-SA 4.0
2023-03-01T00:54:20.700Z
So the input attribute should be `newPassword` and the rule also on `newPassword`? If I do that, I get my error message if it's >6 but <10. But if it's less than 6 I get the Craft error (minimum 6)
supazu
CC BY-SA 4.0
2023-03-01T17:03:14.153Z
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
CC BY-SA 4.0
2023-03-02T22:44:53.457Z
Does this answer your question @supazu?
Ben Croker
CC BY-SA 4.0
2023-03-03T07:36:26.103Z
It definitely helped but I still haven't been able to get it to work. Probably something I'm doing but the errors still aren't working properly. I've shelved it for now, but will mark the answer as technically you are correct I think.
supazu
CC BY-SA 4.0
2023-02-27T16:47:22.543Z
2023-03-01T17:02:50.817Z
2023-03-01T17:02:50.817Z
Ben Croker
<p>I'm trying to add some custom validation rules to user sign up like this:</p>
<pre><code>Event::on(
  User::class, Element::EVENT_DEFINE_RULES, static function(DefineRulesEvent $event) {
    $event-&gt;rules[] = [['fullName', 'email'], 'required'];
    $event-&gt;rules[] = [['password'], 'string', 'min' =&gt; 10, 'tooShort' =&gt; Craft::t('yii','Password is too short')];
    $event-&gt;rules[] = ['password', 'compare', 'compareAttribute' =&gt; 'confirmPassword', 'message' =&gt; Craft::t('yii','Passwords do not match')];
  }
);
</code></pre>
<p>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:</p>
<pre><code>{% macro errorList(errors) %}
  {% if errors %}
    {{ ul(errors, {class: 'errors'}) }}
  {% endif %}
{% endmacro %}

&lt;input name=&quot;password&quot; type=&quot;password&quot;&gt;
{{ user ? _self.errorList(user.getErrors('password')) }}

&lt;input name=&quot;confirmPassword&quot; type=&quot;password&quot;&gt;
{{ user ? _self.errorList(user.getErrors('confirmPassword')) }}
</code></pre>
<p>Can anyone help me learn why the error won't show?</p>

<modules><events>
Custom validation & messages
# Custom validation & messages

(Asked by: username_0 on 2023-02-21)

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 %}


{{ user ? _self.errorList(user.getErrors('password')) }}


{{ user ? _self.errorList(user.getErrors('confirmPassword')) }}

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

**Tags:** modules, events


---

## 1 answers

### Answer by username_1 on 2023-02-27. Score: 4 | Accepted answer

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')];
    }
);

> **Comments:**
> **username_0**: 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.  
> **username_1**: Yes, you're attaching the rules correctly, just using the wrong attribute name.  
> **username_0**: Sorry, `password` is incorrect? I don’t have a `newPassword` input, just `confirmPassword`.  
> **username_1**: Right, but `newPassword` is the name of the attribute on the `User` element: https://github.com/craftcms/cms/blob/aad45b7d4c7005a0ac4809f32e135c6eadec7062/src/controllers/UsersController.php#L1313  
> **username_0**: So the input attribute should be `newPassword` and the rule also on `newPassword`? If I do that, I get my error message if it's >6 but <10. But if it's less than 6 I get the Craft error (minimum 6)  
> **username_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.  
> **username_1**: Does this answer your question @username_0?  
> **username_0**: It definitely helped but I still haven't been able to get it to work. Probably something I'm doing but the errors still aren't working properly. I've shelved it for now, but will mark the answer as technically you are correct I think.  

---

