This type of map will permit you to add different types of validations on the fields of a module.
The accepted format is:
<map> <originmodule> <originname>SalesOrder</originname> </originmodule> <fields> <field> <fieldname>subject</fieldname> {field to validate} <validations> {if more than one is present they must all pass to accept the value} <validation> <rule>{rule_name}</rule> <restrictions> <restriction>{values depend on the rule}</restriction> </restrictions> <message>This is my custom msg for field: {field}</message> {optional} </validation> ..... </validations> </field> <field> ..... </field> </fields>
where {rule_name} can be:
{rule_name}
Restrictions
required - Required field
none equals - Field must match another field (email/password confirmation | name of the other field different - Field must be different than another field | name of the other field accepted - Checkbox or Radio must be accepted (yes, on, 1, true)
none numeric - Must be numeric
numeric - Must be numeric integer - Must be integer number
none array - Must be array
none length - String must be a certain length
number lengthBetween - String must be between given lengths
two restrictions of type number lengthMin - String must be greater than given length
number lengthMax - String must be less than given length
number min - Minimum
number max - Maximum
number in - Performs in_array check on given array value
list of values of the array notIn - Negation of in rule (not in array of values)
list of values of the array ip - Valid IP address
IP number email - Valid email address
none url - Valid URL
none urlActive - Valid URL with active DNS record
none alpha - Alphabetic characters only
none alphaNum - Alphabetic and numeric characters only
none slug - URL slug characters (a-z, 0-9, -, _)
none regex - Field matches a given regex pattern
regular expression. be careful you may have to put this inside a CDATA date - Field is a valid date
none dateFormat - Field is a valid date in the given format
date format dateBefore - Field is a valid date and is before the given date
date in ISO format dateAfter - Field is a valid date and is after the given date
date in ISO format contains - Field is a string and contains the given string
string creditCard - Field is a valid credit card number
list of accepted credit cards, if none given all supported cards will be checked, supported cards: Visa visa, Mastercard mastercard, Dinersclub dinersclub, American Express amex or Discover discover requiredWith - Field is required if any other fields are present
list of fields requiredWithout - Field is required if any other fields are NOT present
list of fields IBAN_BankAccount - validate IBAN Bank Account number
none EU_VAT - validate EU VAT number
none notDuplicate - checks that no other record with the same value exists on the given fieldname
none expression - accept a workflow expression map and evaluate it in the context of the new screen values
map name or id custom - launch custom function that can be found in the indicated
file name, validation test name, function name and label to show on error (will be translated)
All of the rules above accept an optional directive named message where you can set the error message you want the user to see when an error on that field happens. If this is not established a standard error message will be returned. Inside this message you can use the curly brace field tag to indicate where you want the field name to appear: This is my custom msg for field: {field}
The trigger for these maps is that they must be of type “Validations” and the “Target Module” must be set correctly. If more than one record is found, they will ALL be applied.
Accessing other fields in the form
You can use the values of other fields on the form by putting the field name inside two curly brackets. For example, the next map will validate that the field dtstart is before the value in field dtend.
<map> <originmodule> <originname>cbCalendar</originname> </originmodule> <fields> <field> <fieldname>dtend</fieldname> <validations> <validation> <rule>dateAfter</rule> <restrictions> <restriction></restriction> </restrictions> </validation> </validations> </field> </fields> </map>
There is an important limitation when using the values of other fields. These values will only be available when editing the whole record. If the user is doing an inline individual field edit on the detail view, the value of the other fields will not be available. To overcome this limitation, you need to create a custom validation rule and access the values you need from the database.
Other information available during validation
In order to enhance the set of possible validations that can be done, the validation system automatically adds some values that you can use freely.
Current values
When editing a record it is possible to want to compare the value introduced by the user with the value that is currently saved in that same field or some other field with which it may have some dependency. In this case, you can access these values prefixing the string “current_” to the variable name. For example, let's suppose that we are editing an Account, the user has changed the Industry picklist value and we want to check what the currently saved value is before accepting the change. Let's imagine a rule that says:
Any account whose industry is set to Banking, cannot be changed
In this case, we can easily access the value that the user has selected by putting the industry field and to access the value saved in the application we would use: current_industry, something like this:
<map> <originmodule> <originname>Accounts</originname> </originmodule> <fields> <field> <fieldname>current_industry</fieldname> <validations> <validation> <rule>notIn</rule> <restrictions> <restriction>Banking</restriction> </restrictions> </validation> </validations> </field> </fields> </map>
Product lines
In inventory modules, the system will load all the information of the lines into the pdoInformation array which will look something like this:
pdoInformation => array( array( 'crmid' = {first line product/service ID}, 'qty' = {first line quantity (units)}, 'name' = {first line product/service name}, 'type' = {first line product/service type}, ),
Some other examples
Another example of how to limit the accepted values in a picklist, even making it mandatory if needed.
<map> <originmodule> <originname>cbCalendar</originname> </originmodule> <fields> <field> <fieldname>activitytype</fieldname> <validations> <validation> <rule>notIn</rule> <restrictions> <restriction>Call</restriction> <restriction>Meeting</restriction> </restrictions> </validation> </validations> </field> </fields> </map>
This next example contains a REGEX expression that will not accept any alphabetical letter in the accountname field and there must be at least one character. Important things to notice in the REGEX expression are:
-
you must set the initial and end of line markers as the value is compared as a complete string
-
you may or may not need the CDATA depending on the regex (the one below does not need CDATA)
-
modifiers are not supported in the expression
<map> <originmodule> <originname>Accounts</originname> </originmodule> <fields> <field> <fieldname>accountname</fieldname> <validations> <validation> <rule>regex</rule> <restrictions> <restriction><![CDATA[/^[^A-Za-z]+$/]]></restriction> </restrictions> </validation> </validations> </field> </fields> </map>
Custom Validations
coreBOS has some custom validations that are not loaded by default but can be used if necessary:
-
Brazilian ID Number: file include/validation/validateCPFCNPJ.php
-
validaCPF
-
validaCNPJ
-
validaCNPJ2
-
-
Spanish ID Number: file include/validation/validatorESIDNumber.php
-
isValidDNI
-
isValidNIE
-
isValidNIF
-
isValidCIF
-
isValidPersonalESID = isValidDNI or isValidNIE or isValidNIF
-
isValidESID = isValidPersonalESID or isValidCIF
-
-
Italian ID Number: file include/validation/validatePIVA.php
-
checkAccountPIVA
-
For example, a validation for a valid CIF on account siccode field looks like this:
<map> <originmodule> <originname>Accounts</originname> </originmodule> <fields> <field> <fieldname>siccode</fieldname> <validations> <validation> <rule>custom</rule> <restrictions> <restriction>include/validation/validatorESIDNumber.php</restriction> <restriction>isValidCIF</restriction> <restriction>isValidCIF</restriction> </restrictions> </validation> </validations> </field> </fields> </map>
Test Validation Business Mapping
These are the two validation maps I used while developing the integration of the mapping in the save process:
<map> <originmodule> <originname>Accounts</originname> </originmodule> <fields> <field> <fieldname>accountname</fieldname> <validations> <validation> <rule>required</rule> </validation> <validation> <rule>contains</rule> <restrictions> <restriction>mex</restriction> </restrictions> </validation> </validations> </field> <field> <fieldname>industry</fieldname> <validations> <validation> <rule>notDuplicate</rule> </validation> </validations> </field> </fields> </map> <map> <originmodule> <originname>Accounts</originname> </originmodule> <fields> <field> <fieldname>email1</fieldname> <validations> <validation> <rule>custom</rule> <restrictions> <restriction>modules/cbMap/Validation.php</restriction> <restriction>testemail</restriction> <restriction>validate_testacccemail</restriction> </restrictions> </validation> </validations> </field> </fields> </map>
both are set for the Accounts module.
This is the custom validation script:
function validate_testacccemail($field) { global $log;$log->fatal('validation for'.$field); return true; }
Expression Map
<map> <originmodule> <originname>Accounts</originname> </originmodule> <fields> <field> <fieldname>employees</fieldname> <validations> <validation> <rule>expression</rule> <restrictions> <restriction>AccountsEmployees_ConditionExpression</restriction> </restrictions> </validation> </validations> </field> </fields> </map> <map> <expression>if employees > 10 then 1 else 0 end</expression> </map>