Joey33's avatar
Level 1

Bail in Password::defaults()

When chaining methods to Password object in defaults() to specify extra requirements is it possible to show a single error message at a time? I'd like to implement a bail-like behaviour not to clutter the input field with all the messages simultaneously.

So I'd like to show only letters error now and mixedCase in the next submit if necessary

Password::defaults(function () {
   $rule = Password::min(8);
   return $rule->letters()
                    ->mixedCase()
                    ->numbers()
                    ->symbols();
});
0 likes
7 replies
Sinnbeck's avatar

I dont see a way sadly. It runs all of them inside password validation class at once. It doesnt check for bail or similar. Also it isnt macroable..

            if ($this->mixedCase && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) {
                $validator->addFailure($attribute, 'password.mixed');
            }

            if ($this->letters && ! preg_match('/\pL/u', $value)) {
                $validator->addFailure($attribute, 'password.letters');
            }

            if ($this->symbols && ! preg_match('/\p{Z}|\p{S}|\p{P}/u', $value)) {
                $validator->addFailure($attribute, 'password.symbols');
            }

            if ($this->numbers && ! preg_match('/\pN/u', $value)) {
                $validator->addFailure($attribute, 'password.numbers');
            }

You could just set them directly in the validator

$this->validate($request, [
        'password' => ['bail', 'required', 'confirmed', Password::min(8)->mixedCase(), Password::min(8)->letters(), ...etc..],
]);
1 like
Joey33's avatar
Level 1

@Sinnbeck yes, that's a solution I've come up with for the time being but it's awkward and was hoping to reorganize it in a more elegant way in boot() method of app service provider. A sidenote: I've had to put them like the following:

 'password' => ['bail', 'required',
                           Password::min(8)->mixedCase(),
                           Password::min(8)->numbers(),
                           Password::min(8)->symbols(),

            ],

repeating min each time since numbers or letters cannot be called statically.

Anyway thanks for casting light on the issue. I'll leave it like this for now, it works:)

tykus's avatar

I'd like to implement a bail-like behaviour not to clutter the input field with all the messages simultaneously.

Bad UX IMHO. As I user, I would prefer to see all of the errors together rather than be forced to re-enter a password over and over trying to solve the next failure.

1 like
Sinnbeck's avatar

@tykus completely agree. But I at least hope they use something like precognition (or livewire) to show errors as you type

Joey33's avatar
Level 1

@tykus good point! however I put a succinct hint as to what the password should contain above the very field and the custom messages when displayed all at once took like 5 lines so it is overwhelming. But with custom shorter messages it should be more readable. @sinnbeck thanks for the hint with live checking as the user types.

martinbean's avatar

@joey33 Just show the first error message in your view if that’s the behaviour you’re wanting?

<input name="password" type="password">
@if($errors->has('password')
    <div>{{ $errors->first('password') }}</div>
@endif

You shouldn’t be messing about with Password::defaults to do this. This is a client-side concern, not a server-side one.

1 like
Joey33's avatar
Level 1

@martinbean brilliant idea! I haven't thought about it, thx:) I just need to reorganize my components a bit to display only ->first(...) of the array. As to the server-side you're right, but following the bail logic (which is actually ss) I thought sth similar could be achieved in defaults(). But your idea is simple and hits the nail on the head.

1 like

Please or to participate in this conversation.