FormHandler success message when not successful

emergingdzns - 2 weeks ago

I've got a form builder and a handler on a stream. However, when the user saves the form, attempting to enter an email address that's already associated with an account or a mismatched password etc (basically failed validation) it returns back as expected but it's throwing the "success" message at the top before the validator error message.

In the CustomerFormBuilder.php file I have the following (among others):

    protected $options = [
        'success_message'   => 'Customer Account Information Saved',
    ];

In the form, I have added a password field, a confirm password field and an email field. This way when the customer fills in their info, they are able to be added as a user. In my CustomerFormHandler.php file I have it setup like this (please don't give me crap about using the Input class. I know... I'm supposed to use Request. I did this before I really understood that. I'll update eventually):

class CustomerFormHandler
{
    public function handle(CustomerFormBuilder $builder,
                            Redirector $redirect,
                            UserRepositoryInterface $users,
                            Repository $config,
                            UserActivator $activator,
                            UserAuthenticator $authenticator,
                            RoleRepositoryInterface $roles) {
        if (!$builder->canSave()) {
            return;
        }
        if (Input::has('createAccount') && Input::get('createAccount') == "yes" && [email protected]::user()) {
            $username = $display_name = str_replace(['.','@'], ['_','_'], Input::get('email'));
            $email = Input::get('email');
            $password = Input::get('password');
            $confirm_password = Input::get('confirm_password');

            // verify passwords match
            $validator = Validator::make([
                    'email' => $email,
                    'password' => $password,
                    'password_confirmation' => $confirm_password
                ],[
                    'email' => 'required|email|unique:users_users,email',
                    'password' => 'required|confirmed'
                ],[
                    'email.required' => 'Email address is required',
                    'email.email' => 'Email address is not valid',
                    'email.unique' => 'The email address entered is already registered. Click Edit on Step 1 and Login to use that account.',
                    'password.required' => 'The password and confirm password fields are both required',
                    'password.confirmed' => 'The password and confirmation do not match'
                ]);

            if ($validator->fails()) {
                return Redirect::back()->with('error',$validator->errors()->all())->withInput();
            }
            $user = $users->create([
                'username' => $username,
                'display_name' => $display_name,
                'email' => $email,
                'password' => $password
            ]);

            $activator->force($user);

            $memberRole = $roles->findBySlug('members');
            $user->attachRole($memberRole);

            $authenticator->login($user);
            $this->transmit(new UserHasRegistered($user));
        }

        $builder->saveForm();
        $entry = $builder->getFormEntry();
    }
}

So in the code above, it returns back when the validator fails... BEFORE it does the saveForm() function. So why is it throwing a success message when it returns back?

Answer

ryanthompson - 2 weeks ago

Not reading through all the way but by the time if hits the handler - it's already been validated.

Try using your own form validator:

protected $validator = MyFormValidator::class

Or use class transformation like normal and do like protected $validator = MyFormValidator::class right next to your builder.

I don't have anything but the core example to look at but you can do anything you want in there: https://github.com/anomalylabs/streams-platform/blob/1.3/src/Ui/Form/FormValidator.php

ryanthompson - 2 weeks ago

Not reading through all the way but by the time if hits the handler - it's already been validated.

Try using your own form validator:

protected $validator = MyFormValidator::class

Or use class transformation like normal and do like protected $validator = MyFormValidator::class right next to your builder.

I don't have anything but the core example to look at but you can do anything you want in there: https://github.com/anomalylabs/streams-platform/blob/1.3/src/Ui/Form/FormValidator.php

emergingdzns - 2 weeks ago

I could create my own class I suppose but I don't think that would ultimately answer the question. In essence I've just added some code to the form handler at the beginning of the process that tells it to go back with all inputs and give it a message. I'm doing that BEFORE the save function is run. Just like you have the return when !$builder->canSave(). If the builder couldn't save, it would return back to the form and presumably NOT throw the success message at the top. It seems as though simply being submitted, but not actually saved, is triggering success, before I'm then triggering an error message. So when it goes back it shows both success and failure in the messages partial at the top of the page.

emergingdzns - 2 weeks ago

I think I get it now. I was just reading the PostForm file and realized that the form handler system has a defined set of possible returns. So if I create a validation class it will know that it's a failure, otherwise it has no understanding of the problem so it continues on with SetSuccessMessage.

emergingdzns - 2 weeks ago

Ok so another question. If I create a validator, do I have to then validate all fields? Or can I just worry about the fields that aren't actually part of the customer model form/record (specifically the email/password fields)?

emergingdzns - 2 weeks ago

Nevermind. I think I've got it! Thanks for the suggestion @ryanthompson

emergingdzns - 2 weeks ago

Ok so I have one more question @ryanthompson . I have it now validating and such, BUT the problem is that when the form does go through the handler, it throws an error about the password column not existing in the Customer model, which is true. So I added password and password_confirmation to the $skips of the form builder and no more errors. It saves everything, but in the handler, I need to be able to add the password entered into the user object I'm creating, but of course it's coming up blank because it's getting skipped.

So the question is, how do avoid using the skips variable but remove the password and password_confirmation fields from the $builder->saveForm(); call?

I tried changing it to $builder->skipField('password')->skipField('password_confirmation')->saveForm(); but still get the error about password column not existing.

emergingdzns - 2 weeks ago

Disregard. I forgot to unguard() the $users repository object. Ugh.