Custom validation using database lookup

+
0
-

I have a user registration form, which performs some basic validation.
I wish to add a check if an email address validator to check if the email already exists in the users database table.

How/Where do custom validators get registered, and how to apply them?

Trying to do soeting like..

$form->addEmail('email', 'Email Address:')
    ->setRequired('Please enter a valid email Address.')
    ->addRule($this->userManager->userEmailExists($form['email']), 'Email address already in use', $form['email'])
    ->addRule(Form::MIN_LENGTH, 'Email must be at least %d characters', 12)
    ->addRule(Form::MAX_LENGTH, 'Email must be no longer than %d characters', 50);

Last edited by kevin.waterson@gmail.com (2020-07-09 04:46)

CZechBoY
Member | 3608
+
+1
-

You are missing callback function, with this code db lookup is created with each form creation.

+
0
-

CZechBoY wrote:

You are missing callback function, with this code db lookup is created with each form creation.

OK, thanks, what should I be reading in the docs about callback functions in validation?

CZechBoY
Member | 3608
+
0
-

sorry i didnt paste doc which i wanted :D
https://doc.nette.org/…s/validation

Last edited by CZechBoY (2020-07-09 14:13)

+
0
-

CZechBoY wrote:

sorry i didnt paste doc which i wanted :D
https://doc.nette.org/…s/validation

Hmm, but this would be called every time the form is loaded, not just submitted.. maybe not what I need.
How best to implement this sort of check?

CZechBoY
Member | 3608
+
+1
-

if you read docs i sent you could find this

<?php

// user validation: checks if $item is divisible by $arg
// note: this is a real function, not a method in the presenter
function divisibilityValidator(BaseControl $item, int $arg): bool
{
	return $item->getValue() % $arg === 0;
}

$form->addInteger('number', 'Number:')
	->addRule('divisibilityValidator', 'Number must be divisible by %d.', 8);
?>

Last edited by CZechBoY (2020-07-09 19:11)

+
-1
-

CZechBoY wrote:

if you read docs i sent you could find this

If you read the question I asked, you would see that I had read the docs and seeking further information.
If all you can respond with is smart ass answers, I would really prefer you not answer at all, regardless of your knowledge.

jiri.pudil
Nette Blogger | 1028
+
+4
-

Hmm, but this would be called every time the form is loaded, not just submitted

Quite the opposite. In your original example, the function would be called every time the form is loaded, and wouldn't really validate anything. You need to wrap the invocation in a function/callable which, when used as a validation rule, is called every time a form is validated, and determines whether the submitted value is valid or not.

$form->addEmail('email', 'Email Address:')
    ->setRequired('Please enter a valid email Address.')
    ->addRule(fn (TextInput $input) => ! $this->userManager->userEmailExists($input->getValue()), 'Email address already in use');

You can use a named function or a static method instead of an anonymous one, so that you can use the name to implement client-side validation, but I don't think client-side validation makes much sense in this particular use case, so an anonymous function is good enough here it would take some extra effort in this particular use case because it would require an AJAX request to the server.

By the way imo a better way to handle this kind of error is by catching the unique constraint violation exception during the database INSERT because only then is the whole operation atomic. You can then use $form['email']->addError('Email address already in use') to add the error manually.

Last edited by jiri.pudil (2020-07-10 10:56)

+
0
-

jiri.pudil wrote:

By the way imo a better way to handle this kind of error is by catching the unique constraint violation exception during the database INSERT because only then is the whole operation atomic. You can then use $form['email']->addError('Email address already in use') to add the error manually.

Thanks Jiri, I went with this option, and all is working as expected.