1

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?

3

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;
});
| improve this answer | |
  • 1
    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: docs.craftcms.com/api/v3/craft-elements-user.html#events – Levi Nelson Dec 18 '18 at 15:44
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.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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