Inputfilter Authentication validator is fired even with a break_on_failure on previous inputfilter

Hello,

in a login form I have an email (required) and a password. I have 2 inputfilters, one for the email, the other for the password. The password Inputfilter has an Authentication Validator.

This is an example I made on a fresh install of Laminas MVC to reproduce the problem :

$factory = new Factory();

$service   = new AuthenticationService();
$adapter = new Callback();
$adapter->setCallback(static function ($identity, $credential) {
    return null;
});

$service->setAdapter($adapter);

$form = $factory->createForm([
    'name' => 'authentication-form',
    'elements' => [
        'identity' => [
            'spec' => [
                'name' => 'identity',
                'type' => 'email',
                'options' => ['label' => 'Email :'],
            ],
        ],
        'credential' => [
            'spec' => [
                'name' => 'credential',
                'type' => 'password',
                'options' => ['label' => 'Password :'],
            ],
        ],
        'button-submit' => [
            'spec' => [
                'name' => 'button-submit',
                'type' => 'button',
                'attributes' => ['type' => 'submit'],
                'options' => ['label' => 'Log in'],
            ],
        ],
    ],
    'input_filter' => [
        'identity' => [
            'name' => 'identity',
            'required' => true,
            'break_on_failure' => true,
        ],
        'credential' => [
            'name' => 'credential',
            'required' => true,
            'validators' => [
                Authentication::class => [
                    'name' => Authentication::class,
                    'options' => [
                        'identity' => 'identity',
                        'credential' => 'credential',
                        'service' => $service,
                        'adapter' => $adapter,
                    ],
                ],
            ],
        ],
    ],
]);

$form->setData(['identity' => 'emailwrong', 'credential' => 'mypassword']);

if (!$form->isValid()) {
    var_dump($form->getMessages());
}

I would like to stop the login process if the email is invalid. I put the credential InputFilter after the email one and I set ‘break_on_failure’ on the email InputFilter. But it doesn’t work, On the var_dump I have :

array(2) {
  ["identity"]=>
  array(1) {
    ["regexNotMatch"]=>
    string(114) "The input does not match against pattern '/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/'"
  }
  ["credential"]=>
  array(1) {
    ["general"]=>
    string(21) "Authentication failed"
  }
}

Did I miss something ?

Thank you in advance

Hello Denis,

you are adding an inputfilter for the ‘identity’ field without adding any validators to it. Therefore nothing is validated and the break_on_failure does not have any influence.
It must be break_chain_on_failure btw :slight_smile:

Try adding validators like this:

'identity' => [
        'name' => 'identity',
        'required' => true,
        'break_on_failure' => true,
        'validators' => [
                [
                    'name' => 'NotEmpty',
                    'break_chain_on_failure' => true,
                    'options' => [
                        'messages' => ['isEmpty' => 'Please enter username.'],
                    ],
                ],
                [
                    'name' => 'Regex',
                    'break_chain_on_failure' => true,
                    'options' => [
                        'pattern' => '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/',
                        'message' => [
                            'regexNotMatch' => 'Username has to be an email address',
                        ],
                    ],
                ],
            ]
         ],

Hello and welcome to the forums! :smiley:

Please note: You have only one input-filter and this one input-filter has two inputs: identity and credential.

This is wrong because the form element with type Email already adds a validator:

During the creation of the input-filter the order is changed because the Email element adds also an input specification. To solve your problem extend the form array and add a validation_group:

$form = $factory->createForm(
    [
        'name'             => 'authentication-form',
        'elements'         => [
            // …
        ],
        'input_filter'     => [
            // …
        ],
        'validation_group' => [
            'identity',
            'credential',
        ],
    ]
);

Thank you for all your responses.

@froschdesign yes I’m agree on the fact that I allready have a validator on email, that’s why I didn’t understand why that doesn’t work.

During the creation of the input-filter the order is changed

That’s the point ! When I check the validation process in Laminas, I see in vendor/laminas/laminas-inputfilter/src/BaseInputFilter.php in the replace() method :

$this->remove($name);
$this->add($input, $name); 

And in ZF2 it was :

$this->inputs[$name] = $input;

I don’t understand why this change, it seems to completely resort the validators…

Anyway I will try your solution with the validation_group. Thank you !

@froschdesign thank you again, I tried with validation_group and it worked