Please rate how useful you found this document: 
Average: 2.5 (4 votes)

Overview

ProcessMaker uses conditions in a number of different situations to determine whether execution happens or not. Conditions evaluate to either true or false, based upon the Boolean logic found in PHP. Conditions can be defined for Steps (DynaForms, Input Documents, Output Documents, and Triggers), Evaluation and Parallel by Evaluation routing rules, and Events.

In addition, conditions can be created to show or hide elements in a DynaForm using JavaScript's Boolean logic.

Understanding Conditions

Conditions in ProcessMaker are based upon Boolean Logic, which is the idea that any expression can be evaluated to either a value of True or False. If the expression is True, then the execution will occur. If it is False, no execution will occur. In ProcessMaker, a condition can take many forms. These are all valid types of conditions:

ConditionDescription
3124.5A floating point number which evaluates to true
"hello world"A string which evaluates to true
FalseA boolean value of false
@@ContactTypeA case variable
@%Total == 400Equality comparison with an integer
"check" == @@PaymentTypeEquality comparison with a string
@@USR_USERNAME != 'admin'Non-equality comparison with a string
@#InvoiceAmount > 100.00Greater than comparison with a floating point number
max(@#Invoice, @#TotalBill) < 1000Less than comparison with the return value from a function
(@#Price - @#Discount) * @%Quantity <= 3000Less than comparison to a mathematical operation with () to prioritize elements
(@#Amount >= 5000.00 and @@priority == "high")Two comparisons joined by a Boolean AND
((@@contact=="sales" or @@contact=="lead")
and !(@@priority=="high"))
Logical OR, AND, NOT with () to prioritize elements

Variables in Conditions

Conditions can contain system or case variables, which are preceded by an @ sign and then another symbol which indicates how the variable is parsed:

Variable TypeDescription
@@variable_nameThe variable will be parsed as string type. If originally another type, it will be converted to a string. So -1, 0 and 12.45 become "-1", "0" and "12.45", respectively.
@%variable_nameThe variable will be parsed as integer type (a whole number). If originally another type, it will be converted to an integer. A real number will be converted to a whole number, so 12.45 becomes 12. A string which contains numbers will be converted to a whole number, so "655" and "34.19" become 655 and 34, respectively.
@#variable_nameThe variable will be parsed as float type (a real number with decimals).
@?variable_nameThe variable will be parsed as a string used in a URL. The string is transformed with PHP's encodeurl(), so all spaces become pluses (+) and all characters which aren't letters, except underscores (_), are replaced by a % followed by a 2 hexadecimal digits, so that the string can be used in posted data to/from WWW forms.
@$variable_nameThe variable will be parsed as a string for use in an SQL query. Any single quotation marks (') will be preceded by a backslash. So "I'm telling you it's a boy!" becomes "I\'m telling you it\'s a boy!".
@=variable_nameThe variable will not be changed and is parsed as its original type.
 

Case variables are variables which hold information about a case and they are created either when a field in a DynaForm is submitted or when defined in a trigger. Variables names must start with either a letter or underscore and they are case sensitive, so @@_myvar, @@myvar, @@MyVar, @@MYVAR, and @@myvar2 are five different variables. Make sure to spell case variables exactly like their field name in DynaForms or how they were defined in a trigger.

Conditions can NOT contain local or global PHP variables which were defined in triggers, but they can use PHP's superglobal variables, such as $_SERVER['SERVER_ADDR'] and $_ENV['PATH'].

If a condition only contains a variable (and nothing else), then the value of the variable will be examined and evaluated to true or false. In PHP, a value is only considered false when it is one of the following values:

ValueDescription
FALSEA boolean value of false
0An integer zero
0.0A float zero
""An empty string
"0"A string with a value of zero
array()An array with zero elements
new StdClass()An object with zero member variables
NULLA special value meaning "no value"

All other values in PHP are considered true. For example, all of these values are considered true:

ValueDescription
TRUEA boolean value of true
97A positive integer
-4A negative integer
100.99A positive float
-4.23A negative float
"a nice string"A non-empty string
array("jack", "jill", "hill")A non-empty array

Comparison operators in Conditions

If a condition contains a comparison operator, such as equals, greater than or less than, then the values to the right and left of the operator will be compared and evaluated to true or false. The following comparison operators are available in PHP:

OperatorDescriptionExample
==Equals@@CurrencyType == "dollars"
===Equals to same variable type@%Total === 100
<>Not equals@@CurrencyType <> "euros"
!=Not equals@%Total != 0
!==Not equals to same variable type@=RunTest !== false
<Less than@%Total < 1000
<=Less than or equal to@#SubTotal <= @#Total
>Greater than@#Balance > 0
>=Greater than or equal topow(@#Total, 3) >= @#Limit

Type Conversion

It is generally a good idea to use the correct type of variable when doing comparisons, so if comparing to a string, use @@variable_name. If comparing to an integer, use @%variable_name. If comparing to a floating point number, use @#variable_name. If comparing to a boolean value, an array or an object, use @=variable_name. Nonetheless, if the types don't match, PHP will try to convert both values to the same type before doing the comparison. Due to type conversion, the following conditions are all considered true:

True ConditionDescription
"42" == 42The string "42" is converted into the integer 42, then compared.
" 42 " == 42The string " 42 " is converted into the integer 42 (spaces are ignored), then compared.
"42 frogs" == 42The string "42 frogs" is converted into the integer 42, then compared. Only strings starting with numbers can be converted into integers or floats.
42 == 42.0The integer 42 is converted into the float 42.0, then compared.
0 == falseThe integer 0 is converted into the boolean FALSE, then compared.
42 == trueThe integer 42 is converted into the boolean TRUE, then compared.
"" == falseThe empty string "" is converted into the boolean FALSE, then compared
"hello" == trueThe string "hello" is converted into the boolean TRUE, then compared.
 

To prevent the comparison from converting value types, then use the === and !== operators which will only be evaluate to true if comparing the same types of values, so "42"==42 is true, but "42"===42 is false.

While automatic type conversion can be useful, remember that conversion will not round numbers, nor will it truncate strings. Here are a number of solutions to common problems in conditions:

False ConditionProblemSolutionExamples
    
42 == 42.1The integer 42 is converted to the float 42.0 which doesn't equal 42.1, so condition evaluates to false.Use the (int) type cast or the @% variable parsing to convert a float into an integer.42 == (int) 42.1
42 == @%Total
    
42 == (int) 41.999When the float 41.999 is converted to an integer, all decimal numbers are simply dropped and there is no rounding up, so the comparison is 42 == 41.Use PHP's round() function to round to the nearest integer. Also use the ceil() and floor() functions to round a number up or down.42 == round(41.999)
42 == round(@#Total)
5 / 2 == 2.5This is false, because the integer 5 is divided by the integer 2. Since both are integers, the result is the integer 2 (the remainder is dropped). Then, the integer 2 is converted to the float 2.0 to compare with 2.5.Use the type cast (float) or reference the variable as @# to convert one of the numbers to a float before dividing. This will cause the a floating point division, so the remainder won't be lost.5 / (float) 2 == 2.5
5 / @#var == 2.5
42.12 == 42.123In order for two floats to be equal, their decimal numbers must also be equal.Specify the number of decimal points to round to before comparing.42.12 == round(42.123, 2)
42.12 == round(@#Total, 2)
"hel" == "hello"The condition is false, because strings have to have the same number of characters to be equal.Use PHP's substr() function to cut the string to a set number of characters before comparing. To compare a variable number of characters use the strlen() function. To look for a string inside another string, use the strstr() function."hel" == substr("hello", 0, 3)
"hel" == substr(@@s, 0, 3)
@@s1 == substr(@@s2, 0, strlen(@@s1))
strstr(@@s, "hel")
"hello" == " hello "The condition is false, because PHP doesn't eliminate spaces when comparing strings.Use PHP's trim() function to eliminate any whitespace (including tabs and returns) from the beginning or end of a string. Also use ltrim() or rtrim() to only eliminate from the beginning or end of a string."hello" == trim(" hello ")
"hello" == trim(@@Greet)
"HeLlO" == "hello"The condition is false, because the comparison of strings is case sensitive.Use strtoupper() or strtolower() to convert the strings to the same case or use strcasecmp() or strncasecmp() to do case insensitive comparisons.strtolower("HeLlo") == "hello"
strtoupper(@@s1) == strtoupper(@@s2)
!strcasecmp(@@s1, @@s2)

Math in Conditions

Conditions can use PHP's mathematical operators, such as - (negation), + (addition), - (subtraction), * (multiplication), / (division), % (modulus, i.e., division remainder). When using mathematical operators, keep in mind the rules of operator precedence and remember to use parentheses to evaluate certain elements before other elements in the expression.

If needing to do more advanced mathematical operations, use PHP math functions such as pow(), max(), min(), sin(), cos(), log(), abs(), etc.

Logical Operators in Conditions

Conditions can also use logical operators to join together multiple expressions and construct complex conditions.

 
OperatorExampleDescription
and(@@a and @@b)True if both @@a and @@b are true.
&&(@@a && @@b)True if both @@a and @@b are true. && is like the and operator, but has a higher operator precedence.
or(@@a or @@b)True if either @@a or @@b is true.
||(@@a || @@b)True if either @@a or @@b is true. || is like the or operator, but has a higher operator precedence.
xor(@@a xor @@b)True if either @@a or @@b is true, but not both.
!!@@aReverses the valence so true becomes false and false becomes true.

Like true and false, the spelling of the and, or, xor operators is case insensitive, so and can also be spelled as And, AnD, AND, etc.

Warning: If using the logical operators AND, OR, XOR, &&, || in a condition, it is recommended to enclose the statement inside parentheses () to ensure that the entire statement is evaluated and not just the first part of the statement. However it is recommended to use && and || instead of AND, OR, XOR. In recent versions of ProcessMaker, the following condition:
@@myvar != "X" AND @@myvar != "Y"
is evaluated as:
@@myvar != "X"
To ensure that the entire statement is evaluated, enclose it in parentheses:
(@@myvar != "X" AND @@myvar != "Y")

Strings in conditions

Most data entered into DynaForm fields is stored as strings, so it is useful to know how to handle strings in ProcessMaker. All strings must be enclosed in either single quotes '...' or double quotes "...". Strings enclosed in single quotes have their characters treated as literal values, whereas PHP interprets escaped characters in double quoted strings. For instance, \t is interpreted as a tab and \n is interpreted as a hard return.

Note: Unlike normal PHP variables which can be inserted inside double quoted strings, such as "I say $greeting to you" or "Give {$arrayNames['manager']} the letter", ProcessMaker case variables can not be inserted inside double quoted strings, so "I say @@Greeting to you" will not work.

PHP uses the dot operator "." to concatenate strings. For example, "Hello" . " " . "World!" evaluates to "Hello World!". People coming from other languages commonly try to do "Hello" + " " + "World!", but PHP only uses the + operator for adding integers and floats, so it will try to convert each string into an integer or float and then add them together. If the string starts with a number (such as '42 is the answer' or " 3.5 duckies"), then it will successfully convert, otherwise it will become zero, so "Hello" + " " + "World!" becomes 0 + 0 + 0

ProcessMaker system and case variables can be concatenated. Remember to reference them as @@variable_name, so they will be parsed as strings:

  • "Hello " . @@USR_USERNAME
  • @@FirstName . ' ' . @@LastName

Operator Precedence in Conditions

A condition is evaluated according to the rules of operator precedence, so certain operators will be executed before other operators.

For example, how does ProcessMaker know whether 2 + 3 * 4 equals 20 or 14? If addition has precedence over multiplication, then first 2 + 3 = 5, then 5 * 4 = 20. If multiplication has precedence, then first 3 * 4 = 12, then 2 + 12 = 14. Since ProcessMaker uses the PHP rules of operator precedence, multiplication has higher precedence than addition, so the result is 14.

In the following table, the operators are ordered according to their precedence, with the highest precedence at the top. So parentheses "()" have the highest precedence and commas "," have the lowest.

OperatorsDescription
( )Group elements to have highest precedence.
[ ]Access an element in an array or a character in a string
++ --Increment or decrement operator
- (type)Negation, Type casting such as (int), (float), (string), (boolean), etc.
!Logical NOT (inverse of true or false)
* / %Multiplication, division, modulus
+ - .Addition, subtraction, string concatenation
< <= > >= <>Greater than, less than, not equal to
== != === !==Equal, not equal, equal same type, not equal same type
&&Logical AND
||Logical OR
? :Ternary operator for constructing if-then-else statements
= ^= <<= >>= =>Assignment operators
andLogical AND
xorLogical XOR
orLogical OR
,Commas separate parameters in function calls and elements in arrays
 

If operators are in the same precedence level, then they are parsed from left to right. For example, in the expression 5 - 6 / 2 . " for you!", division has the highest precedence so 6 / 2 will happen first. Subtraction and string concatenation (which is the "." operator) have the same precedence, therefore the leftmost operator, which is subtraction will happen first, followed by concatenation. Here is the order of the operations:

  • 6 / 2 = 3
  • 5 - 3 = 2
  • Integer 2 converted into the string "2", then: "2" . " for you!" = "2 for you!"

In order to change the order of operations, place parenthesis around elements to give them the highest precedence. For example, the expression @#Price - @#Discount * @%Quantity can not be used to calculate the total price, because the discount needs to be subtracted before multiplying by the quantity. Therefore parentheses can be used to first subtract, then multiply: (@#Price - @#Discount) * @%Quantity

Parentheses can be nested as many times as necessary. For example: ((@#Price - @#Discount) * @%Quantity) * @#TaxRate

Parentheses can be useful when combined with "!" (logical NOT) to take the inverse of a comparison. For example, in the expression !(@%Amount > 1000), if the amount is greater than 1000, then true would be inverted to false by the ! operator.

When in doubt about the precedence, it is a good idea to use parentheses, because it makes the precedence explicit and the code is easier to understand.

Conditions with DynaForm Fields

When a DynaForm is submitted, a case variable is created for each of the fields in the DynaForm. These case variables can then be used later in the process and added in the conditions.

Currency boxes

Available Version: 2.0.x

If the currency box accepts decimal numbers, reference it as @#field_name in the condition. If it doesn't accept decimal numbers, then is can be referenced as an integer @%field_name, but it is a good idea to reference it as a float if doing any division where the remainder might be dropped. Example:

@#Amount + @#Shipping >= 1000.0 or @#Total > @#CreditLimit

Percentage boxes

Available Version: 2.0.x

If the percentage box accepts decimal numbers, reference it as @#field_name in the condition. If it doesn't accept decimal numbers, then is can be referenced as an integer @%field_name, but it is a good idea to reference it as a float if doing any division where the remainder might be dropped. Example:

@#Price + @#Price * @#TaxRate > 0

Dropdown boxes and Radiogroups

Dropdown boxes and radiogroups store the value (not the label) of the selected option. Generally dropdown boxes and radiogroups are accessed as @@field_name, but if the values for the options are integers, they can be accessed as either @@field_name or @%field_name. Due to automatic type conversion, @%var == 2 or @@var == 2 mean the same thing and both would work. Examples:

  @@ContactMethod == 'telephone'
 @@ContactMethod != 'fax'
 @%ExpenseType != 2

To check for the label (not the value) of the selected option in a dropdown box, then check the option Save label of selected value in variable when defining the dropdown box. Then reference it as @@field_name_label. Example:

@@ExpenseType_label != "Taxes"

Listboxes and checkgroups

Available Version: Listboxes 2.0.x

Like dropdown boxes, listboxes and checkgroups store the value (not the label) of the selected option as a string. Unlike dropdown boxes which require one selected option, listboxes and checkgroups allow zero, one, or multiple options to be selected. If more than one option is selected, then each value is separated by a “|” (vertical bar) in a string, such as “blue|yellow|pink” or “0|4|5”.

To deal with situations where more than two options might be selected, it is recommended to break the selected values into an array using the explode() function and then search for a value in the array using the in_array() function.

For instance, to search whether the option "telephone" was selected in the "ContactMethods" listbox:

in_array("telephone", explode('|', @@ContactMethods))

To search whether the option "telephone" was NOT selected, then use ! (Logical NOT):

!in_array("telephone", explode('|', @@ContactMethods))

If the values in a listbox or checkgroup are numbers, use the same method to search for the values as strings:

in_array("3", explode('|', @@ExpenseTypes))

To search for multiple values, then the first parameter of in_array() should be an array of the values to be found:

in_array(array("telephone", "fax", "email"), explode('|', @@ContactMethods))

?Use count() to count the number of selected options. For example, to check whether more than one option was selected:

count(explode('|', @@ContactMethods)) > 1

Yes/No boxes

Available Version: 2.0.x

Yes/No boxes store "1" for Yes and "0" for No. Because 1 means true in PHP and 0 means false, Yes/No boxes can be referenced as just the case variable (without checking for a particular value). All of these conditions would mean exactly the same thing:

 @%mycheckbox
 @%mycheckbox == 1
 @@mycheckbox == "1"

However, do NOT try to use Yes/No boxes in these ways:

 @@mycheckbox
 @=mycheckbox

Yes/No are stored as the strings "0" or "1", so they will always evaluate to true if parsed as strings.

Grids

A grid is stored in a case variable as an array of associative arrays, so it has to be referenced as @=field_name, where it is the field name for the grid object in a master form. The counting of the array starts from the number 1 (not 0 like a normal array). Each row is stored as an associative array where the grid field names are the keys and the entered data are the values. For more information, see Accesing Grids with PHP.

To check how many rows are in a grid, use the count() function. For example, to checking whether the "Products" grid has more than 3 rows:

 count(@=Products) > 3

It is not a good idea to reference a particular grid row in a condition, because an error will be generated if the row doesn't exist. Instead, wrap the condition inside a ternary operator, which first checks whether the row exists.

For example, if checking whether the "Price" field in the first row in the "Products" grid is greater than 100, first check if the row exists with the count() function. Only if it does exist, then check the value of the first "Price" field, otherwise return false.

count(@=Products) >= 1 ? @=Products[1]['Price'] > 100 : false

If unsure whether the grid form was submitted, it is a good idea to first check whether the grid case variable exists with isset(). For example, to check whether the "imported" Yes/No box in the first row of the "Products" grid has selected "Yes" (which has a value of 1):

isset(@=Products) and count(@=Products) >= 1 and @=Products[1][imported] == 1

The condition first checks whether the grid exists, then it checks whether there is at least one row in the grid and finally checks whether the "Yes" option was selected in the Yes/No box (Yes is 1, No is 0).

To check whether any of the "Price" fields in any of the rows is greater than 100, it is recommended to fire a trigger before the condition which would pass through all the rows in the grid and assign a value to a case variable which could be checked in the condition. For example, use the following trigger:

 @=Over100 = false;
 foreach (@=Products as row)
 {
    if (row['Price'] > 100)
       @=Over100 = true;
 }

Then use the following condition:

@=Over100

Setting Conditions

Conditions can be set for a number of different elements in ProcessMaker.

Conditions for Steps

For Version 2.0.x

Conditions can be set for steps, which are activities which happen in order inside a task. To set a condition for a DynaForm, Input Document or Output Document, first assign the activity as a step to a task in a process. Then right click on the task in the process map and select the option Steps from the dropdown menu. In the Steps of: task-name dialog box which appears, click on the Conditions tab to see a list of steps and their conditions.

If a step doesn't have a condition, then it will always be executed when running a case. To add a condition to a step, click on its "Edit" link. Enter the condition in the editing box.

To insert a case or system variable, click on the [@@] button and click on a variable from the list to automatically insert it in the condition. Note that only system variables and case variables from fields used inside master DynaForms will appear in the list to be inserted. Case variables defined in triggers will not appear in the list to be inserted, although they can also be used in conditions.

When done defining the condition, click on the "Save" button.

Conditions for Triggers

Setting a condition for a Trigger is similar to setting one for other types of steps. First, assign the trigger to fire at a particular point in a task. Then right click on the task in the process map and select the "Steps" option from the dropdown menu.

In the Steps of: task-name dialog box which appears, click on the Triggers tab to see a list of points where triggers can be fired. Click on the [+] icons to expand the steps and find the trigger.

If a Trigger doesn't have a condition, then it will always be executed when running a case. To add a condition or edit an existing condition, click on the trigger's Condition link.

When done defining the condition, click on the "Save" button.

Conditions in Evaluation Routing Rules

Evaluation routing rules can use conditions to decide whether to decide the execution of a particular paths in a process.

A condition can be set for each path. If the condition evaluates to True then the next task will be executed. If False then the next task (and any subsequent tasks on the same path) will not be executed. If the condition on a routing rule is left blank, then the condition will be considered True and the next task in the path will be executed.

To add a condition, first join two tasks with an Evaluation or Parallel by Evaluation routing rule. Then, click on the icon for Evaluations or icon for Parallel by Evaluations. In the dialog box that appears, enter the condition for each path.

Make sure that at least one of the conditions will be true, otherwise an error will be thrown and the process will stop at that point.

Errors in Conditions

It can be difficult to debug problems in conditions, so it is recommended to run cases with the Debugger activated. As a case progresses, examine the values of the case and system variables used in the conditions and verify that the conditions are testing for the right values in the variables.

If an error occurs in the syntax of a condition, then an error message will appear to indicate the problem while running cases.

If ProcessMaker encounters a case variable when evaluating a condition, which doesn't exist or hasn't yet been defined in the process, then it gives no indication of the problem. Instead, it inserts a value of "" (an empty string) in place of the variable and evaluates the expression. This kind of problem can be very hard to debug, because the case continues to run without giving any indication of a problem.

If all of the conditions for an Evaluation or Parallel by Evaluation routing rule evaluate to false and there is no available path, then the process stops and the following error message appears:

Fix the conditions so at least one of them will always evaluate to true.

Common Condition Problems

These are some common problems when designing conditions:

  • Misspelled variable names. Remember that variable names are case sensitive and must be spelled exactly as defined (either in the field names in DynaForms or as case variables in Triggers).
  • Using a case variable in a condition before it has been created in the process. Do not use a case variable in a condition, if it is created in a later DynaForm field or defined in a later trigger.
  • Using a case variable in a condition from a DynaForm field whose data may not have been submitted. By default, clicking on the Next Step link in a DynaForm will not save the data, so no case variables will be created for each DynaForm field. To fix this problem, set the Next Step Link property for DynaForms to the "Save & Continue" option, so the data will automatically be saved when the user clicks on the Next Step link. If the user should have the choice to whether to save the DynaForm data or not, then fire a trigger after the DynaForm which will create case variables for each of the fields that are used in subsequent conditions. The trigger code would be:
if (!isset(@@Field1))
    @@Field1 = "";
if (!isset(@@Field2))
    @@Field2 = "";
   
  • When comparing strings, remember to use the same case and the same spacing. "HeLlO" does not equal "hello" and " hello " does not equal "hello" If comparing text entered by the user, it is a good idea to eliminate surrounding spaces with the trim() command and convert all input to either upper or lowercase with strtoupper() or strtolower(). For example:
 trim(strtoupper(@@Department)) == "FINANCE"

If searching within text entered by the user, consider using preg_match(). For example:

preg_match("/finance/i", @@Department)
  • In PHP, = is used for assignment, whereas == or === is used for equality. The condition @%ExpenseType = 3 will always evaluate to true, because the integer 3 can be assigned correctly to the variable. Instead, use the condition @%ExpenseType == 3 to check if @%ExpenseType is equal to the integer 3.