Jump to content

form->processInput doesn't catch missing InputfieldCheckbox


Recommended Posts

Posted (edited)

I'm trying to create a newsletter signup form with the API and validate/sanitize it with form->processInput.
It only has two inputs: email and a consent checkbox.

When I submit the form with an empty or malformed email, I get form errors after calling processInput.
But when I don't check the checkbox, the submission gets through without errors. 

It seems like setting required(true) on the checkbox has no effect.

Is this normal and I have to manually sanitize checkboxes? I'd expect it to behave like the other input and automatically create an error.

These functions are inside a page class:

public function createForm() {
    $modules = $this->wire()->modules;
    
    /** @var InputfieldForm */
    $form = $modules->get('InputfieldForm');
    $form->method = 'post';
    $form->action = $this->url;
    
    /** @var InputfieldEmail */
    $field = $modules->get('InputfieldEmail');
    $field->label = __('Email*');
    $field->attr('id+name', 'email');
    $field->attr('placeholder', $field->label);
    $field->required(true);
    $field->requiredAttr(true);
    $form->append($field);
    
    /** @var InputfieldCheckbox */
    $field = $modules->get('InputfieldCheckbox');
    $field->label = '%consent_label%';
    $field->attr('id+name', 'newsletter_consent');
    $field->attr('required', true);
    $field->required(true);
    $form->append($field);

    ...

    return $form;
}

public function progressInput() {
    $input = wire()->input;
    
    $this->form = $this->createForm();

    if($input->post('newsletter_submit')) {
        // Process the form with current input
        $this->form->processInput($input->post);
        
        $errors = $this->form->getErrors();
        if(!count($errors)) {
            $this->subscribeToMailchimp();
        }
    }
}

Template:

$page->progressInput();
$errors = $page->form->getErrors(true);
  
if(count($errors) > 0) {
  foreach($errors as $error) { 
    echo $error;
  }
}

echo $page->form->render();

 

Edited by thausmann
Link to comment
Share on other sites

Posted (edited)

Idk, it works as expected for me. The only thing I changed from your code was removing $field->attr('required', true), so the browser would let me send without checking the box. And making everything into plain functions so I could just put them in a template.

The required-check happens in InputfieldWrapper and there is no special logic for checkboxes (InputfieldCheckbox::processInput() will find no errors, leaving it to InputfieldWrapper). You can check it out here: https://github.com/processwire/processwire/blob/44fcf13ea2d7f14a04eed54c29afcc79eb46ec45/wire/core/InputfieldWrapper.php#L1304

// check if a value is required and field is empty, trigger an error if so
if($child->attr('name') && $child->getSetting('required') && $child->isEmpty()) {
	$requiredLabel = $child->getSetting('requiredLabel'); 
	if(empty($requiredLabel)) $requiredLabel = $this->requiredLabel;
	$child->error($requiredLabel); 
}

The error value will be “%consent_label% - Missing required value”.

As we can see, this depends on InputfieldCheckbox::isEmpty(), which simply negates InputfieldCheckbox::checked(). The rest is a little weird, but suffice it to say that the posted form data is examined using PHP’s empty(), so if any value at all has been sent for the checkbox (“newsletter_consent”), it’ll pass the required check. By default the value would be the string '1', and if unchecked, as we know, no mention of the checkbox would be sent at all.

Edited by Jan Romero
  • Like 1
Link to comment
Share on other sites

Thanks so much Jan for double checking! 

You found the culprit: removing $field->attr('required', true); really makes the key difference. When I was testing, I bypassed the browser check by removing the required attribute through the dev tools.

The solution is to use $field->requiredAttr = true; instead! One of those seem to have some side effects that cause the unwanted behaviour. In the past, I had a syntax error because I used $field->requiredAttr(true); which works for text inputs, but not checkboxes, interestingly. After checking the docs again, it's supposed to just be a property and not a method call. Which is a bit confusing because there is $field->required(true)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...