Difference between revisions of "lib/formslib.php Validation"

Jump to: navigation, search
(MoodleQuickForm::addRule())
(moodleform and groups -- evil gotcha)
 
(11 intermediate revisions by 6 users not shown)
Line 7: Line 7:
 
You use this typically inside your moodleform::definition method. For example to set a field as required.
 
You use this typically inside your moodleform::definition method. For example to set a field as required.
  
<pre>
+
 
        $mform->addElement('text','shortname', get_string('shortname'),'maxlength="15" size="10"');
+
 
        $mform->setHelpButton('shortname', array('courseshortname', get_string('shortname')), true);
+
 
        $mform->setDefault('shortname', get_string('defaultcourseshortname'));
+
 
        $mform->addRule('shortname', null, 'required', null, 'client');
+
<code php>
        $mform->setType('shortname', PARAM_MULTILANG);
+
$mform->addElement('text','shortname', get_string('shortname'),'maxlength="15" size="10"');
</pre>
+
$mform->setHelpButton('shortname', array('courseshortname', get_string('shortname')), true);
 +
$mform->setDefault('shortname', get_string('defaultcourseshortname'));
 +
$mform->addRule('shortname', null, 'required', null, 'client');
 +
$mform->setType('shortname', PARAM_MULTILANG);
 +
</code>
  
 
There is good documentation for this on the [http://pear.php.net/manual/en/package.html.html-quickform.intro-validation.php PEAR web site]
 
There is good documentation for this on the [http://pear.php.net/manual/en/package.html.html-quickform.intro-validation.php PEAR web site]
Line 19: Line 23:
 
In Moodle formslib you can set certain rules' error message to null and a default error message will automatically be used. The default messages are defined in lang/{language}/form.php. Here are the English definitions :
 
In Moodle formslib you can set certain rules' error message to null and a default error message will automatically be used. The default messages are defined in lang/{language}/form.php. Here are the English definitions :
  
<pre>
+
<code php>
 
$string['err_alphanumeric']='You must enter only letters or numbers here.';
 
$string['err_alphanumeric']='You must enter only letters or numbers here.';
 
$string['err_email']='You must enter a valid email address here.';
 
$string['err_email']='You must enter a valid email address here.';
Line 30: Line 34:
 
$string['err_rangelength']='You must enter between {$a->format[0]} and {$a->format[1]} characters here.';
 
$string['err_rangelength']='You must enter between {$a->format[0]} and {$a->format[1]} characters here.';
 
$string['err_required']='You must supply a value here.';
 
$string['err_required']='You must supply a value here.';
</pre>
+
</code>
  
 
== moodleform::validation() ==
 
== moodleform::validation() ==
  
Define a method validation on your moodleform child to make your own custom validation for the form. This is done on the client side. And data_submitted will return null until the function returns no errors. You return an array of errors if there is any error or an empty array if there are no errors.
+
Define a method validation on your moodleform child to make your own custom validation for the form. This is done on the server side. And data_submitted will return null until the function returns no errors. You return an array of errors if there is any error or an empty array if there are no errors.
  
<pre>
+
<code php>
 
class course_edit_form extends moodleform {
 
class course_edit_form extends moodleform {
  
Line 43: Line 47:
 
     }
 
     }
  
 
+
    // Perform some extra moodle validation
/// perform some extra moodle validation
+
     function validation($data, $files) {
     function validation($data) {
 
 
         $errors= array();
 
         $errors= array();
 
         if ($foundcourses = get_records('course', 'shortname', $data['shortname'])) {
 
         if ($foundcourses = get_records('course', 'shortname', $data['shortname'])) {
Line 69: Line 72:
 
}
 
}
 
?>
 
?>
</pre>
+
</code>
 +
 
 +
Also, note that if you decide to override this method in your child class, depending of its hierarchy, '''you'll need to perform one call to its parent validation() method''' in order to avoid missing various checks. Although it may be not necessary if your form is direct descendant of moodleform (because it does not contain any check), it is safe, in all cases, to start the method with this call:
 +
 
 +
<code php>
 +
class gorgeous_form extends parent_form {
 +
    ...
 +
    ...
 +
    // Perform some extra moodle validation
 +
    function validation($data, $files) {
 +
        $errors = parent::validation($data, $files);
 +
        ...
 +
        ...
 +
    }
 +
}
 +
</code>
  
 
{{Moodle 1.9}}There is a new parameter $files in Moodle 1.9, it allows validation of uploaded files too.
 
{{Moodle 1.9}}There is a new parameter $files in Moodle 1.9, it allows validation of uploaded files too.
<pre>
+
 
 +
<code php>
 
     function validation($data, $files) {
 
     function validation($data, $files) {
         $errors = parrent::validate($data, $files);
+
         $errors = parent::validation($data, $files);
 
         if (empty($files['userfile'])) {
 
         if (empty($files['userfile'])) {
 
             if (array_key_exists('url', $data)) {
 
             if (array_key_exists('url', $data)) {
Line 82: Line 101:
 
         return $errors;
 
         return $errors;
 
     }
 
     }
</pre>
+
</code>
 +
 
 +
{{Moodle 1.9}}To validate a recaptcha element use the following code inside the function validation($data) {
 +
:
 +
<code php>
 +
if (!empty($CFG->recaptchapublickey) && !empty($CFG->recaptchaprivatekey)) {
 +
    $recaptcha_element = $this->_form->getElement('recaptcha_field_name');
 +
    if (!empty($this->_form->_submitValues['recaptcha_challenge_field'])) {
 +
        $challenge_field = $this->_form->_submitValues['recaptcha_challenge_field'];
 +
        $response_field = $this->_form->_submitValues['recaptcha_response_field'];
 +
        if (true !== ($result = $recaptcha_element->verify($challenge_field, $response_field))) {
 +
            $errors['recaptcha_field_name'] = $result;
 +
        }
 +
    } else {
 +
        $errors['recaptcha_field_name'] = get_string('missingrecaptchachallengefield');
 +
    }
 +
}
 +
</code>
 +
 
 +
== Validation and groups: an edge case ==
 +
 
 +
When validating elements which are added to your form via MoodleQuickForm::addGroup(), be sure to apply errors on the group and not individual elements.
 +
 
 +
If your form fields are defined as follows:
 +
 
 +
<code>
 +
        $fields= array(
 +
            $mform->createElement('text', 'field'),
 +
            $mform->createElement('button', 'validatefield'),
 +
        );
 +
        $mform->addGroup($fields, 'group', '', '', false);
 +
</code>
 +
 
 +
Your validation should do the following:
 +
 
 +
<code>
 +
        if (!is_valid($data['field'])) {
 +
            $errors['group'] = get_string('validationfailed', 'xxx_yyy');
 +
        }
 +
</code>

Latest revision as of 18:06, 19 March 2015


There are two ways to add validation in the forms lib.

MoodleQuickForm::addRule()

You use this typically inside your moodleform::definition method. For example to set a field as required.



$mform->addElement('text','shortname', get_string('shortname'),'maxlength="15" size="10"');
$mform->setHelpButton('shortname', array('courseshortname', get_string('shortname')), true);
$mform->setDefault('shortname', get_string('defaultcourseshortname'));
$mform->addRule('shortname', null, 'required', null, 'client');
$mform->setType('shortname', PARAM_MULTILANG);

There is good documentation for this on the PEAR web site

In Moodle formslib you can set certain rules' error message to null and a default error message will automatically be used. The default messages are defined in lang/{language}/form.php. Here are the English definitions :

$string['err_alphanumeric']='You must enter only letters or numbers here.';
$string['err_email']='You must enter a valid email address here.';
$string['err_lettersonly']='You must enter only letters here.';
$string['err_maxlength']='You must enter not more than $a->format characters here.';
$string['err_minlength']='You must enter at least $a->format characters here.';
$string['err_nopunctuation']='You must enter no punctuation characters here.';
$string['err_nonzero']='You must enter a number not starting with a 0 here.';
$string['err_numeric']='You must enter a number here.';
$string['err_rangelength']='You must enter between {$a->format[0]} and {$a->format[1]} characters here.';
$string['err_required']='You must supply a value here.';

moodleform::validation()

Define a method validation on your moodleform child to make your own custom validation for the form. This is done on the server side. And data_submitted will return null until the function returns no errors. You return an array of errors if there is any error or an empty array if there are no errors.

class course_edit_form extends moodleform {
 
    function definition() {
        blah blah;
    }
 
    // Perform some extra moodle validation
    function validation($data, $files) {
        $errors= array();
        if ($foundcourses = get_records('course', 'shortname', $data['shortname'])) {
            if (!empty($data['id'])) {
                unset($foundcourses[$data['id']]);
            }
            if (!empty($foundcourses)) {
                foreach ($foundcourses as $foundcourse) {
                    $foundcoursenames[] = $foundcourse->fullname;
                }
                $foundcoursenamestring = implode(',', $foundcoursenames);
                $errors['shortname']= get_string('shortnametaken', '', $foundcoursenamestring);
            }
        }
 
        if (empty($data['enrolenddisabled'])){
            if ($data['enrolenddate'] <= $data['enrolstartdate']){
                $errors['enroldateendgrp'] = get_string('enrolenddaterror');
            }
        }
        return $errors;
    }
}
?>

Also, note that if you decide to override this method in your child class, depending of its hierarchy, you'll need to perform one call to its parent validation() method in order to avoid missing various checks. Although it may be not necessary if your form is direct descendant of moodleform (because it does not contain any check), it is safe, in all cases, to start the method with this call:

class gorgeous_form extends parent_form {
    ...
    ...
    // Perform some extra moodle validation
    function validation($data, $files) {
        $errors = parent::validation($data, $files);
        ...
        ...
    }
}

Moodle1.9 There is a new parameter $files in Moodle 1.9, it allows validation of uploaded files too.

function validation($data, $files) {
        $errors = parent::validation($data, $files);
        if (empty($files['userfile'])) {
            if (array_key_exists('url', $data)) {
                $errors['url'] = get_string('required');
            }
        }
        return $errors;
    }

Moodle1.9 To validate a recaptcha element use the following code inside the function validation($data) {

if (!empty($CFG->recaptchapublickey) && !empty($CFG->recaptchaprivatekey)) {
    $recaptcha_element = $this->_form->getElement('recaptcha_field_name');
    if (!empty($this->_form->_submitValues['recaptcha_challenge_field'])) {
        $challenge_field = $this->_form->_submitValues['recaptcha_challenge_field'];
        $response_field = $this->_form->_submitValues['recaptcha_response_field'];
        if (true !== ($result = $recaptcha_element->verify($challenge_field, $response_field))) {
            $errors['recaptcha_field_name'] = $result;
        }
    } else {
        $errors['recaptcha_field_name'] = get_string('missingrecaptchachallengefield');
    }
}

Validation and groups: an edge case

When validating elements which are added to your form via MoodleQuickForm::addGroup(), be sure to apply errors on the group and not individual elements.

If your form fields are defined as follows:

        $fields= array(
            $mform->createElement('text', 'field'),
            $mform->createElement('button', 'validatefield'),
        );
        $mform->addGroup($fields, 'group', '', '', false);

Your validation should do the following:

        if (!is_valid($data['field'])) {
            $errors['group'] = get_string('validationfailed', 'xxx_yyy');
        }