Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-02-28T00:28:55.833Z
Answers.Text: 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.
Answers.UserDisplayName: supazu
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-02-28T15:04:34.570Z
Answers.Text: Yes, you're attaching the rules correctly, just using the wrong attribute name.
Answers.UserDisplayName: Ben Croker
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-02-28T23:47:31.700Z
Answers.Text: Sorry, `password` is incorrect? I don’t have a `newPassword` input, just `confirmPassword`.
Answers.UserDisplayName: supazu
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-02-28T23:53:04.517Z
Answers.Text: 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
Answers.UserDisplayName: Ben Croker
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-03-01T00:54:20.700Z
Answers.Text: 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)
Answers.UserDisplayName: supazu
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-03-01T17:03:14.153Z
Answers.Text: 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.
Answers.UserDisplayName: Ben Croker
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-03-02T22:44:53.457Z
Answers.Text: Does this answer your question @supazu?
Answers.UserDisplayName: Ben Croker
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-03-03T07:36:26.103Z
Answers.Text: 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.
Answers.UserDisplayName: supazu
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-02-27T16:47:22.543Z
Answers.LastActivityDate: 2023-03-01T17:02:50.817Z
Answers.LastEditDate: 2023-03-01T17:02:50.817Z
Answers.UserDisplayName: Ben Croker
Body: <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>
  
Tags: <modules><events>
Title: Custom validation & messages
ThreadText: # 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 %}
  
  <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?
  
  **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.
  
  ```php
          $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`.
  
  ```php
      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:
  
  ```php
  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.  
  
  ---
  
  