Answers.Body: <p>I think you want the <code>$handled</code> property set to true. This is a base Yii property that says "I've handled this, stop processing anything else for it."</p>
  
  <p>I could be wrong, but the <code>$isValid</code> is only for "CancelableEvent" type and maybe some others as well.</p>
  
  <p>Looking at these pages:
  <a href="https://docs.craftcms.com/api/v3/craft-events-cancelableevent.html" rel="nofollow noreferrer">https://docs.craftcms.com/api/v3/craft-events-cancelableevent.html</a></p>
  
  <p><a href="https://www.yiiframework.com/doc/api/2.0/yii-base-event#" rel="nofollow noreferrer">https://www.yiiframework.com/doc/api/2.0/yii-base-event#</a>$handled-detail</p>
  
  <p>It's worth a shot.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-12-17T20:14:32.037Z
Answers.LastActivityDate: 2018-12-17T20:14:32.037Z
Answers.UserDisplayName: Vigilante
Answers.Body: <p>The event fired by element service is not cancellable, as that is a bit too broad to be controlled like that. Instead, you should be listening to the <code>EVENT_BEFORE_SAVE</code> on the <code>User</code> element as that supports the <code>isValid</code> property.</p>
  
  <pre><code>use craft\events\ModelEvent;
  use craft\elements\User;
  use yii\base\Event;
  
  Event::on(User::class, User::EVENT_BEFORE_SAVE, function(ModelEvent $event) {
      $event-&gt;sender-&gt;addErrors([
          'password' =&gt; 'Passwords do not match.'
      ]);
      $event-&gt;isValid = false;
  });
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-12-18T15:44:59.903Z
Answers.Text: Ah perfect! I did have to make one change. Just submitted the edit, `$event->element->addErrors()` should be `$event->sender->addErrors()`.
  
  Is the User `EVENT_BEFORE_SAVE` event documented anywhere? Sorry, still trying to get a handle on how Yii2 events live alongside Craft events, and where to look for each. I didn't see that event when I was looking here: https://docs.craftcms.com/api/v3/craft-elements-user.html#events
Answers.UserDisplayName: Levi Nelson
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-12-18T07:47:19.453Z
Answers.LastActivityDate: 2019-01-08T14:36:32.813Z
Answers.LastEditDate: 2019-01-08T14:36:32.813Z
Answers.UserDisplayName: Andris Sevcenko
Body: <p>I had a simple Password Confirmation validation function in Craft 2. In porting the function to Craft 3, I'm struggling to figure out how to handle the same thing. In Craft 2, all events were consistently handled by setting <code>$event-&gt;performAction = false</code> but in Craft 3, only a subset of events have a similar <code>isValid</code> option.</p>
  
  <p>Here is my previous Craft 2 version, triggered on <code>onBeforeSaveUser</code>...</p>
  
  <pre><code>public function confirmPassword($event)
  {
      // Only do anything if it is a front end submission
      // Only validates against passwordConfirm if field is present
      if (craft()-&gt;request-&gt;isSiteRequest()) {
          $password = Craft::$app-&gt;request-&gt;post('password');
          $passwordConfirm = Craft::$app-&gt;request-&gt;post('passwordConfirm');
          if (isset($passwordConfirm) &amp;&amp; strcmp($password, $passwordConfirm) !== 0) {
              $event-&gt;user-&gt;addErrors(array('passwordConfirm' =&gt; Craft::t('Passwords do not match.')));
              $event-&gt;performAction = false;
          }
      }
  }
  </code></pre>
  
  <p>In my attempt to port to Craft 3, right now, I'm listening for <code>EVENT_BEFORE_SAVE_ELEMENT</code> and then doing...</p>
  
  <pre><code>public function confirmPassword(ElementEvent $event)
  {
      // Only do anything if it is a front end submission
      // Only validates against passwordConfirm if field is present
  
      if (Craft::$app-&gt;request-&gt;isSiteRequest) {
  
          $password = Craft::$app-&gt;request-&gt;getBodyParam('password');
          $passwordConfirm = Craft::$app-&gt;request-&gt;getBodyParam('passwordConfirm');
  
          if (isset($passwordConfirm) &amp;&amp; strcmp($password, $passwordConfirm) !== 0) {
  
              $event-&gt;element-&gt;addErrors([
                  'password' =&gt; 'Passwords do not match.'
              ]);
  
              // WHAT DO I DO HERE TO PREVENT USER ELEMENT FROM SAVING?
  
          }
      }
  }
  </code></pre>
  
  <p>When I print out <code>$event-&gt;element-&gt;errors</code>, it correctly shows the errors. But the element is still saved. Am I missing a step here? Or is there a better way to handle this simple/custom validation?</p>
  
Tags: <plugin-development><craft3>
Title: Craft 3: Preventing Element from Saving in Plugin
ThreadText: # Craft 3: Preventing Element from Saving in Plugin
  
  (Asked by: username_0 on 2018-12-17)
  
  I had a simple Password Confirmation validation function in Craft 2. In porting the function to Craft 3, I'm struggling to figure out how to handle the same thing. In Craft 2, all events were consistently handled by setting `$event->performAction = false` but in Craft 3, only a subset of events have a similar `isValid` option.
  
  Here is my previous Craft 2 version, triggered on `onBeforeSaveUser`...
  
  ```
  public function confirmPassword($event)
  {
      // Only do anything if it is a front end submission
      // Only validates against passwordConfirm if field is present
      if (craft()->request->isSiteRequest()) {
          $password = Craft::$app->request->post('password');
          $passwordConfirm = Craft::$app->request->post('passwordConfirm');
          if (isset($passwordConfirm) && strcmp($password, $passwordConfirm) !== 0) {
              $event->user->addErrors(array('passwordConfirm' => Craft::t('Passwords do not match.')));
              $event->performAction = false;
          }
      }
  }
  
  ```
  
  In my attempt to port to Craft 3, right now, I'm listening for `EVENT_BEFORE_SAVE_ELEMENT` and then doing...
  
  ```
  public function confirmPassword(ElementEvent $event)
  {
      // Only do anything if it is a front end submission
      // Only validates against passwordConfirm if field is present
  
      if (Craft::$app->request->isSiteRequest) {
  
          $password = Craft::$app->request->getBodyParam('password');
          $passwordConfirm = Craft::$app->request->getBodyParam('passwordConfirm');
  
          if (isset($passwordConfirm) && strcmp($password, $passwordConfirm) !== 0) {
  
              $event->element->addErrors([
                  'password' => 'Passwords do not match.'
              ]);
  
              // WHAT DO I DO HERE TO PREVENT USER ELEMENT FROM SAVING?
  
          }
      }
  }
  
  ```
  
  When I print out `$event->element->errors`, it correctly shows the errors. But the element is still saved. Am I missing a step here? Or is there a better way to handle this simple/custom validation?
  
  **Tags:** plugin-development, craft3
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_2 on 2018-12-18. Score: 8 | Accepted answer
  
  The event fired by element service is not cancellable, as that is a bit too broad to be controlled like that. Instead, you should be listening to the `EVENT_BEFORE_SAVE` on the `User` element as that supports the `isValid` property.
  
  ```
  use craft\events\ModelEvent;
  use craft\elements\User;
  use yii\base\Event;
  
  Event::on(User::class, User::EVENT_BEFORE_SAVE, function(ModelEvent $event) {
      $event->sender->addErrors([
          'password' => 'Passwords do not match.'
      ]);
      $event->isValid = false;
  });
  
  ```
  
  > **Comments:**
  > **username_0**: Ah perfect! I did have to make one change. Just submitted the edit, `$event->element->addErrors()` should be `$event->sender->addErrors()`.  Is the User `EVENT_BEFORE_SAVE` event documented anywhere? Sorry, still trying to get a handle on how Yii2 events live alongside Craft events, and where to look for each. I didn't see that event when I was looking here: https://docs.craftcms.com/api/v3/craft-elements-user.html#events  
  
  ---
  
  ### Answer by username_1 on 2018-12-17. Score: 2
  
  I think you want the `$handled` property set to true. This is a base Yii property that says "I've handled this, stop processing anything else for it."
  
  I could be wrong, but the `$isValid` is only for "CancelableEvent" type and maybe some others as well.
  
  Looking at these pages:
  <https://docs.craftcms.com/api/v3/craft-events-cancelableevent.html>
  
  <https://www.yiiframework.com/doc/api/2.0/yii-base-event#>$handled-detail
  
  It's worth a shot.
  
  
  ---
  
  