J3.x

Difference between revisions of "Server-side form validation"

From Joomla! Documentation

(My contribution, I hope someone else will fill in the description and availability)
 
(Remove needs review. it's good enough)
 
(17 intermediate revisions by 12 users not shown)
Line 1: Line 1:
{{incomplete}}{{Review}}
 
 
After submitting a form, you should validate your data. In Joomla this can be done via the JForm validate method (normally called in the controller via the model JModelForm).
 
After submitting a form, you should validate your data. In Joomla this can be done via the JForm validate method (normally called in the controller via the model JModelForm).
  
Line 7: Line 6:
 
<source lang="xml"><field name="email" type="text" class="inputbox" description="Fill in your E-mail" label="E-mail" required="true" validate="email" size="30" /></source>
 
<source lang="xml"><field name="email" type="text" class="inputbox" description="Fill in your E-mail" label="E-mail" required="true" validate="email" size="30" /></source>
  
 +
 +
You can find the specific implementation of these rules in /libraries/joomla/form/form.php - validation begins in the function validate(), moves to validateField(), which then calls the respective validation functions of /libraries/joomla/form/rule/*.php
 +
 +
== Custom Validation rules ==
 +
Its very easy to add custom validation rules to your form elements. You can easily extend the JFormRule class to do this.
 +
 +
'''Add the rule path to your form:'''
 +
 +
In your form.xml file, add to the fieldset the following:
 +
 +
<source lang="xml">
 +
<form>
 +
    <fieldset name="form_name" addrulepath="components/com_yourcomponent/models/rules">
 +
       
 +
    </fieldset>
 +
</form></source>
 +
 +
This tells your form to look at:
 +
 +
<source lang="php">
 +
<joomla_root>/components/com_yourcomponent/models/rules/*.php</source>
 +
 +
And auto-loads any of the php files here which will have classes that act as rules.
 +
 +
'''Extend JFormRule'''
 +
 +
Create your rule file at:
 +
<source lang="php">
 +
<joomla_root>/components/com_yourcomponent/models/rules/[rule].php</source>
 +
 +
For example:
 +
 +
<source lang="php">
 +
<joomla_root>/components/com_yourcomponent/models/rules/date.php</source>
 +
 +
The contents of the file is important as well. You must extend the JFormRule class:
 +
 +
<source lang="php">
 +
class JFormRuleDate extends JFormRule</source>
 +
 +
The suffix of the classname (JFormRule[SUFFIX]) must be the same as the rule file name. For date.php, the class name should be JFormRuleDate. For integer you would have integer.php, and JFormRuleInteger.
 +
 +
'''Use a Regex, or override the test function'''
 +
 +
There's two ways to write the validator. The first and possibly easier is to simply override the $regex property of the JFormRule class. For an integer rule, the entire class looks like this:
 +
 +
<source lang="php">
 +
class JFormRuleInteger extends JFormRule
 +
{
 +
    protected $regex = '[0-9]';
 +
}</source>
 +
 +
But often times you want a slightly more complex validation rule, to do this its easier to override the test() method, providing your own implementation and ignoring the regex entirely.
 +
 +
For example, to test the format of a date:
 +
 +
    <source lang="php">
 +
public function test(SimpleXMLElement $element, $value, $group = null, JRegistry $input = null, JForm $form = null)
 +
    {
 +
        $dt = DateTime::createFromFormat("m/d/Y", $value);
 +
 +
        if ($dt instanceof DateTime) {
 +
            return true;
 +
        }
 +
        return false;
 +
    }</source>
 +
 +
Note: The test() method already exists in the JFormRule class, so here you are just extending the existing method.
 +
 +
All you need to do is make sure the method returns a 'true' or 'false' boolean when its done. It can call other methods and do any amount of checks to verify the entered value is correct.
 +
 +
'''Call the validation from your JForm Field'''
 +
 +
The last step in the validation process is to tell your form field which validation rule to use. This is easy. Just add the reference of the rule name to the Jform XML for the input element:
 +
 +
<source lang="xml">
 +
<field name="date_issued"  type="calendar" label="COM_YOURCOMPONENT_LABEL" hint="COM_YOURCOMPONENT_HINT"
 +
              description="COM_YOURCOMPONENT_DESC" size="20" required="true" class="form-control col-md-5" validate="date" format="%m/%d/%Y"
 +
                /></source>
 +
 +
The important part of that is the ''validate="date"'' part. Again, that must match the suffix of the JFormRule[SUFFIX], and the rule's filename: [suffix].php (in the models/rules directory).
 +
 +
'''Add a custom validation message'''
 +
 +
You may want to display a more useful message than the standard "Warning: Invalid Field".
 +
 +
For messages that don't need to be dynamic add a "message"  attribute to your form field.
 +
 +
<source lang="xml">
 +
<field name="date_issued"  type="calendar" label="COM_YOURCOMPONENT_LABEL" hint="COM_YOURCOMPONENT_HINT"
 +
              description="COM_YOURCOMPONENT_DESC" size="20" required="true" class="form-control col-md-5" validate="date" format="%m/%d/%Y" message="Your custom validation messsage goes here"
 +
                /></source>
 +
 +
You can provide a more dynamic message too. Say you want to include a variable in the message, or you do multiple tests inside the test() function which obviously may lead to different failure reasons, then you can add the custom and dynamic message from within the test() function.
 +
 +
    <source lang="php">
 +
public function test(SimpleXMLElement $element, $value, $group = null, JRegistry $input = null, JForm $form = null)
 +
    {
 +
        /* test 1 */
 +
        if ($value < 1) {
 +
            $element->attributes()->message = 'The value ' . $value . ' is not valid because it is less than 1';
 +
            // The above line works if you have already specified a custom message by adding the message="..." attribute
 +
            // to your form field. If you haven't then use instead
 +
            // $element->addAttribute('message', 'The value ' . $value . ' is not valid because it is less than 1');
 +
            return false;
 +
        }
 +
 +
        /* test 2 */
 +
        if ($value > 1000) {
 +
            $element->attributes()->message = 'The value ' . $value . ' is not valid because it is greater than 1000';
 +
            return false;
 +
        }
 +
 +
        return true;
 +
    }</source>
 +
 +
==Server- or Client-side validation?==
 +
[[Form validation]]
 
== Validation rules ==
 
== Validation rules ==
{| class="wikitable" style="vertical-align:top; border:1px solid Sienna; background-color:Cornsilk;"
+
{| class="wikitable sortable"  
|- style="background-color:Wheat; font-weight:bold; text-align: left;"
+
|-  
|Rule
+
!Rule
|Description
+
!Description
|Availability
+
!Availability
 
|-
 
|-
 
|
 
|
 
'''boolean'''
 
'''boolean'''
| Todo
+
| Accepts only the values '0', '1', 'true' or 'false' (case-insensitive).
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer
 
|-
 
|-
 
|
 
|
 
'''color'''
 
'''color'''
| Todo
+
| Accepts only empty values (converted to '#000000') and strings in the form '#RGB' or '#RRGGBB' where R, G, and B are hex values.
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.2}} and newer
 
 
 
|-
 
|-
 
|
 
|
 
'''email'''
 
'''email'''
| Todo
+
| Accepts an email address satisfies a basic syntax check in the pattern of "x@y.zz", with no invalid characters.
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer
 
 
 
|-
 
|-
 
|
 
|
 
'''equals'''
 
'''equals'''
| Todo
+
| Requires the value to be the same as that held in the field named "field", eg: <source lang="xml"><input type="text" name="email_check" validate="equals" field="email" /></source>
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer
 
 
 
|-
 
|-
 
|
 
|
 
'''options'''
 
'''options'''
| Todo
+
| Requires the value entered be one of the options in an element of type="list": that is, that the element is a select list.
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer  
 
 
 
|-
 
|-
 
|
 
|
 
'''rules'''
 
'''rules'''
 
| Todo
 
| Todo
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer  
 
 
 
|-
 
|-
 
|
 
|
 
'''tel'''
 
'''tel'''
| Todo
+
| Requires the value to be a Telephone number complying with the standards of nanpa, ITU-T T-REC-E.164 or ietf rfc4933.
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer
 
 
 
|-
 
|-
 
|
 
|
 
'''url'''
 
'''url'''
| Todo
+
| Validates that the value is a URL with a valid scheme (which can be restricted by the optional comma-separated field 'scheme'), and passes a basic syntax check. eg: <source lang="xml"><input type="text" name="link" validate="url" scheme="http,https,mailto" /></source>
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer
 
 
 
|-
 
|-
|
+
|  
 
'''username'''
 
'''username'''
| Todo
+
| Validates that the value does NOT appear as a username on the system; that is, that it is a valid new username. Does not syntax check it as a valid name.
| Todo (e.g. {{JVer|1.5}} and newer)
+
| {{JVer|11.1}} and newer
 
 
 
|-
 
|-
 
|}
 
|}

Latest revision as of 17:56, 29 March 2020

After submitting a form, you should validate your data. In Joomla this can be done via the JForm validate method (normally called in the controller via the model JModelForm).

Unlike client-side validation, the validation uses html attributes to do its validation. There is the attribute required ("true" or "required") which makes a field required and the attribute validate with a joomla or custom rule value.

E.g. field in a joomla form xml

<field name="email" type="text" class="inputbox" description="Fill in your E-mail" label="E-mail" required="true" validate="email" size="30" />


You can find the specific implementation of these rules in /libraries/joomla/form/form.php - validation begins in the function validate(), moves to validateField(), which then calls the respective validation functions of /libraries/joomla/form/rule/*.php

Custom Validation rules[edit]

Its very easy to add custom validation rules to your form elements. You can easily extend the JFormRule class to do this.

Add the rule path to your form:

In your form.xml file, add to the fieldset the following:

<form>
    <fieldset name="form_name" addrulepath="components/com_yourcomponent/models/rules">
         
    </fieldset>
</form>

This tells your form to look at:

<joomla_root>/components/com_yourcomponent/models/rules/*.php

And auto-loads any of the php files here which will have classes that act as rules.

Extend JFormRule

Create your rule file at:

<joomla_root>/components/com_yourcomponent/models/rules/[rule].php

For example:

<joomla_root>/components/com_yourcomponent/models/rules/date.php

The contents of the file is important as well. You must extend the JFormRule class:

class JFormRuleDate extends JFormRule

The suffix of the classname (JFormRule[SUFFIX]) must be the same as the rule file name. For date.php, the class name should be JFormRuleDate. For integer you would have integer.php, and JFormRuleInteger.

Use a Regex, or override the test function

There's two ways to write the validator. The first and possibly easier is to simply override the $regex property of the JFormRule class. For an integer rule, the entire class looks like this:

class JFormRuleInteger extends JFormRule
{
    protected $regex = '[0-9]';
}

But often times you want a slightly more complex validation rule, to do this its easier to override the test() method, providing your own implementation and ignoring the regex entirely.

For example, to test the format of a date:

public function test(SimpleXMLElement $element, $value, $group = null, JRegistry $input = null, JForm $form = null)
    {
        $dt = DateTime::createFromFormat("m/d/Y", $value);

        if ($dt instanceof DateTime) {
            return true;
        }
        return false;
    }

Note: The test() method already exists in the JFormRule class, so here you are just extending the existing method.

All you need to do is make sure the method returns a 'true' or 'false' boolean when its done. It can call other methods and do any amount of checks to verify the entered value is correct.

Call the validation from your JForm Field

The last step in the validation process is to tell your form field which validation rule to use. This is easy. Just add the reference of the rule name to the Jform XML for the input element:

<field name="date_issued"  type="calendar" label="COM_YOURCOMPONENT_LABEL" hint="COM_YOURCOMPONENT_HINT"
               description="COM_YOURCOMPONENT_DESC" size="20" required="true" class="form-control col-md-5" validate="date" format="%m/%d/%Y"
                />

The important part of that is the validate="date" part. Again, that must match the suffix of the JFormRule[SUFFIX], and the rule's filename: [suffix].php (in the models/rules directory).

Add a custom validation message

You may want to display a more useful message than the standard "Warning: Invalid Field".

For messages that don't need to be dynamic add a "message" attribute to your form field.

<field name="date_issued"  type="calendar" label="COM_YOURCOMPONENT_LABEL" hint="COM_YOURCOMPONENT_HINT"
               description="COM_YOURCOMPONENT_DESC" size="20" required="true" class="form-control col-md-5" validate="date" format="%m/%d/%Y" message="Your custom validation messsage goes here"
                />

You can provide a more dynamic message too. Say you want to include a variable in the message, or you do multiple tests inside the test() function which obviously may lead to different failure reasons, then you can add the custom and dynamic message from within the test() function.

public function test(SimpleXMLElement $element, $value, $group = null, JRegistry $input = null, JForm $form = null)
    {
        /* test 1 */
        if ($value < 1) {
            $element->attributes()->message = 'The value ' . $value . ' is not valid because it is less than 1';
            // The above line works if you have already specified a custom message by adding the message="..." attribute
            // to your form field. If you haven't then use instead
            // $element->addAttribute('message', 'The value ' . $value . ' is not valid because it is less than 1');
            return false;
        }

        /* test 2 */
        if ($value > 1000) {
            $element->attributes()->message = 'The value ' . $value . ' is not valid because it is greater than 1000';
            return false;
        }

        return true;
    }

Server- or Client-side validation?[edit]

Form validation

Validation rules[edit]

Rule Description Availability

boolean

Accepts only the values '0', '1', 'true' or 'false' (case-insensitive). Joomla 11.1 and newer

color

Accepts only empty values (converted to '#000000') and strings in the form '#RGB' or '#RRGGBB' where R, G, and B are hex values. Joomla 11.2 and newer

email

Accepts an email address satisfies a basic syntax check in the pattern of "x@y.zz", with no invalid characters. Joomla 11.1 and newer

equals

Requires the value to be the same as that held in the field named "field", eg:
<input type="text" name="email_check" validate="equals" field="email" />
Joomla 11.1 and newer

options

Requires the value entered be one of the options in an element of type="list": that is, that the element is a select list. Joomla 11.1 and newer

rules

Todo Joomla 11.1 and newer

tel

Requires the value to be a Telephone number complying with the standards of nanpa, ITU-T T-REC-E.164 or ietf rfc4933. Joomla 11.1 and newer

url

Validates that the value is a URL with a valid scheme (which can be restricted by the optional comma-separated field 'scheme'), and passes a basic syntax check. eg:
<input type="text" name="link" validate="url" scheme="http,https,mailto" />
Joomla 11.1 and newer

username

Validates that the value does NOT appear as a username on the system; that is, that it is a valid new username. Does not syntax check it as a valid name. Joomla 11.1 and newer