## Overview

ProcessMaker has made a number of its PHP functions available to be used in triggers and conditions. These functions are defined in the file workflow/engine/classes/class.pmFunctions.php. Many of these functions are wrappers for internal class methods used by ProcessMaker or in Gulliver, which is the development framework used by ProcessMaker. To call ProcessMaker's internal functions and classes in triggers and plugins, see Internal Functions and Classes.

The ProcessMaker Functions are generally named PMF...() and are designed to control ProcessMaker from inside a trigger. These functions are executed with the permissions of the currently logged-in user who is running the case. If it is necessary to execute these functions as a different user, use the corresponding WSDL Web Services or REST endpoints.

## Process Functions

### PMFProcessList()

PMFProcessList() returns a list of processes for the current workspace.

array PMFProcessList(void)

Parameters:

None.

Return Value:

An array of associative arrays that contain the unique ID and title of processes. The array has the following structure:

[0] array ( associative array ( [string guid] [string name] ) ) ...

Where:

• string guid: The unique ID for a process.
• string name: The process title.

Example:

@@ArrayProcesses = PMFProcessList();

### PMFGetProcessUidByName()

Available Version: 3.0.1.8 and later.

PMFGetProcessUidByName() retrieves the UID of a Process.

string PMFGetProcessUidByName(string processName)

Parameters:

• string processName: The name of the process.

Return Value:

• With Parameter: returns the unique ID of the process name.
• Without Parameter: returns the unique ID of the current process.

Example without Parameter:

@@UIDProcess = PMFGetProcessUidByName();

Example with Parameter:

@@UIDProcess = PMFGetProcessUidByName("Purchase Process");

PMFTaskList() returns the list of tasks the specified user has initiated.

Parameters:

• string userId: The unique ID of a user.

Return value:

An array of tasks, with the following structure:

[0] array ( associative array ( [string guid] [string name] [string processId] [int initialTask] ) ) ...

Where:

• string guid: The unique ID of a task.
• string name: The name of a task.
• string processId: The unique ID of the process.
• int initialTask: Set to 1 if the task is an initial task. Otherwise, set to 0.

Example:
Get the unique ID of the task whose name is "Verify Data" and place it in the @@taskId variable:

$aTasks = PMFTaskList(@@USER_LOGGED); foreach ($aTasks as $aTask) { if ($aTask['name'] === 'Verify Data')
• string $processUid: Optional. The unique ID of the process. It is only necessary to specify the process if there may be multiple DynaForms with the same name in different processes. The process's unique ID which can be found in the following ways: • Use the @@PROCESS system variable to get the unique ID of the current process. • Use the PMFProcessList() function or processList() web service. • Query the wf_<WORKSPACE>.PROCESS.PRO_UID field in the database or use a query like: SELECT CON_ID FROM CONTENT WHERE CON_CATEGORY='PRO_TITLE' AND CON_VALUE='Purchase Request Form' Return value: • string: The function returns the unique ID of the Dynaform. Example: @@dynUID = PMFGetDynaformUID("Purchase Request Form",'75150592456d5efe4848088021942802'); The returned value stored in @@dynUID will be '81917311556d5f0d0622012054540345'. ### PMFRemoveMask() The PMFRemoveMask() function removes the mask of a currency field by deleting the thousands separator (which is a "." (period) or "," (comma) and the currency symbol, such as "$", "€", "£" or "¥". Call this function before using a currency field in a mathematical calculation that requires a number rather than a string.

string PMFRemoveMask(string fields, string separator = '.', string currency='')

Parameters:

• string field: Value to be stripped of thousands separators and currency symbols.
• string separator: Optional. The thousands separator, which by default is "." (period). In most European and Latin American countries, the thousands separator is "," (comma).
• string currency: Optional. The currency symbol. This parameter is set to an empty string by default, so if the parameter is not set no currency symbol will be removed.

Return Value

A string with the the currency and thousands separator removed.

Note: PMFRemoveMask() returns a string. In most cases this is not a problem, because PHP will automatically convert the string into a number if it is used with a mathematical operator (+, -, *, /, %, etc.) or compared (==, !=, >, >=, < or <=) with a number. Nonetheless, it may be a good idea to convert the string into a real number using the floatval() or into an integer using the intval() functions, in order to avoid potential problems.

Example in a trigger:

Use the PMFRemoveMask() function to delete the mask of a value introduced in a currency field named "Amount". Then use the is_numeric() function to check whether it can be converted into a number. If so, then convert it to a real number and then subtract 10% from the amount for a discount. If not a valid number, then use the G:SendMessageText() function to display a warning message to the user on the next screen:

$amount = PMFRemoveMask(@=Amount, ",", "$");
if (is_numeric($amount) {$amount = floatval($amount); @=Discount =$amount - $amount * 0.10; } else { //if not a valid number, then display warning message G::SendMessageText(@=Amount . " is not a valid amount.", "WARNING"); } For instance, if the value of @=Amount is "$5,000.00", then it will be converted into "5000.00" and floatval() will convert it into 5000.00 (a real number). Notice that the comma (,) and the dollar sign ($) were removed from the string. Note: Case variables that are passed as the first parameter of PMFRemoveMask() should be referenced as @@field-name or @=field-name, so that they are maintained as text. Do NOT use @#field-name or @%field-name, since PHP will try to convert the value to a number, which probably will not work correctly, depending on the mask. Example in a condition: Depending on the value introduced in a field, the following condition is used to decide whether the workflow moves to subsequent task(s): (PMFRemoveMask(@=Amount, ",", "$") >= 100 && (PMFRemoveMask(@=Amount, ".", "$") <= 10000) This condition can be used inside an evaluation routing rule: ### PMFgetLabelOption() PMFgetLabelOption() returns the label of a specified option from a dropdown box, listbox, checkgroup or radiogroup. Available in version 1-2.2467 and later. string PMFgetLabelOption(string processId, string dynaformId, string fieldName, string optionId) Parameters: • string processId: The unique ID of the process that contains the field. To use the current process, use the system variable @@PROCESS. • string dynaformId: The unique ID of the DynaForm where the field is located. • string fieldName: The field name of the dropdown box, checkbox group or radiogroup from the specified DynaForm. • string optionId: The value (i.e., ID) of the option from the fieldName. Return Value: A string holding the label of the specified option or NULL if the specified option does not exist. Example: @@countries_lab = PMFgetLabelOption(@@PROCESS, '6962405664a55ed3b36b168077366134', 'countries', @@countries); Where "6962405664a55ed3b36b168077366134" is the UID of the DynaForm that holds the dropdown box, and "countries" is the name of the field whose values are displayed as options in the dropdown box. "@@countries" is a variable that holds the ID of the option that has been selected in the dropdown box. If just trying to find the label from the selected option in a dropdown box, it is not necessary to use PMFgetLabelOption(). From version 1.2-2552 on, dropdown boxes have a new attribute called "saveLabel". When set to "1", it permits the value of a label for a selected option to be saved automatically in a variable with the same name as the original variable, but with "_label" added to the end of the variable name. For instance, if trying to find the label of the selected option in the "countries" dropdown box, it can be found in the "@@countries_label" variable. ## Case Functions ### PMFCaseList() PMFCaseList() returns a list of the pending cases (i.e., cases that have a status of "To Do" or "Draft") for a specified user. Note that the specified user must be designated to work on the current task for these cases. array PMFCaseList(string userId) Parameters: • string userId: The unique ID of a user who is assigned to work on the cases. Return Value: A list of cases, with the following structure: [0] array ( associative array ( [string guid] [string name] [string status] [int delIndex] ) ) ... Where: • string guid: The unique ID for a case. • string name: The label of a case. • string status: The status of a case. • int delIndex: The current delegation index. Example: @@GRID_CASES = PMFCaseList(); ### PMFTaskCase() PMFTaskCase() returns all the tasks that have open delegations for the specified case. array PMFTaskCase(string caseId) Parameters: • string caseId: The unique ID for a case. Return Value: A list of tasks, with the following structure: [0] array ( associative array ( [string guid] [string name] ) ) ... Where: • string guid: The unique ID of a task. • string name: The name of a task. Example: @@pendingTasksForCase = PMFTaskCase(@@APPLICATION); ### PMFNewCase() PMFNewCase() creates a new case starting in the specified task. variant PMFNewCase(string processId, string userId, string taskId, array variables) Parameters: • string processId: The unique ID of the process, which can be found in the following ways: • Use the @@PROCESS system variable to get the unique ID of the current process. • Use the PMFProcessList() function or processList() web service. • Query the wf_<WORKSPACE>.PROCESS.PRO_UID field in the database or use a query like: SELECT CON_ID FROM CONTENT WHERE CON_CATEGORY='PRO_TITLE' AND CON_VALUE='Expense Report Process' • string userId: The unique ID of the user, which can be found in the following ways: • Use the @@USER_LOGGED system variable for the unique ID of the currently logged-in user. • Use the PMFUserList() function or userList() web service. • Query the wf_<WORKSPACE>.USERS.USR_UID field in the database. • string taskId: The unique ID of the task, which can be found in the following ways: • Use the @@TASK system variable for the unique ID of the current task. • Use the PMFTaskList() function or taskList() web service. • Query the wf_<WORKSPACE>.TASK.TAS_UID field in the database or get the starting task of the current process with the following query: executeQuery("SELECT TAS_UID FROM TASK WHERE PRO_UID='" .@@PROCESS . "' AND TAS_START='TRUE'") • array variables: An associative array of the variables that will be sent to the case. The keys are the variable names and the values are the values of the case variables. If the case variable is a grid, then set the value to an associative array of associative arrays. See Example 3 below. If no variables are needed, then set to an empty array: array() Return Value: If an error occurred, it returns zero. Otherwise, it returns a string with the case UID of the new case. Note: The status of the new case will automatically be set to "DRAFT". To change the status so the new case will appear in the user's Inbox (instead of the Draft box), see Create new case and change its status. Example 1: Create a new case in the current process, designating the current user to work on the new case. The starting task ID is hard coded in the trigger code and no case variables are set in the new case. After creating the new case, call Cases::LoadCase() to find out the new case number and the name of its assigned user. Then, call the G::SendMessageText() function to display a message in the next screen about the new case.$taskId  = '7766592404f358fb90dcdc9043579725'; //set to the starting task's unique ID
$newCaseId = PMFNewCase(@@PROCESS, @@USER_LOGGED,$taskId, array());
//if a new case was created, display a message in the next screen:
if ($newCaseId) {$c = new Cases();
$aCaseInfo =$c->LoadCase($newCaseId, 1);$msg = 'New Case #' . $aCaseInfo['APP_NUMBER'] . ' is assigned to ' .$aCaseInfo["CURRENT_USER"];
G::SendMessageText($msg, 'INFO'); } else {$msg = "Unable to create new case." . isset(@@__ERROR__) ? @@__ERROR__ : '';
G::SendMessageText($msg, 'ERROR'); } Example 2: Look up the ID of a process named "Expense Report Process" and its starting task in the database. Then, call the Derivation::getAllUsersFromAnyTask() method to get an array of the users who are assigned to that starting task. Use the rand() function to randomly choose one to assign to the new case. Set the values of case variables named "Model", "Price" and "OrderDate" in the new case. //Look up the process UID$result = executeQuery("SELECT CON_ID FROM CONTENT WHERE
CON_CATEGORY='PRO_TITLE' AND CON_VALUE='Expense Report Process'"
);
$processId =$result[1]['CON_ID'];

//Look up the UID of the starting task for the process:
$result = executeQuery("SELECT TAS_UID FROM TASK WHERE PRO_UID='$processId' AND TAS_START='TRUE'");
$taskId =$result[1]['TAS_UID'];

//Randomly choose a user from the list of assigned users for the starting task:
$d = new Derivation();$aUsers = $d->getAllUsersFromAnyTask($taskId);
if (count($aUsers) == 0) { throw new Exception("There are no assigned users for task$taskId.");
}
$noUser = rand(0, count($aUsers)-1);
$userId =$aUsers[$noUser]; //Create an associative array of case variables named "Model", "Price" and "OrderDate":$aData = array('Model' => 'Acme Coyote Trap', 'Price' => 29.99, 'OrderDate' => '2010-12-31');

PMFNewCase($processId,$userId, $taskId,$aData);

Example 3:
Start a new case, setting a grid case variable named "clientsGrid" that has the fields "firstName", "lastName" and "telephone" and has 3 rows of data:

$taskId = '7766592404f358fb90dcdc9043579725'; //look up the starting task's unique ID$aGrid = array(
"1" => array("firstName" => "Greg",  "lastName" => "Brown", "telephone" = "471.826-4329"),
"2" => array("firstName" => "Anne",  "lastName" => "Smith", "telephone" = "913.626-9518"),
"3" => array("firstName" => "Sally", "lastName" => "Slim",  "telephone" = "765.652-8608")
);
$newCaseId = PMFNewCase(@@PROCESS, @@USER_LOGGED,$taskId, array("clientsGrid" => $aGrid)); ### PMFNewCaseImpersonate() PMFNewCaseImpersonate() creates a new case. It is similar to PMFNewCase(), but it impersonates the session variables, so it is more robust than PMFNewCase(). int PMFNewCaseImpersonate(string processId, string userId, array variables, string taskId = '') Parameters: • string processId: The unique ID of the process. • string userId: The unique ID of the user. • array variables: An associative array of the variables that will be sent to the case. The array keys are the variable names and the array values are the values of the case variables. See PMFSendVariables() for the format of different variables in ProcessMaker. If no variables are needed, then set to an empty array: array() • string taskId: Optional. Available in version 2.5.1 and later. The unique ID of the task where the case will start. If the process only has one starting task or the user is only assigned to one of the starting tasks, then it is not necessary to specify the task. Return Value: Returns 1 if new case was created successfully; otherwise, returns 0 if an error occurred. Note: The status of the new case will automatically be set to "DRAFT". To change the status so the new case will appear in the user's Inbox (instead of the Draft box), see Create new case and change its status. Note: It is possible to send file variables to new cases, but the files themselves will not be available in the new case. If users working on the new case need to access the files, then either send the files to the new case with the PMFCopyDocumentCase() function or upload the files to the new case using the POST .../services/upload or POST .../cases/{app_uid}/input-document endpoints. Example: The following example creates a new case in the same process and sends variables to the new case. It is possible that the user skipped a DynaForm and a variable was not set in the case, so the isset() function is used to check whether the case variable exists, before using it.$aData = array(
'orderNo'        => 'FL-3478',
'partId'            => isset(@@partOrdered) ? @@partOrdered : '',
'quantity'       => 24
);
PMFNewCaseImpersonate(@@PROCESS, @@USER_LOGGED, $aData); ### PMFPauseCase() PMFPauseCase() pauses a specified case. int PMFPauseCase(string caseUid, int delIndex, string userUid, string unpauseDate=null) Parameters: • string caseUid: The unique ID of the case, which can be found in the following ways: • int delIndex: The delegation index of the current task in the case. For the current case, use the system variable @%INDEX. • string userUid: The unique ID of the user who pauses the case. Note that PMFPauseCase() allows any user to pause any case. The user's unique ID can be found in the following ways: • Get the UID of the currently logged-in user with the @@USER_LOGGED system variable or $_SESSION['USER_LOGGED'].
• Use the PMFUserList() or WSUserList() functions, or the userList() web service.
• Query the wf_<WORKSPACE>.USERS.USR_UID field in the database with executeQuery().
• string unpauseDate: Optional. The datetime in the format "YYYY-MM-DD HH:MM:SS" indicating when the case will be unpaused. If set to NULL or "" (empty string), then the case will be paused indefinitely, until a user manually unpauses it. If the hours, minutes or seconds aren't included in the datetime, then they automatically set to zero. Note that the case will be automatically unpaused on the configured datetime by the cron.php script, so the server needs to periodically execute this script. Ex: "2015-12-31 17:59:59" or "2017-01-08"

Return Value:

Returns 1 if the case is paused successfully; otherwise, returns 0 if an error occurred.

Example:
Pause the current case. Then, call G::header() to redirect the web browser to the Inbox and call die() to stop the case from trying to advance to the next step.

PMFPauseCase(@@APPLICATION, @%INDEX, @@USER_LOGGED, "2016-09-23");
die();

Note: If calling die() in a trigger that executes immediately after a DynaForm, it will prevent the form's data from being saved. Therefore it is recommended to set this trigger to execute before the next step in the task (or before assignment if the last step in the task), so that the form's data will be saved.

### PMFUnpauseCase()

PMFunpauseCase() unpauses a specified case.

int PMFUnpauseCase(string caseUid, string delIndex, string userUid)

Parameters:

• string caseUid: The unique ID of the case, which can be found in the following ways:
• Use the @@APPLICATION system variable to get the unique ID of the current case.
• Use the caseList() web service.
• string delIndex: The delegation index of the current task in the case. For the current case, use the system variable @%INDEX.
• string userUid: The unique ID of the user who will unpause the case, which can be found in the following ways:
• Get the UID of the currently logged-in user with the @@USER_LOGGED system variable or $_SESSION['USER_LOGGED']. • Use the PMFUserList() or WSUserList() functions, or the userList() web service. • Query the wf_<WORKSPACE>.USERS.USR_UID field in the database with executeQuery(). Return Value: Returns 1 if the case is unpaused successfully; otherwise, returns 0 if an error occurred. ### PMFDeleteCase() PMFDeleteCase() deletes a specified case. Note that the case will be deleted completely and it will not appear in the "Participated" tray. To cancel a case use PMFCancelCase() instead of PMFDeleteCase(). int PMFDeleteCase(string caseId) Parameters: • string caseId: The unique ID for a case. For the current case use the system variable @@APPLICATION. Other case UIDs can be found with PMFCaseList(), WSCaseList(), caseList() or by querying the field wf_<WORKSPACE>.APPLICATION.APP_UID. Return value: • Returns 1 if the case was successfully deleted, otherwise returns 0 if an error occurred. Example: @@return = PMFDeleteCase(@@APPLICATION); G::header("Location: casesListExtJsRedirector"); die(); This example uses G::header() with Location: casesListExtJsRedirector to go back to the list of cases (inbox) after deleting the case. ### PMFCancelCase() PMFCancelCase() cancels a specified case. A cancelled case can be reviewed in the "Participated" tray. int PMFCancelCase(string caseUid, string delIndex, string userUid) Parameters: • string caseUid: The unique ID of the case, which can be found in the following ways: • string delIndex: The delegation index of the current task in the case. For the current case, use the @%INDEX system variable. • string userUid: The unique ID of the user who will cancel the case. For the currently logged-in user, use the @@USER_LOGGED system variable. Return value: • Returns 1 if the case was successfully canceled, otherwise returns 0 if an error occurred. Example: The following trigger code cancels the current case and uses the die() function to prevent the next step from being executed: @@return = PMFCancelCase(@@APPLICATION, @%INDEX, @@USER_LOGGED); print "Case cancelled." die; Warning: Take into consideration that until ProcessMaker 3.0.1.8, when using the PMFCancelCase function in parallel tasks, ONLY the thread of the current parallel task will be canceled. The rest of parallel tasks will remain open. i.e. In order for a case to be canceled, the current thread must currently be the unique open thread. ### PMFSendVariables() PMFSendVariables() sends an array of case variables to a specified case. These variables are stored in the wf_<WORKSPACE>.APPLICATION.APP_DATA field and can be displayed by any subsequent DynaForm that has field controls associated with variables of the same name. int PMFSendVariables(string caseId, array variables) Parameters: • string caseId: The unique ID of the case to receive the variable. Note that the case ID changes with each new task in the process. To send variables to the current case, use the system variable @@APPLICATION. • array variables: An associative array to hold the case variables to send to the case. The keys are the case variable names and the values are the values of the case variables. Return Value: Returns 1 if the variables were sent successfully to the case; otherwise, returns 0 if an error occurred. Example 1: Send variables from a subprocess case to its parent case. The executeQuery() function is used to look up the case ID of the parent case in the SUB_APPLICATION table in the database.$caseId = @@APPLICATION;
$aCase = executeQuery("SELECT APP_PARENT FROM SUB_APPLICATION WHERE APP_UID='$caseId'");
if (is_array($aCase) and count($aCase) > 0) {
$aData = array( 'Model' => 'Acme Blender #2', 'Price' => 27.40, 'OrderDate' => '2010-12-31' ); PMFSendVariables($aCase[1]['APP_PARENT'], $aData); } Example 2: This example send variables from the current case (which is a parent case) to all its subprocess cases. It uses the Cases::LoadCase() function to get all the variables for the current case which are stored in the ['APP_DATA'] array key. It then unsets the system variables in the array and sends all those variables to a new case. Note that Cases::LoadCase() gets the case variables which are stored in the database, so this code should not be used in a trigger immediately after a DynaForm, because the variables from the DynaForm have not yet been saved at that point.$caseId = @@APPLICATION;
//get the current case variables:
$c = new Cases();$aCase = $c->LoadCase($caseId, @%INDEX);
$aVars =$aCase['APP_DATA'];
//unset the system variables:
$aSystemVars = array('SYS_SYS', 'SYS_LANG', 'SYS_SKIN', 'PROCESS', 'TASK', 'APPLICATION', 'INDEX', 'APP_NUMBER', 'USER_LOGGED', 'USR_USERNAME', 'PIN'); foreach ($aSystemVars as $var) { unset($aVars[$var]); } //lookup the subprocess cases in the SUB_APPLICATION table:$aSubcases = executeQuery("SELECT APP_UID FROM SUB_APPLICATION WHERE APP_PARENT='$caseId'"); foreach ($aSubcases as $aSubcase) { PMFSendVariables($aSubcase['APP_UID'], $aVars); } Example 3: This example shows how to send all the different types of variables to a different case. Note that it is not necessary to send the label variables (@@variable_label) for textboxes, textareas and hidden controls, because they have the same value as the normal variable (@@variable). Grids don't have a label variable. File controls have a label variable which holds the filename of the uploaded file in a JSON string. In version 3.0.1.18 and later, file controls also have a normal variable which holds the ID for the uploaded file in a JSON string, but this variable is not created if no file is uploaded, so it is necessary to use isset() to check whether the variable exists before trying to pass it to another case. With the file's ID it is possible to look up information about the file using the AppDocument::Load() function or use executeQuery() to do a database search in the APP_DOCUMENT table. However, if users working in the new case need to access the file, then upload the files to the new case using the POST .../services/upload or POST .../cases/{app_uid}/input-document endpoints.$aData = array(
'orderNo'        => 'FL-3478',            //string
'partId'         => @@partOrdered,        //string variable for textbox, textarea, dropdown, suggest, radio or hidden
'quantity'       => 24,                   //integer
'daysToShip'     => @%daysToShip,         //integer variable for textbox, textarea, dropdown, radio or hidden
'taxRate'        => 0.055,                //float (real number)
'price'          => @#partPrice,          //float variable for textbox, textarea, dropdown, radio or hidden

'orderDate'      => '2017-10-30 18:03:50',//datetime in "YYYY-MM-DD HH:MM:SS" format
'orderDate_label'=> 'Oct 10, 2017',       //datetime according to control's format property
'shipDate'       => @@shipDate,           //variable for datetime control
'shipDate_label' => @@shipDate_label,     //label variable for datetime control

'rushOrder'      => array('1'),           //checkbox values set by options. By default: array('1') or array('0')
'rushOrder_label'=> 'true',               //checkbox label set by options. By default: 'true' or 'false'
'shipByAir'      => @=shipByAir,          //variable for checkbox
'shipByAir_label'=> @@shipByAir_label,    //label variable for checkbox

'partType'       => 'engine',             //value of selected option in dropdown,suggest,radio. Values set by options
'partType_label' => 'Engine component',   //label of selected option in dropdown,suggest,radio. Labels set by options
'shipType'       => @@shipType,           //variable for dropdown,suggest,radio (can also be @%variable or @#variable)
'shipType_label' => @@shipType,           //label variable for dropdown,suggest,radio.

'rushOrder'      => array('1'),           //checkbox values set by options property. By default: array('1') or array('0')
'rushOrder_label'=> 'true',               //checkbox labels set by options property. By default: 'true' or 'false'
'shipByAir'      => @=shipByAir,          //variable for checkbox
'shipByAir_label'=> @@shipByAir_label,    //label variable for checkbox

'services'       => array('cleaning','accounting'),  //array of selected options in checkgroup
'services_label' => '["Janitorial","Accounting"]',   //JSON string of selected labels in an array for checkgroup
'classes'        => @=classes,                       //variable for checkgroup
'classes_label'  => @@classes_label                  //label variable for checkgroup

'specFile'       => '["2157955725880e1bb747882058967964"]', //JSON string with ID of AppDocument in an array. Variable only
//created if file selected and only in version 3.0.1.18 and later.
'specFile_label' => '["FL-3478_Specs.pdf"]',                //JSON string with filename in an array
'clientDoc'      => isset(@@clientDoc) ? @@clientDoc : '[]',//variable for file control, not created if no file selected
'clientDoc_label'=> @@clientDoc_label,                      //label variable for file control

'contractFiles'  => array(                                  //multiple file control with array for each selected file
array(
'appDocUid'  => '5027371035880e1a3a0de93013055939',     //ID of AppDocument for selected file
'name'       => 'contract17Mar2014.docx',               //filename of selected file
'version'    => '1'                                     //version number of selected file (always '1')
),
array(
'appDocUid'  => '1478887215880e1a3c07a36097363616',
'name'       => 'contract03Nov2017.odt',
'version'    => '1'
)
),
'receiptFiles'   => @=receiptFiles,                         //variable for multiple file control

'clientsList'    => array(                                  //array of arrays for each row in grid
array(                                                   //first row, keys are the IDs of fields in grid
'company'       => 'Acme, Inc.',                       //textbox
'address'       => "234 Main St.\nPortland, OR 23876", //textarea
'canShip'       => '1',                                //checkbox values of '1' or '0' (not inside array)
'canShip_label' => 'true',                             //checkbox labels of 'true' or 'false' by default
'service'       => 'landscaping',                      //dropdown: selected value
'service_label' => 'Lawn Service',                     //dropdown: selected label
'endDate'       => '2018-06-01 00:00:00',              //datetime in "YYYY-MM-DD HH:MM:SS" format
'endDate_label' => 'June 1, 2018'                      //datetime label
'specFile_label'=> '["AcmeSpecs.pdf"]'                 //file: JSON string of filename in array
//Note that ID of AppDocument for file is not in grid
),
array(                                                   //second row
'company'       => "Serious Eat'n",
'address'       => "275 Oak Av.\nMiami, FL 653420",
'canShip'       => '0',
'canShip_label' => 'false',
'service'       => 'catering',
'service_label' => 'Food Service',
'endDate'       => '2020-12-31 23:59:59',
'endDate_label' => 'December 31, 2020'
'specFile_label'=> '["food_selection.pdf"]'
)
),
//Variables for files in grid in version 3.0.1.18 and later and only created if file is selected in row:
'clientsList_1_specFile'       => '["9652344485880e1bbb826e5060565812"]',//File in row 1
'clientsList_1_specFile_label' => '["AcmeSpecs.pdf"]',                   //Filename in row 1
'clientsList_2_specFile'       => '["2157955725880e1bb747882058967964"]',//File in row 2
'clientsList_2_specFile_label' => '["food_selection.pdf"]',              //Filename in row 2

'contractsGrid' => @=contractsGrid                         //variable for grid
);
PMFSendVariables('2648391115880de3d598d26021145506', $aData); ### setCaseTrackerCode() setCaseTrackerCode() sets the code and PIN for a case, which are used when an unregistered user logs into the Case Tracker to view the details of a particular case. By default, the code for a case is its case number and its PIN (public identification number) is a semirandom string of 4 characters (numbers and letters) autogenerated by ProcessMaker; however,setCaseTrackerCode() can set the case code and PIN to any desired values. int setCaseTrackerCode(string caseId, string code, string pin) Parameters: • string caseId: The unique ID for a case. For the current case use the system variable @@APPLICATION. Other case UIDs can be found with PMFCaseList(), WSCaseList(), caseList() or by querying the field wf_<WORKSPACE>.APPLICATION.APP_UID. • string code: The new code for a case, which will be stored in the field wf_<WORKSPACE>.APPLICATION.APP_PROC_CODE. • string pin: The new code for a case, which will be stored in the field wf_<WORKSPACE>.APPLICATION.APP_PIN as MD5 hash and will be available in the system variable @@PIN for the current case. Return Value: If successful, returns one; otherwise zero or an error number. Example: setCaseTrackerCode(@@APPLICATION, '999', generateCode(4, 'ALPHANUMERIC')); ## Case Routing Functions ### PMFDerivateCase() Warning: Please, take into consideration that this function is NOT supported in ProcessMaker Mobile. It will be available in future versions. PMFDerivateCase() routes a case to the next task in the process. int PMFDerivateCase(string caseId, int delegation, boolean executeTriggersBeforeAssigment=false) Parameters: • string caseId: The unique ID of the case to be routed, which can be found with PMFCaseList() or by querying the field wf_<WORKSPACE>.APPLICATION.APP_UID. The case UID of the current case is stored in the system variable @@APPLICATION. • int delegation: The delegation index of the task to be routed. The delegation index of the current case is stored in the system variable @%INDEX. Note that the delegation index changes with each new task in the case, so look up the index before calling this function. • boolean executeTriggersBeforeAssigment: Optional parameter. By default, it is set to false. If set to true, any triggers that are set to be fired before the case is assigned to the next user will be fired before routing the case. It is not recommended to set the value as true, because the function will generate an infinite loop. On the other hand, if this value is set as false the trigger will be executed before assignment . Return Value: Returns 1 if the new case was routed successfully; otherwise, returns 0 if an error occurred. Note 1: If this function is called for the current task when running a case, then the case will be routed twice--once by PMFDerivateCase() and the second time by the interface running the case. To work around this problem, call the die() function after PMFDerivateCase() to stop the processing and prevent the second derivation (routing). However, if die() is called after a DynaForm step, then it will stop the DynaForm data from getting committed to the database. In this case, use PMFSendVariables() to save the data to the database before calling PMFDerivateCase and die(). See the example below. Note 2: This function only works if the currently logged in user is assigned to the task indicated by the delegation parameter. If it is necessary to route a task that is assigned to another user, login as that user with web services and use routeCase() instead of PMFDerivateCase(). See this code example for routing past the next task in the current case. Note 3: The PMFDerivateCase() function can only route tasks that exist in the wf_<WORKSPACE>.APP_DELEGATION table and whose status is 'OPEN'. In other words, this function can't be called on past tasks that are already closed and future tasks that don't yet exist. To route the next task in the case, which doesn't yet exist, see Skipping the Next Task in a Case. Example 1: Route the current case to the next task in the process and redirect the web browser back to Home > Inbox to see the cases list: PMFDerivateCase(@@APPLICATION, @%INDEX); G::header("Location: casesListExtJsRedirector"); die(); Example 2: To route to a case immediately after a DynaForm step, the data from the DynaForm variables needs to be stored in the database with PMFSendVariables() before calling die(). For example, the DynaForm contains the variables "firstName", "lastName", "address" and "telephone", which need to be saved.$aVars = array(
"firstName" => @@firstName,
"lastName"  => @@lastName,
"telephone" => @@telephone
);
PMFSendVariables(@@APPLICATION, $aVars); PMFDerivateCase(@@APPLICATION, @%INDEX); G::header("Location: casesListExtJsRedirector"); die(); Note: If the trigger is set before the next step (or before assignment if the last step in the task), then it is not necessary to call PMFSendVariables() because the variables from the DynaForm will have already been saved to the database. Example 3: To avoid having to click on the Continue button at the end of a task, create the following trigger, which is set before assignment: PMFDerivateCase(@@APPLICATION, @%INDEX); If the next task is assigned to the same user as the current task, then it can be opened directly without going to the Inbox. Create the following trigger and set it to execute after routing:$caseId = @@APPLICATION;
$nextIndex = @%INDEX + 1; G::header("Location:cases_Open?APP_UID=$caseId&DEL_INDEX=$nextIndex&action=draft"); die(); ### jumping() jumping() routes a case to the next task in the process (or terminates the case if the last task in the process) and then displays the case list. void jumping(string caseId, int delegation) Parameters: • string caseId: The unique ID for the case to be routed. For the current case, use the system variable @@APPLICATION. For other cases, use PMFCaseList() to obtain the case UID or do a database query to look up the case's unique ID in the field wf_<WORKSPACE>.APPLICATION.APP_UID. Note that the case's UID changes with each new task. • int delegation: The delegation index of the task to be routed. Counting starts from 1. For the current case, use the system variable @%INDEX. For other cases, use PMFCase() to obtain the delegation index or do a database search in the field wf_<WORKSPACE>.APP_DELEGATION.DEL_INDEX. Return Value: None. Example: jumping(@@APPLICATION, @%INDEX); ### PMFRedirectToStep() PMFRedirectToStep() redirects a case to any step in the current task. In order for the step to be executed, the specified step must exist and if it contains a condition, it must evaluate to true. Any pending variables in the case will be saved before redirecting and any triggers set to execute before the step will by executed before showing the step. Note that any trigger code after PMFRedirectToStep() is called will not be executed, so it should be used as the last command in the trigger code. void PMFRedirectToStep(string caseId, int indexDelegation, string stepType, string stepUidObject) Parameters: • string CaseId: The unique ID of a case. For the current case, use the system variable @@APPLICATION. For other cases, look up it up using the PMFCaseList() function or by doing a database query for the field wf_<WORKSPACE>.APPLICATION.APP_UID. • int delegation: The delegation index of a case. For the current case, use the system variable @%INDEX. • string stepType: The type of step, which can be 'DYNAFORM', 'INPUT_DOCUMENT', 'OUTPUT_DOCUMENT', or 'EXTERNAL'. • string stepUidObject: The unique ID of the object (e.g. DynaForm, Input Document, Output Document, etc.) in the step. This unique ID can be found by looking up the wf_<WORKSPACE>.STEP.STEP_UID_OBJ field in the database. Return Value: None. Warning: The PMFRedirectToStep function is not supported in the Mobile Version of Processmaker. Instead, use the G::header() function for the same purpose, but make sure to save any case variables with PMFSendVariables() if redirecting in a trigger after a DynaForm. Example: In the following code, the unique ID of the third step object is obtained with the executeQuery function after redirecting the task directly to the 3rd step with the PMFRedirectToStep() function:$taskId = @@TASK; //get ID for current task
$result = executeQuery("SELECT STEP_UID_OBJ FROM STEP WHERE TAS_UID='$taskId' and STEP_POSITION = 3");
@@stepUidObj= $result[1]['STEP_UID_OBJ']; PMFRedirectToStep(@@APPLICATION, @%INDEX, 'DYNAFORM', @@stepUidObj); ### PMFGetNextAssignedUser() PMFGetNextAssignedUser() returns an array of information about the user designated (i.e., chosen out of the assignment pool) to work on the next task for a specified case. array PMFGetNextAssignedUser(string$application, string $task, int$delIndex = null, string $userUid = null) Parameters: • string$application: The unique ID for a case. For the current case, use the system variable @@APPLICATION. For other cases, use the PMFCaseList() function or caseList() web service. Alternatively, query the wf_<WORKSPACE>.APPLICATION.APP_UID or wf_<WORKSPACE>.APP_DELEGATION.APP_UID fields in the database
• string $task: The unique ID for the task, which can be found by right clicking on the task in the process map and selecting Properties in the context menu. It can also be found with the taskList() web service or by querying the wf_<WORKSPACE>.TASK.TAS_UID field in the database. • int$delIndex: Optional. The delegation index for the current task in the case. It is only necessary to set this parameter if calling this function in a script task or if not calling this function for the current case.
• string $userUid: Optional. The unique ID for the user assigned to the case. It is only necessary to set this parameter if calling this function in a script task or if not calling this function for the current case. Return Value: An associative array of information about the user to be designated to work on the next task in the specified case, with the following elements: • string 'USR_UID': The unique ID of the next assigned user. • string 'USR_USERNAME': The username of the next assigned user. • string 'USR_FIRSTNAME': The first name of the next assigned user. • string 'USR_LASTNAME': The last name of the next assigned user. • string 'USR_EMAIL': The email address of the next assigned user. Warning: This function only works reliably if called in certain circumstances; otherwise, it is recommended to get the next designated user by querying the wf_<WORKSPACE>.APP_DELEGATION.USR_UID field in the database in a trigger fired after routing. See this email example and this routing example. This function should only be used when the next task in the process has cyclical assignment, since this function checks who was the last user designated to work on the next task (which is stored in the wf_<WORKSPACE>.TASK.TAS_LAST_ASSIGNED field in the database) and then returns the next user in the list. That next user will be assigned to the next case that routes to the task, however, the next case may not be the case specified by the $application parameter. Therefore, it is recommended to use this function in processes which do NOT have multiple cases being executed at the same time. If the process might execute multiple simultaneous cases, then only call this function in a trigger that fires before assignment.

Note: If this function is not called for the next task in the specified case, meaning that the $task is not the next task in the case, then the following error message will be displayed: Fatal error: Call to a member function getTasUid() on null in /opt/processmaker/workflow/engine/classes/class.case.php on line 2351 Example 1: Send an email to the designated user for the next task in the current case, warning him/her about an upcoming case to work on. Send the first and last names of the next user as the variables @#firstname and @#lastname to insert in the email template:$taskId = '1220028735824ce9181a724086456364'; //set to task ID
$aUser = PMFGetNextAssignedUser(@@APPLICATION,$taskId);
$aVars = array('firstname'=>$aUser['USR_FIRSTNAME'], 'lastname'=>$aUser['USR_LASTNAME']); PMFSendMessage(@@APPLICATION, 'boss@example.com',$aUser['USR_EMAIL'], '', '',
'Upcoming case to work on', 'upcomingCase.html', $aVars); Example 2: In a script task, send out an email to the designated user for the next task in the current case, warning him/her about an upcoming case to work on. Because it is a script task, it is necessary to set the delegation index for the current task and the UID of the user. Because the @%INDEX in script tasks is stuck in the number from the last normal task, 1 needs to be added to get the index for the current task.$taskId = '1220028735824ce9181a724086456364'; //set to task ID
$aUser = PMFGetNextAssignedUser(@@APPLICATION,$taskId, @%INDEX + 1, @@USER_LOGGED);
PMFSendMessage(@@APPLICATION, 'boss@example.com', $aUser['USR_EMAIL'], '', '', 'Upcoming case to work on', 'upcomingCase.html', array()); ### PMFGetNextDerivationInfo() Available Version: 3.0.1.8 and later. PMFGetNextDerivationInfo() retrieves the Uid value, type of assignment of each task involved in the next routing and the UID values of Users and Groups assigned to each one of these tasks. The function evaluates what the subsequent tasks will be based on the current case status. • In case of a Gateway, the function evaluates the gateway conditions and the next task or tasks are returned. If these conditions are changed, then the function must be executed again to get the updated list of the next tasks. • In case of a Valued Based Assignment of users, the variable is evaluated to define the next users. • And in case of parallel tasks, an array of all subsequent tasks is returned. array PMFGetNextDerivationInfo(string caseUid, string delIndex) Parameters: • string caseUid: The unique ID of the case, which can be found in the following ways: • string delIndex: The delegation index of the current task in the case. For the current case, use the system variable @%INDEX. Return Value: An array of associative arrays. Each one of these arrays contains the taskId, type of assignment, users and groups assigned to each one of the subsequent tasks of the routing. The array has the following structure: [0] array ( associative array ( [TaskUid1] => value [assignmentType] => string [Users] => array [userUid1] => value [userUid2] => value [userUid3] => value ... [Groups] => array [groupUid1] => value [groupUid2] => value [groupUid3] => value ... ) ) [1] array ( associative array ( [TaskUid1] => value [assignmentType] => string [Users] => array [userUid1] => value [userUid2] => value [userUid3] => value ... [Groups] => array [groupUid1] => value [groupUid2] => value [groupUid3] => value ... ) ... Example: @@nextderivationinfo = PMFGetNextDerivationInfo(@@APPLICATION, @%INDEX); The variable @@nextderivationinfo obtains Uid values of users and groups and the type of assignment of each task belonging to the next derivation of the current case. The return value will show: Array ( [0] => Array ( [taskUid] => 1513061525703ed80a852e4097938551 [assignmentType] => REPORT_TO [users] => Array ( [0] => 5764160155703df3d460413079972555 ) [groups] => Array ( ) ) [1] => Array ( [taskUid] => 7843933105703ed59af8bf7030860154 [assignmentType] => BALANCED [users] => Array ( [0] => 5764160155703df3d460413079972555 [1] => 3594665525703ee153f20c8004440048 ) [groups] => Array ( [0] => 4433898925703eddbbac7d5066664808 [1] => 7599792485703edeced1af8096618293 ) ) [2] => Array ( [taskUid] => 4588928225703ed5a56af22075961026 [assignmentType] => MANUAL [users] => Array ( [0] => 00000000000000000000000000000001 [1] => 1475524905703ee63396449071456336 ) [groups] => Array ( [0] => 4411010745703ede31505a5086018309 ) ) ) ## Case Notes Functions ### PMFAddCaseNote() PMFAddCaseNote() adds a case note to a specified case. int PMFAddCaseNote(string$caseUid, string $processUid, string$taskUid, string $userUid, string$note, int $sendMail = 1) Parameters: • string caseUid: The unique ID of the case, which can be found in the following ways: • string processId: The unique ID of the process, which can be found in the following ways: • For the current process, use the @@PROCESS system variable. • Use executeQuery() to look up the unique ID in the wf_<WORKSPACE>.PROCESS.PRO_UID field. • string taskId: The unique ID of the task, which can be found in the following ways: • Use the @@TASK system variable for the unique ID of the current task. • Use the PMFTaskList() function or taskList() web service. • Query the wf_<WORKSPACE>.TASK.TAS_UID field in the database or get the starting task of the current process with the following query: executeQuery("SELECT TAS_UID FROM TASK WHERE PRO_UID='" . @@PROCESS . "' AND TAS_START='TRUE'") • $userUid: Optional. Provide the unique ID of a user to return all case notes related to that specific user. If set to null or "" (empty string), then the case notes for all users will be returned. Note that the case notes created in the current task will not be included and it is not possible to include the UID of more than one user.
• $note: Note of the case. • $sendMail: Optional parameter. If set to 1, will send an email to all participants in the case.

Return Value:
Returns 1 if the note has been successfully added to the case, otherwise returns 0 if an error has occurred.

Example:

Note: It is possible to use case or system variables in the text of the case note. The following example inserts the resolution number, which is a value from a DynaForm field in the text of the case note:

@@return = PMFAddCaseNote(@@APPLICATION, @@PROCESS, @@TASK, @@USER_LOGGED, 'Completed with resolution #' . @@NumberResolution, 1);

### PMFGetCaseNotes()

PMFGetCaseNotes() returns a list of the case notes posted for a specified case.

array PMFGetCaseNotes(string $applicationID, string$type = 'array', string $userUid = '') Parameters: • string$application: The unique ID for a case, which can be obtained in the following ways:
• For the current case, use the system variable @@APPLICATION.
• Use PMFCaseList(), WSCaseList() or the caseList() web service.
• Use executeQuery() to query the wf_<WORKSPACE>.APPLICATION.APP_UID or wf_<WORKSPACE>.APP_DELEGATION.APP_UID fields in the database
• string $type: Optional parameter. Set to 'array' if the result will be displayed in a grid. Set to 'string' to return a string, which can be displayed in a textarea field. The default value is 'array'. • string$userUid: Optional parameter. To return the case notes posted by a single user, set to the unique ID of that user. If no user ID is specified, then it will return the case notes from all users. For the currently logged-in user, use the @@USER_LOGGED system variable.

Note: It's not possible to define more than one user ID on the last parameter.

Return Value:
If the $type is set to 'array', then this function returns an array of associative arrays with the following structure: [1] array ( string ['FULL_NAME']: First name and last name of the user who created the case note. string ['APP_UID']: Case UID. string ['USR_UID']: User UID. string ['NOTE_DATE']: The datetime when the case note was created in YYYY-MM-DD HH:MM:SS format. string ['NOTE_CONTENT']: The content of the case note. string ['NOTE_TYPE']: The type of the case note. string ['NOTE_AVAILABILITY']: The type of availability of the case note. string ['NOTE_RECIPIENTS']: The users who got the note by notification. string ['USR_USERNAME']: The username of the user who created the case note. ) ... Note that the counting of the array starts from 1, not 0. If the $type is set to 'string', then this function returns a string that includes the name and username of the user who posted the case note, the content of the case note, and the date-time when posted:

#### Showing Case Notes in a Grid

Create a DynaForm and inside it add a grid. When dropping the Grid Element, create a new variable gridPMFunction associated to the grid.

Add the following controls inside the grid:

• A Textbox with id: FULL_NAME.
• A Textbox with id: USR_USERNAME.
• A Textarea with id: NOTE_CONTENT
• A Datetime control with id: NOTE_DATE

Save the changes and close the DynaForm. Then, create a trigger with the following parameters:

@@gridPMFunction = PMFGetCaseNotes(@@APPLICATION, 'array', '');

Where:

• @@gridPMFunction: is the name of the grid added inside the DynaForm and where results will be shown.
• @@APPLICATION: UID of the current process.
• array: results to show, in the case of the example, results will be shown in a grid.

Note that the last parameter is empty so it will display case notes of all users who have created one.

Assign the trigger before the DynaForm created and the results will be as seen in the image below:

In this example, the trigger was assigned in the second task, so all case notes added in both the first task and the second task will be displayed on the grid.

#### Showing Case Notes in a TextBox

Create a Dynaform that has a Textarea control with a variable called textAreaPMFunction.

Then create a trigger as follows:

@@textAreaPMFunction = PMFGetCaseNotes(@@APPLICATION, 'string', '');

Where:

• @@textAreaPMFuntion : name of the textarea added in the DynaForm and where results will be shown.
• @@APPLICATION: UID of the current process.
• string: results to show, in the case of the example they will be shown in a textarea.

The last parameter is empty, so it will display all the case notes created by the users.

Assign the trigger before the DynaForm, the result will be:

## User Functions

### PMFUserList()

PMFUserList() returns a list of users whose status is set to "ACTIVE" for the current workspace.

array PMFUserList(void)

Parameters:

None.

Return Value:

An array of users, with the following structure:

[0] array ( associative array ( [string guid] [string name] ) ) ...

Where:

• string guid: The unique ID of a user.
• string name: The username of a user.

Example:

@@GRID_USERS = PMFUserList();

### PMFInformationUser()

PMFInformationUser() retrieves information about a specified user.

array PMFInformationUser(string $userUid) Parameters: • string USER_ID: The user's unique ID, which can be found in the following ways: Return Value: An associative array with the following keys:  array( 'username', The username, which must be unique. 'firstname', The user's first name (maximum of 50 characters). 'lastname', The user's last name (maximum of 50 characters). 'mail', The user's email address (maximum of 100 characters). 'address', The user's address (maximum of 255 characters). 'zipcode', The user's zip or postal code (maximum of 16 characters). 'country', The user's country. 'state', The user's state, province or region. 'location', The user's location. 'phone', The user's phone number (maximum of 24 characters). 'cellular', The user's cellular phone number (maximum of 24 characters). 'birthday', The user's birthday in "YYYY-MM-DD" format. Ex: "1970-11-24" 'position', The user's position. 'replacedby', The unique ID of the user who will replace the user, when his/her status changes to INACTIVE or VACATION. Use the PMFInformationUser() function a second time to get his/her name. 'duedate', Date when the user account will expire in 'YYYY-MM-DD' format. Ex: "2020-12-31" 'status', The user's status, which can be: ACTIVE, INACTIVE or VACATION. 'department', The unique ID of the department. To get the name of the department, use a database query in the CONTENTS table where: CON_ID='' AND CON_CATEGORY='DEPO_TITLE' 'reportsto', The unique ID of the user's supervisor in the department. Use the PMFInformationUser() function a second time to get his/her name. 'userexperience', The User Experience setting, which can be: NORMAL, SINGLE (for a single application), SIMPLIFIED (for mobile interfaces), or SWITCHABLE (to be able to change between the normal and the simplified interfaces). 'photo' The path where the user's photo file is stored in the ProcessMaker server at: /shared/sites//usersPhotographies/.gif For example: /opt/processmaker/shared/sites/workflow/usersPhotographies/9108004215481b57a6e38b3002299563.gif The URL to access the user's photo would be: http:///sys//users/users_ViewPhotoGrid?pUID= For example: http://example.com/sysworkflow/en/neoclassic/users/users_ViewPhotoGrid?pUID=9108004215481b57a6e38b3002299563 Note: The extension of the photo file is always renamed as .gif, even if the file is JPEG or PNG, which can cause problems displaying the image in some web browsers because the file extension doesn't match the file type. To figure out the type of image file, the finfo_file() function can be used to check whether the MIME file type is "image/png", "image/jpeg" or "image/gif". ) For example: array( "username" => "Eve", "firstname" => "Jones", "lastname" => "ejones", "mail" => "eve@example.com", "address" => "235 W. Oak Av.", "zipcode" => "81643", "country" => "United States", "state" => "Florida", "location" => "Miami Lakes", "phone" => "1-317-453-8776", "fax" => "1-305-402-0282", "cellular" => "1-305-675-1400", "birthday" => "1980-02-25", "position" => "Accountant", "replacedby" => "22515138055fc47dcf0d786050067981", "replacedbyfullname"=> "Bob Smith", "duedate" => "2020-01-01", "calendar" => "16215376855fc5e051e7499057282210" "calendarname" => "Florida Calendar" "status" => "ACTIVE", "department" => "79557529255fc48a94665a1003191338", "departmentname" => "Accounting", "reportsto" => "14944204555fc4860983227093956871", "userexperience" => "NORMAL", "photo" => "/opt/pm3.1/shared/sites/workflow/usersPhotographies/63431366054f5d20ec91ce1029282852.gif" ) Example getting a phone number: Look up the phone number of the currently logged-in user and assign it to a case variable named @@Phone, which will be displayed in a subsequent DynaForm field:$aUser = PMFInformationUser(@@USER_LOGGED);
@@Phone = $aUser['phone']; Example getting an address: Look up the address of a user whose username is "jdoe" and assign it to the @@Address variable, which will be displayed in a textarea associated with that variable in a subsequent DynaForm. The address is a US style address.$username = 'jdoe';
$result = executeQuery("SELECT USR_UID FROM USERS WHERE USR_USERNAME='$username' ");
if (is_array($result) and count($result) > 0) {
$aUser = PMFInformationUser($result[1]['USR_UID'] );
@@Address = $aUser['address'] . (empty($aUser['location']) ? '' : "\n" . $aUser['location'] .', '.$aUser['state'] .' '. $aUser['zipcode']) . ($aUser['country'] == 'United States' or empty($aUser['country']) ? '' :$aUser['country']);
}

Example showing user information in a grid:

Create a DynaForm with a grid. When dropping the Grid Element, create a new variable userInformation associated to the grid.

Add the following controls inside the grid:

• A Textbox with id: username.
• A Textbox with id: firstname.
• A Textbox with id: lastname.
• A Textbox with id: mail.
• A Textbox with id: address.
• A Textbox with id: zipcode.

Save the changes and close the DynaForm. Then, create a trigger with the following parameters:

@@userInformation = array();
@@userInformation[1] = PMFInformationUser('50125991157c071f6d684f8088171283');

Where:

• @@userInformation[1]: Name of the grid where information will be displayed. Moreover, the grid name is defined as [1] because the return value is a grid and it has to start on 1 to display information in the corresponding fields.

Set the above trigger to fire before the DynaForm. While running a case, the user's information will be displayed in the grid:

Also, this function can be created by using the Trigger Wizard:

Example showing a group of users in a grid:

This example shows a grid in a DynaForm which lists information about the users in a group named Managers.

First, create a DynaForm with a grid. When dropping the Grid Element, create a new variable listGroup associated to the grid.

Add the following controls inside the grid:

• A Textbox with id: username.
• A Textbox with id: firstname.
• A Textbox with id: lastname.
• A Textbox with id: mail.
• A Textbox with id: address.
• A Textbox with id: zipcode.

After that, create the following trigger, which will use the executeQuery() function to look up the members of the group named Managers. It then loops through the list of users and looks up information about each user, then adds it to an array named "ListGroup", which will be displayed in the grid. Remember that grids are stored as an associative array of associative arrays, where the outer array is numbered, starting from 1 for each row in the array and the keys in the inner array are the fields in the grid:

$query = "select U.USR_UID from CONTENT C, GROUP_USER GU, USERS U where C.CON_CATEGORY='GRP_TITLE' and C.CON_VALUE='Managers' and C.CON_ID=GU.GRP_UID and GU.USR_UID=U.USR_UID and U.USR_STATUS='ACTIVE'" ;$aUsers = executeQuery($query); if (is_array($aUsers) and count($aUsers) > 0) { for ($i = 1; $i <= count($aUsers); $i++) { @@listGroup[$i] = PMFInformationUser($aUsers[$i]['USR_UID']);
}
}

While running a case, the information of the managers group members will be displayed in the grid:

Example looking up information about the Supervisor:

The following trigger code retrieves information about the current logged-in user and then looks up information about the user's supervisor, whose unique ID is listed in the 'reportsto' key of the array. It also uses the executeQuery() function to look up the name of the department in the CONTENT table. The trigger then uses the G:SendMessageText() function to display a message in the next screen telling the user to contact his/her supervisor:

$aUser = PMFInformationUser(@@USER_LOGGED); if (($aUser['reportsto'])!=NULL) {
$aSuper = PMFInformationUser($aUser['reportsto']);

$aDept = executeQuery("SELECT CON_VALUE FROM CONTENT WHERE CON_ID='{$aSuper['department']}'
AND CON_CATEGORY='DEPO_TITLE'"
);

$msg = "Please contact your supervisor {$aSuper['firstname']} {$aSuper['lastname']} " . "({$aSuper['mail']}) of the {$aDept[1]['CON_VALUE']} Department for authorization of this decision."; G::SendMessageText($msg, "WARNING");
}
else {
G::SendMessageText("You do not have authorization for this decision, ".
"because it needs a supervisor's approval, but you don't have a supervisor.", "ERROR");
}

if ($var == 0) @@text = 'not created'; else @@text = 'created'; ### PMFUpdateUser() PMFUpdateUser() updates a specified user's information. int PMFUpdateUser(string userUid, string userName, string firstName, string lastName, string email, string dueDate, string status, string role, string password) Parameters: • string userId: The unique ID of the user whose information will be updated. • string userName: The username of the user. • string firstname: The first name of the user which can be up to 50 characters long. • string lastname: The last name of the user which can be up to 50 characters long. • string email: The email of the user, which can be up to 100 characters long. • string dueDate: The expiration date which must be a string in the format "YYYY-MM-DD" • string status: The user's status, such as 'ACTIVE', 'INACTIVE' or 'VACATION'. • string role: The role of the user, such as 'PROCESSMAKER_ADMIN', 'PROCESSMAKER_OPERATOR' or 'PROCESSMAKER_MANAGER'. • string password: The password of the user, which can be up to 32 characters long. For more information, see Customizing Authentication. Note: All fields must be filled. Return Value: • Returns 1 if the user has been successfully updated; otherwise, returns 0 if an error occurred. Example: @@return = PMFUpdateUser(@@USER_LOGGED, 'jdoe', 'John', 'Doe', 'jdoe@example.com', '2020-12-31', 'ACTIVE', 'PROCESSMAKER_OPERATOR', 'p4ssw0rd'); ### PMFRoleList() PMFRoleList() returns a list of all the roles in the current workspace. array PMFRoleList(void) Parameters: • None. Return Value: • This function returns an array of roles, with the following structure: [0] array ( associative array ( [string guid] [string name] ) ) ... Where: • string guid: The unique ID of a role. • string name: The name of a role. Example:$GridRoles = PMFRoleList();

//Counting in the array starts from 1
@@RoleName = $GRID_ROLES[1]['name']; ## Group Functions ### PMFGroupList() PMFGroupList() returns a list of groups in the current workspace. array PMFGroupList(void) Parameters: None. Return Value: An array of groups, with the following structure: [0] array ( associative array ( [string guid] [string name] ) ) ... Where: • string guid: The unique ID of a group. • string name: The name of a group. ### PMFGetGroupUID() Available Version: 3.0.1.8 and later. PMFGetGroupUID() retrieves the unique ID of a Group according to the group name. string PMFGetGroupUID(string groupName) Parameters: • string groupName: The name of the group. Return value: • string: The function returns the unique ID of the group. Example: @@groupUID = PMFGetGroupUID("Employees"); The returned value stored in @@groupUID will be '17937032156da2acd670ae7095412095'. ### PMFGetGroupName() Available Version: 3.0.1.8 and later. PMFGetGroupName() retrieves the Name of a Group according to the unique ID of the group and given language. string PMFGetGroupName(string groupId, string Language) Parameters: • string groupId: The unique ID of the group, which can be found in the following ways: • string Language: Optional parameter. The language in which the group name will be retrieved. If not specified then the default system language is used. Note: Please take into account that returned values directly depend on the current data stored in the wf_<WORKSPACE>.CONTENT table, and more specifically records related to group titles (CON_CATEGORY = GRP_TITLE. Return value: • string: The function returns the name of the group. Example: @@groupName = PMFGetGroupName(@@GROUP,'es'); The returned value stored in @@groupName will be "Empleados". ### PMFGetGroupUsers() Available Version: 3.0.1.8 and later. PMFGetGroupUsers() retrieves the users who are part of a Group. array PMFGetGroupUsers(string GroupUID) Parameters: • string$GroupUID: The unique ID of a group, which can be found in the following ways:
• Use the PMFGroupList() or WSGroupList() functions or the groupList() web service.
• Query the wf_<WORKSPACE>.GROUPWF.GRP_UID field in the database.
• Use the query:
SELECT CON_VALUE, CON_ID FROM CONTENT WHERE CON_CATEGORY='GRP_TITLE'

Return Value:

An array of associative arrays, each one of these arrays contains information about each user included in the group. The array has the following structure:

[0] array ( associative array ( [property1] => value [property2] => value [property3] => value ... ) ) [1] array ( associative array ( [property1] => value [property2] => value [property3] => value ... ) ...

Example:

@@UsersList = PMFGetGroupUsers("8511196744b6380deb57b69039061394");

The variable @@UsersList will obtain all the information about the users of the group. The return value will show:

Array ( [0] => Array ( [USR_UID] => 41648276456d8a8acd76857021709199 [USR_USERNAME] => daniela [USR_PASSWORD] => aa41ab4c932bdcc5246171e3a0aed710 [USR_FIRSTNAME] => Daniela [USR_LASTNAME] => Martinez [USR_EMAIL] => email@engineer.com [USR_DUE_DATE] => 2017-03-03 [USR_CREATE_DATE] => 2016-03-03 21:12:12 [USR_UPDATE_DATE] => 2016-03-03 21:12:12 [USR_STATUS] => ACTIVE [USR_COUNTRY] => BO [USR_CITY] => L [USR_LOCATION] => LPB [USR_ADDRESS] => [USR_PHONE] => [ [USR_FAX] => [USR_CELLULAR] => [USR_ZIP_CODE] => 2254 [DEP_UID] => 77449242256d8a8dbe3fa03081252723 [USR_POSITION] => [USR_RESUME] => [USR_BIRTHDAY] => 2016-03-03 [USR_ROLE] => PROCESSMAKER_ADMIN [USR_REPORTS_TO] => 41648276456d8a8acd76857021709199 [USR_REPLACED_BY] => 00000000000000000000000000000001 [USR_UX] => NORMAL [USR_TOTAL_INBOX] => 5 [USR_TOTAL_DRAFT] => 1 [USR_TOTAL_CANCELLED] => 0 [USR_TOTAL_PARTICIPATED] => 6 [USR_TOTAL_PAUSED] => 0 [USR_TOTAL_COMPLETED] => 0 [USR_TOTAL_UNASSIGNED] => 0 [USR_COST_BY_HOUR] => 10.00 [USR_UNIT_COST] => $[USR_PMDRIVE_FOLDER_UID] => [USR_BOOKMARK_START_CASES] => [USR_TIME_ZONE] => America/New_York [USR_DEFAULT_LANG] => en ) [1] => Array ( [USR_UID] => 64057912456ddf2b679e620007773823 [USR_USERNAME] => monica [USR_PASSWORD] => 3250fc092f6026b2cf0333f63644cb6e [USR_FIRSTNAME] => Monica [USR_LASTNAME] => Roddeford [USR_EMAIL] => d.callisaya@hotmail.com [USR_DUE_DATE] => 2017-03-07 [USR_CREATE_DATE] => 2016-01-17 21:29:26 [USR_UPDATE_DATE] => 2016-03-05 11:25:03 [USR_STATUS] => ACTIVE [USR_COUNTRY] => [USR_CITY] => [USR_LOCATION] => [USR_ADDRESS] => [USR_PHONE] => [USR_FAX] => [USR_CELLULAR] => [USR_ZIP_CODE] => [DEP_UID] => [USR_POSITION] => [USR_RESUME] => [USR_BIRTHDAY] => 2016-03-07 [USR_ROLE] => PROCESSMAKER_OPERATOR [USR_REPORTS_TO] => [USR_REPLACED_BY] => [USR_UX] => NORMAL [USR_TOTAL_INBOX] => 35 [USR_TOTAL_DRAFT] => 4 [USR_TOTAL_CANCELLED] => 0 [USR_TOTAL_PARTICIPATED] => 87 [USR_TOTAL_PAUSED] => 5 [USR_TOTAL_COMPLETED] => 10 [USR_TOTAL_UNASSIGNED] => 0 [USR_COST_BY_HOUR] => 580.00 [USR_UNIT_COST] => Euro [USR_PMDRIVE_FOLDER_UID] => [USR_BOOKMARK_START_CASES] => [USR_TIME_ZONE] => America/Anguilla [USR_DEFAULT_LANG] => en ) ) ### PMFAssignUserToGroup() PMFAssignUserToGroup() assigns a user to a group. Note that the logged-in user must have the PM_USERS permission in his/her role to be able to assign a user to a group. int PMFAssignUserToGroup(string userId, string groupId) Parameters: • string userId: The unique ID of the user. • string groupId: The unique ID of the group. Return Value: Returns 1 if the user was successfully assigned to the group; otherwise, returns 0 if an error occurred. Example:$GroupUID = '8511196744b6380deb57b69039061394';
$var = PMFAssignUserToGroup(@@USER_LOGGED,$GroupUID);
if($var == 0) @@text = "It was not assigned"; else @@text = "It was assigned"; Where: • $GroupUID: It is the ID of the employee group.
• @@USER_LOGGED: This is the user logged ID.
• $var: As this function returns 1 if the user was successfully assigned and 0 if not, this variable will store this return value to confirm the assignation. ## Email Functions ### PMFSendMessage() The PMFSendMessage() function sends out customized email notifications using a template. For more information, see Trigger Messages. int PMFSendMessage(string caseId, string from, string to, string cc, string bcc, string subject, string template, array aFields=array(), array aAttachments=array(), boolean showMessage=true, int delIndex=0, array config=array()) Parameters: • string caseId: The UID (unique identification) for a case, which is a string of 32 hexadecimal characters that uniquely identifies each individual case. For the current case use the system variable @@APPLICATION. Other case UIDs can be found with the PMFCaseList() function, the WSCaseList() function, the caseList() web service, or by using the executeQuery() function to query the wf_<WORKSPACE>.APPLICATION.APP_UID field in the database. • string from: The email address of the person who sends out the email. Use the userInfo() function to get a user's email address. If it is necessary to include the person's name along with the email address, list the name first followed by the email address enclosed inside angle brackets < >. The name may be enclosed inside double quotations, but it isn't necessary: 'Liliana Iriarte <liliana@example.com>' or '"Liliana Iriarte" <liliana@example.com>' Note: Due to security restrictions, Yahoo!, gmail and many other email providers will no longer deliver email that doesn't come from the same email address as the account in the Email Configuration at ADMIN > Settings > Email. To avoid this problem, set the email address for the from parameter to the same email address found in the Email Configuration. • string to: The email address(es) to whom the email is sent. If there are multiple recipients, separate each email address with a comma ",". If it is necessary to include the person's name along with the email address, list the name first followed by the email address enclosed inside angle brackets < > as shown above. Use the userInfo() function to get a user's email address. • string cc: The email address(es) of people who will receive carbon copies of the email. If there are multiple recipients, separate each email address with a comma. Use the userInfo() function to get a user's email address. • string bcc: The email address(es) of people who will receive blind carbon copies of the email. Unlike a normal carbon copy, the other recipients won't see who has received blind carbon copies. If there are multiple recipients, separate each email address with a comma. Use the userInfo() function to get a user's email address. • string subject: The subject (title) of the email. • string template: The name of the template file in plain text or HTML format that will produce the body of the email. Include the file extension in the file name. For example: "negativeResponse.html" or "caseStatus.txt" The template file must be located in the mailTemplates directory of the Process Files Manager for the current process (which is stored in the shared/sites/<WORKSPACE>/mailTemplates/<PROCESS-UID>/ directory in the server's file system). The template file can contain system variables, case variables (which weren't defined in the same trigger), or any variables that are passed in the fields parameter. See Notifications for how to insert variables in an email template. • array fields: Optional parameter to define custom variables that can be inserted into the template file. The fields parameter is an associative array where the keys are the variable's name and the values are the variable's value. If no array is included, an empty array is included by default. Case variables defined in the same trigger that calls PMFSendMessage() should be passed to the email template using the fields array. See the example below for how to set the values in the fields array. • array aAttachments: Optional. An array of complete paths for files to attach to the email. The paths can be web addresses or paths in the file system of the server where ProcessMaker is installed. For example: array('/home/foobar/clients/client_03452342.xls', '/var/www/public/profile.pdf', 'http://www.example.com/finances.doc') By default, files are attached using their original file names, which means that Input Documents, Output Documents and attached files are sent with filenames containing their unique ID and version number. In version 2.0.38 and later, it is possible to rename file attachments by setting the new filename as the array key. For example: array( "InvoiceForJohnDoe.xls" => "/home/foobar/clients/client_03452342.xls", "scannedInvoice.png" => PATH_DOCUMENT . G::getPathFromUID(@@APPLICATION) . PATH_SEP . "9743702654e6925b52e1e34098864192_1.png" ) If sending files stored by ProcessMaker, it is recommended to use ProcessMaker's predefined system constants, such as PATH_DATA_PUBLIC, PATH_DATA_MAILTEMPLATES, PATH_DOCUMENT and PATH_SEP, to construct the paths: PATH_DATA_PUBLIC . "<PROCESS-UID>" . PATH_SEP . "<FILENAME>" Example: PATH_DATA_PUBLIC . @@PROCESS . PATH_SEP . "letterheadLogo.png" PATH_DATA_MAILTEMPLATES . "<PROCESS-UID>" . PATH_SEP . "<FILENAME>" Example: PATH_DATA_MAILTEMPLATES . @@PROCESS . PATH_SEP . "companyProfile.html" PATH_DOCUMENT . G::getPathFromUID("<CASE-UID>") . PATH_SEP . "<CASE-DOC-UID>_<VERSION>.<EXTENSION>" Example: PATH_DOCUMENT . G::getPathFromUID(@@APPLICATION) . PATH_SEP . "9743702654e6925b52e1e34098864192_1.png" PATH_DOCUMENT . G::getPathFromUID("<CASE-UID>") . PATH_SEP . "outdocs" . PATH_SEP . "<CASE-DOC-UID>_<VERSION>.<EXTENSION>" Example: PATH_DOCUMENT . G::getPathFromUID(@@APPLICATION) . PATH_SEP . "outdocs" . PATH_SEP . "6960198894e6927e0a40b14004833875_2.pdf" • Files uploaded in the Home > Documents interface, which aren't attached to a case: PATH_DOCUMENT . '00000000000000000000000000000000' . PATH_SEP . G::getPathFromUID("<CASE-DOC-UID>") .'_<VERSION>.<EXTENSION>" Example: PATH_DOCUMENT . '00000000000000000000000000000000' . PATH_SEP . G::getPathFromUID('965821362588279cb660237001025225') . '_1.png' • boolean showMessage: Optional parameter available in version 2.5 and later. If set to true, which is the default, the the email message will be displayed in the message history. If set to false, then the email message will not be displayed in the message history, although a record of the email will still be stored in the APP_MESSAGE table. • int delIndex: Optional parameter available in version 2.5 and later. If not set to 0, the message will be associated with a particular task in the case, which is indicated by its delegation index. The delegation index for the current case is stored in the system variable @%INDEX. Note that the delegation index changes with each new task in the case, so look up the index in the APPLICATION.DEL_INDEX field before calling this function. • array config: Optional parameter available in Enterprise Edition version 2.8 and later to configure an alternative email server to send the message. See Use an alternative email server. Return Value: Returns 1 if email was sent to the configured email server; otherwise, returns 0 if an error occurred. When the trigger should be set to fire The PMFSendMessage() function can be used in triggers set to fire after a DynaForm step. Example Sending Variables to a Template: The following trigger code is used to send an email template named "LeaveRequestTemplate.html" to the user working on the current case. An array of variables is passed to PMFSendMessage(), so the @#reqUserName, @#reqSup, @#fromReq, @#toReq and @#daysReq fields will be filled in the template:$aFields = array('reqUserName' => @=reqUserName, 'reqSup' => @=reqSup,
'fromReq' => @=fromReq, 'toReq' => @=toReq, 'daysReq' => @=daysReq);
$usr = userInfo(@@USER_LOGGED);$to = $usr['mail']; PMFSendMessage(@@APPLICATION, 'manager@acme.com',$to, '', 'ceo@acme.com, cfo@acme.com',
'Leave Request Notification', 'LeaveRequestTemplate.html', $aFields); Example Emailing Attachments from the Process Files Manager: The following trigger sends to two files named "companyLogo.png" and "companyProfile.pdf", which are stored in the "public" directory of the Process Files Manager:$aAttachFiles = array(
PATH_DATA_PUBLIC . @@PROCESS . PATH_SEP . 'companyLogo.png',
PATH_DATA_PUBLIC . @@PROCESS . PATH_SEP . 'companyProfile.pdf'
);
$usr = userInfo(@@USER_LOGGED); PMFSendMessage(@@APPLICATION, 'manager@acme.com',$usr['mail'], '', '',
'Company Information', 'companyInfoTemplate.html', array(), $aAttachFiles); Example Emailing Input Document Files: This trigger emails all the uploaded files for an Input Document whose definition has the ID "8935316924e692b256860c4075654232".$caseId = @@APPLICATION; //Unique ID for the current case
$inDocDef = "8935316924e692b256860c4075654232"; //set to the Input Document definition's unique ID$aAttachFiles = array();

$inDocQuery = "SELECT AD.APP_DOC_UID, AD.DOC_VERSION, C.CON_VALUE AS FILENAME FROM APP_DOCUMENT AD, CONTENT C WHERE AD.APP_UID='$caseId' AND AD.DOC_UID='$inDocDef' AND AD.APP_DOC_STATUS='ACTIVE' AND AD.APP_DOC_UID = C.CON_ID AND C.CON_CATEGORY = 'APP_DOC_FILENAME'" ;$inDocs = executeQuery($inDocQuery); if (is_array($inDocs)) {
foreach ($inDocs as$inDoc) {
$aAttachFiles[$inDoc['FILENAME']] = PATH_DOCUMENT . G::getPathFromUID($caseId) . PATH_SEP .$inDoc['APP_DOC_UID'] . '_' . $inDoc['DOC_VERSION'] . '.' . pathinfo($inDoc['FILENAME'], PATHINFO_EXTENSION);
}
}
$usr = userInfo(@@USER_LOGGED); PMFSendMessage(@@APPLICATION, 'manager@acme.com',$usr['mail'], '', '',
'Client documents', 'clientTemplate.html', array(), $aAttachFiles); Note: This example only emails the latest version of input document files. To email all versions, remove from the query: AND AD.APP_DOC_STATUS='ACTIVE' To email all uploaded files for a case, remove from the query: AND AD.DOC_UID='$inDocDef'

Example Emailing a File Uploaded to a DynaForm's File Field:

This trigger emails all the files uploaded to file fields for the current case:

$aAttachFiles = array();$caseId = @@APPLICATION; //Unique ID for the current case
$docQuery = "SELECT AD.APP_DOC_UID, AD.DOC_VERSION, C.CON_VALUE AS FILENAME FROM APP_DOCUMENT AD, CONTENT C WHERE AD.APP_UID='$caseId' AND AD.APP_DOC_TYPE='ATTACHED' AND AD.APP_DOC_STATUS='ACTIVE' AND
AD.APP_DOC_UID = C.CON_ID AND C.CON_CATEGORY = 'APP_DOC_FILENAME'"
;
$docs = executeQuery($docQuery);
if (is_array($docs)) { foreach ($docs as $doc) {$aAttachFiles[$doc['FILENAME']] = PATH_DOCUMENT . G::getPathFromUID($caseId) . PATH_SEP .
$doc['APP_DOC_UID'] . '_' .$doc['DOC_VERSION'] . '.' . pathinfo($doc['FILENAME'], PATHINFO_EXTENSION); } }$usr = userInfo(@@USER_LOGGED);
PMFSendMessage(@@APPLICATION, 'manager@acme.com', $usr['mail'], '', '', 'Invoices for case', 'invoiceInfo.html', array(),$aAttachFiles);

Example Emailing Generated Output Document Files:

This trigger emails the PDF and DOC files of the latest version of an Output Document whose definition has the ID "691319281570bc9938b4460028767596".

//set to the Output Document definition's unique ID:
$outDocDef = "691319281570bc9938b4460028767596";$caseId = @@APPLICATION; //Unique ID for the current case
$aAttachFiles = array();$outDocQuery = "SELECT AD.APP_DOC_UID, AD.DOC_VERSION, C.CON_VALUE AS FILENAME
WHERE AD.APP_UID='$caseId' AND AD.DOC_UID='$outDocDef' AND
SELECT MAX(DOC_VERSION) FROM APP_DOCUMENT WHERE APP_UID='$caseId' AND DOC_UID='$outDocDef' AND APP_DOC_STATUS='ACTIVE')
AND AD.APP_DOC_UID = C.CON_ID AND C.CON_CATEGORY = 'APP_DOC_FILENAME'"
;
$outDoc = executeQuery($outDocQuery);

if (is_array($outDoc) and count(outDoc) > 0) {$path = PATH_DOCUMENT . G::getPathFromUID($caseId) . PATH_SEP . 'outdocs'. PATH_SEP .$outDoc[1]['APP_DOC_UID'] . '_' . $outDoc[1]['DOC_VERSION'];$filename = $outDoc[1]['FILENAME'];$aAttachFiles[$filename . '.pdf'] =$path . '.pdf';
$aAttachFiles[$filename . '.doc'] = $path . '.doc'; }$aUser = userInfo(@@USER_LOGGED);

@@resp=PMFSendMessage(@@APPLICATION, "admin@processmaker.com", $aUser['mail'], "", "", "Case Report", "caseReportTemplate.html", array(),$aAttachFiles);

Example Emailing File Uploaded in Home > Documents:

Files which are uploaded directly in the Home > Documents interface are not associated with any case, so their paths are different from normal files in the ProcessMaker. To attach one of these files to an email, first go to the Home > Documents interface and download the file. Then, in your web browser, go to the Download Manager and copy the URL to the file, which should be similar to:

http://example.com/sysworkflow/en/neoclassic/cases/cases_ShowDocument?a=965821362588279cb660237001025225&v=1

This file will be found on the ProcessMaker server at a location such as:

/opt/processmaker/shared/sites/workflow/files/00000000000000000000000000000000/965/821/362/588279cb660237001025225_1.png

or:

C:\Bitnami\processmaker-3.1.3\apps\processmaker\shared\sites\workflow\files\00000000000000000000000000000000\965\821\362/588279cb660237001025225_1.png

or:

C:\Users\Bob\AppData\Roaming\ProcessMaker-3_0_1_17\processmaker\shared\sites\workflow\files\00000000000000000000000000000000\965\821\362/588279cb660237001025225_1.png

Copy the CASE-DOC-UID and version number of the file and use it in the following trigger that sends the file as an attachment:

$appDocId = '965821362588279cb660237001025225';$docVersion = 1;
//get file extension from the filename:
$d = new AppDocument();$aFile = $d->Load($appDocId, $docVersion);$ext = pathinfo($aFile['APP_DOC_FILENAME'], PATHINFO_EXTENSION);$filePath = PATH_DOCUMENT . '00000000000000000000000000000000' . PATH_SEP .
G::getPathFromUID($appDocId) .'_'.$docVersion .'.'. $ext;$aAttachFiles = array(
$aFile['APP_DOC_FILENAME'] =>$filePath
);
$usr = userInfo(@@USER_LOGGED); PMFSendMessage(@@APPLICATION, 'manager@acme.com',$usr['mail'], '', '',
'Company Information', 'companyInfoTemplate.html', array(), $aAttachFiles); ### PMFGetUserEmailAddress() PMFGetUserEmailAddress() returns the email addresses for the specified user(s). variant PMFGetUserEmailAddress(variant$id, string $APP_UID=null, string$prefix='usr')

Parameters:

• variant $id: A list of recipients, which can be a mixture of user IDs, group IDs, variable names or email addresses. To find the IDs for users and groups, go to ADMIN > Settings > Web Services Test and use the userList() and groupList() web services or look them up in the wf_<WORKSPACE>.USERS.USR_UID field in the database or in wf_<WORKSPACE>.CONTENT.CON_ID where CON_CATEGORY='GRP_TITLE'. This list can either be an array with each recipient in a separate element or a string with each recipient separated by commas ",". If the recipients are all the same type, then set that type in the $prefix parameter. If the list contains a mix of different types, then prepend "usr|", "grp|", "dyn|" or "ext|" before each recipient. For the currently assigned user to a case, use "-1" or "usr|-1".
• string $APP_UID: The case unique ID from where the user will get the user email. Notice that the result value will be obtained from the last open delegation of the case specified. If using variables or the currently assigned user, then specify the unique ID of the case that contains the variables. If using "-1" as the first value to obtain the currently assigned user email, then the second parameter has to be @@APPLICATION. • string$prefix: An optional parameter. Specify the type for all the recipients in the list:
• "usr": All the recipients are users, so the $id is a list of unique IDs for users. This is the default value if the parameter is not included. • "grp": All the recipients are groups, so the $id is a list of unique IDs for groups.
• "dyn": All the recipients are variables, so the $id is a list of case variable names from the case specified in the$APP_UID parameter.
• "ext": All the recipients are external email addresses, so the $id is a list of email addresses. If the $id has mixed types of recipients, then do not include this parameter and specify the type in the $id, separated by vertical bars "|". Return Value: A list of email addresses. If the $id is a string, then a string will be returned with each email address separated by commas. If the $id was an array, then an array will be returned of email addresses. If there were no valid recipients in the $id, then the function returns false.

Examples:
Send an email to the currently assigned user for the current case:

$to = PMFGetUserEmailAddress('-1', @@APPLICATION); PMFSendMessage(@@APPLICATION, "boss@example.com",$to, '', '', 'Reminder Notice', 'reminderNote.html');

To send an email to the currently assigned user and two users with the IDs "79498307748c8645cbed0d2037379255" and "6187429034914a77c452de6051925565" for the current case:

$to = PMFGetUserEmailAddress('-1, 79498307748c8645cbed0d2037379255, 6187429034914a77c452de6051925565'); PMFSendMessage(@@APPLICATION, "boss@example.com",$to, '', '', 'Reminder Notice', 'reminderNote.html');

To do the same thing with an array of recipients:

$aTo = PMFGetUserEmailAddress(array('-1', '79498307748c8645cbed0d2037379255', '6187429034914a77c452de6051925565'));$sTo = implode(',' $aTo); //convert to a string with emails separated by commas PMFSendMessage(@@APPLICATION, "boss@example.com",$sTo, '', '', 'Reminder Notice', 'reminderNote.html');

Send out an email to the user IDs found in the case variables @@StoreManager, @@RegionalManager, @@CEO for the current case:

$to = PMFGetUserEmailAddress('StoreManager, RegionalManager, CEO', null, 'dyn'); PMFSendMessage(@@APPLICATION, 'boss@example.com',$to, '', '', 'Reminder Notice', 'reminderNote.html');

Send out the same email as above, but use the case variables for a case with the ID "1014502514e4556596e2e29033579043" and send the email in that case:

$to = PMFGetUserEmailAddress('StoreManager, RegionalManager, CEO', '1014502514e4556596e2e29033579043', 'dyn'); PMFSendMessage('1014502514e4556596e2e29033579043', 'boss@example.com',$to, '', '', 'Reminder Notice', 'reminderNote.html');

Send an email to users, groups, variables and email addresses. In this example, the email is sent to the currently assigned user to the current case, all the members of a group with the UID of "6538387794e45573cdaa563079341214", a user whose UID is specified in the field "selectedManager" in a DynaForm, and to the email address "john_doe@example.com":

$ids = 'usr|-1, grp|6538387794e45573cdaa563079341214, dyn|selectedManager, ext|john_doe@example.com';$to = PMFGetUserEmailAddress($ids); PMFSendMessage(@@APPLICATION, 'boss@example.com',$to, '', '', 'Reminder Notice', 'reminderNote.html');

To do the same thing, using an array:

$aIds = array('usr|-1', 'grp|6538387794e45573cdaa563079341214', 'dyn|selectedManager', 'ext|john_doe@example.com');$aTo = PMFGetUserEmailAddress($aIds);$sTo = implode(',', $aTo); PMFSendMessage(@@APPLICATION, 'boss@example.com',$sTo, '', '', 'Reminder Notice', 'reminderNote.html');

The PMFAddAttachmentToArray() function is used to add an additional file to an array of files, which can be passed to the PMFSendMessage() function to send out an email with an array of validated filenames through indexes. If a file with the same filename already exists in the array, it will add the file to the array, but rename its index key from "filename.ext" to "filename Copy(X).ext" where X is incremented so the original file doesn't get replaced.

array PMFAddAttachmentToArray(array arrayData, string index, string value, string suffix)

Parameters:

• array arrayData: An existing associative array of files, where the index key is the filename and the value is the web address or the complete path to the file in the file system of the server where ProcessMaker is installed. To understand the format of this array, see the aAttachments parameter of the PMFSendMessage() function.
• string index: The new filename of the file to be added, which will also be the new index in the associative array of files. Note that the added file will be renamed with this value, so it is recommended to include the file extension, such as .doc, .pdf, etc.
• string value: The web address or the path on the ProcessMaker server to the file to be added to the array.
• string suffix: Optional parameter. A string that will concatenated to the index if the filename already exists in the array. Its default value is " Copy({i})", where {i} will be replaced by an autoincremented number.

Return Value:

The modified associative array of files, with the new file added to it. This return value can be used as the aAttachments parameter in the PMFSendMessage() function.

Example 1:
In this example, the paths to 3 different files named "akbc14.pdf", "doc.pdf" and "doc.pdf" are in an array. The PMFAddAttachmentToArray() function is used avoid overwriting the existing files in the array of file attachments.

$aFiles = array( "https://terpconnect.umd.edu/~oard/pdf/akbc14.pdf", "/home/u1/Escritorio/doc.pdf", "/home/u1/Escritorio/doc.pdf" );$aAttachments = array();
foreach ($aFiles as$file) {
$aAttachments = PMFAddAttachmentToArray($aAttachments, basename($file),$file);
}

@@res0 = $aAttachments; The above trigger code will save in @@res0 an array of validated filenames: "akbc14.pdf", "doc.pdf" and "doc Copy(2).pdf". Example 2: In this example, the paths to 4 different files named "expenseReport.doc", "accountingGuide.pdf", "expenseReport.doc" and "expenseReport.doc" are in an array. Each file from the array is added as file attachments to an email. The PMFAddAttachmentToArray() function is used avoid overwriting the existing files in the array of file attachments. Then PMFSendMessage() is used to send out the email with the file attachments.$aFiles = array(
"http://www.acme.com/reports/expenseReport.doc",
PATH_DATA_PUBLIC . @@PROCESS . PATH_SEP . "accountingGuide.pdf",
"/home/accounting/2014-Nov/expenseReport.doc",
"/home/accounting/2014-Dec/expenseReport.doc"
);
$aAttachments = array(); foreach ($aFiles as $file) {$aAttachments = PMFAddAttachmentToArray($aAttachments, basename($file), $file); } PMFSendMessage(@@APPLICATION, 'accountant@acme.com', 'manager@acme.com', '', '', '3 months of expense reports', 'monthlyExpenses.html', array(),$aAttachments);

The above trigger code will send an email to manager@acme.com with the attached files named "expenseReport.doc", "accountingGuide.pdf", "expenseReport Copy(2).doc" and "expenseReport Copy(3).doc".

### getEmailConfiguration()

getEmailConfiguration() returns information about the current email configuration.

array getEmailConfiguration()

Return Value:

Returns an associative array with the following information about the email configuration:

 array( "MESS_PASSWORD", Encrypted password to login to the email server, such as: "vKbAqYO+urusxc6+xbp+eIF9" "MESS_PASSWORD_HIDDEN", Always set to "" (empty string. "MESS_ENABLED", Set to "1" if email notifications are enabled. If not enabled, set to "0". "MESS_ENGINE", The email engine, which can be "PHPMAILER" to use the PHPMailer program that supports SMTP, or "MAIL" to use PHP's mail() function to send the email via the mail transfer agent configured for the ProcessMaker server. "MESS_SERVER", The IP number or domain name of the email server, such as: "smtp.mail.yahoo.com" "MESS_RAUTH", Set to true if login needed to send out messages; otherwise set to false. "MESS_PORT", Port number of the email server, such as "25", "465" or "587". "MESS_ACCOUNT", The username of the email account. For some email servers, such as gmail, the account name included the full email address, such as:"joedoe@gmail.com" "MESS_BACKGROUND", HTML code for the background to the email message. Generally set to "" (no background). "MESS_EXECUTE_EVERY", Time between attempts to send message. If set to "", then uses the default. "MESS_SEND_MAX", Maximum number of attempts to send the message. If set to "", then uses the default. "SMTPSecure", The type of secure connection to the email server: "ssl", "tls" or "" (empty string for no secure connection) "MAIL_TO", Email address to whom the test email will be sent. "MESS_FROM_NAME", Name of the sender, such as: "ProcessMaker Admin" "MESS_TRY_SEND_INMEDIATLY", Set to "1" to send out a test email after configuring the email server or "false" to not send it. "MESS_FROM_MAIL", Email address of the sender of emails. In most cases this will be the same as the email account. )

Example:
Check whether email notifications are enabled before sending out an email with PMFSendMessage():

$aEmailConfig = getEmailConfiguration(); if ($aEmailConfig['MESS_ENABLED'] === "1"){
PMFSendMessage(@@APPLICATION, 'accountant@acme.com', 'manager@acme.com', '', '', 'Accounting report', 'accountingTemplate.html');
}

## Document Functions

PMFAddInputDocument() adds an Input Document file to a specified case.

string PMFAddInputDocument(string inputDocumentUid, string appDocUid, int docVersion, string appDocType = 'INPUT', string appDocComment, string inputDocumentAction, string caseUid, int delIndex, string taskUid, string userUid, string option = 'file', string file = 'path_to_file/myfile.txt')

Parameters:

• string inputDocumentUid: The unique ID of the Input Document definition. This can be found by clicking on the UID button in the list of Input Documents or by using the following database query:
SELECT CON_ID FROM CONTENT WHERE CON_CATEGORY='INP_DOC_TITLE' AND CON_VALUE='INPUT-DOC-TITLE'
• string appDocUid: The unique ID of the file to be replaced or a new version added. Set to null or "" (empty string) if adding a new file.
• int docVersion: The document version, which starts numbering from 1. If adding a new version, increment the existing version by 1.
• string appDocType: The document type, which is 'INPUT' for an Input Document file or 'ATTACHED' for an attached file (which is uploaded to a file field).
• string appDocComment: The comment for the uploaded file.
• string inputDocumentAction: The action, which can be: null or "" for add, "R" for replace or "NV" for new version.
• string caseUid: The unique ID of the case to which the file will added. It can be found in the following ways:
• Use the @@APPLICATION system variable to get the unique ID of the current case.
• Use the PMFCaseList(), WSCaseList() or the caseList() web service.
• Use executeQuery() to look up the case UID in the wf_<WORKSPACE>.APPLICATION.APP_UID field in the database.
• int delIndex: The delegation index of the case to which the file will be added. It can be found in the following ways:
• Use the system variable @%INDEX for the current case.
• Use the PMFCaseList(), WSCaseList() or the caseList() web service.
• Use executeQuery() to look up the delegation index in the wf_<WORKSPACE>.APP_CACHE_VIEW.DEL_INDEX field WHERE DEL_THREAD_STATUS='OPEN'.
• string taskUid: The unique ID of the task, which can be found in the following ways:
• Use the @@TASK system variable for the unique ID of the current task.
• Query the wf_<WORKSPACE>.TASK.TAS_UID field in the database or get the starting task of the current process with the following query:
executeQuery("SELECT TAS_UID FROM TASK WHERE PRO_UID='" . @@PROCESS . "' AND TAS_START='TRUE'")
• string userUid: The unique ID of the user who is set as the uploader of the file.
• string option: The option, which should be set to: "file"
• string file: The path to the file to be added, which is stored on the ProcessMaker server.

Return value:

• Returns ID if it has added the Input Document successfully; otherwise, returns null or empty if an error occurred.

Example:

Create an Input Document in ProcessMaker. Look up its current ID and assign it to the variable named inputDocumentUid. Set the values to 'null' of the application document Id and to 'Add' of the Document Action if it is the first time you are running the process.

inputDocumentUid = 757584323513f501410f3f3061256214 appDocUid = null inputDocumentAction = Add

Set the following trigger to execute before the Input Document files will be displayed:

@@APPLICATION, @%INDEX, @@TASK, @@USER_LOGGED, 'file', 'c:\file.txt');

If the same document needs to be uploaded as a new version, copy the Document ID previously added with the following parameters:

inputDocumentUid = 757584323513f501410f3f3061256214 appDocUid = 456268310513fa1b624c751021820069 //obtain this from the return variable while case is running or from the database wf_<WORKSPACE>.INPUT_DOCUMENT inputDocumentAction = 'NV'

Note: Don't forget to enable versioning when defining the Input Document. Otherwise, it won't be possible to upload another version of the same Input Document file.

### PMFGenerateOutputDocument()

PMFGenerateOutputDocument() generates a specified Output Document, merging the variables from the current case into the Output Document's template. This function creates the Output Document files in the server file system and adds a new record to the wf_<WORKSPACE>.APP_DOCUMENT table. For more information, see Output Document Storage. If the Output Document has already been generated for the current case, this function will overwrite the existing Output Document files (or add a new version of the files, if the versioning option is enabled.)

void PMFGenerateOutputDocument(string $outputID) Parameters: • string$outputID: The unique ID for the Output Document definition, which can be found in 3 ways:
1. Look it up in the wf_<WORKSPACE>.OUTPUT_DOCUMENT.OUT_DOC_UID field in the database.
2. In the wf_<WORKSPACE> database, issue the query: SELECT CON_ID FROM CONTENT WHERE CON_CATEGORY='OUT_DOC_TITLE'
3. Run a case with the Output Document as a step and examine the UID variable in the URLs with Time Logging.

Return Value:
None.

Note: PMFGenerateOutputDocument() can be called at any point in a case, but if a variable used in the Output Document template does not yet exist, then the variable name will be inserted in the generated file, not a value for that variable.

Examples:
1. If the template file for the Output Document contains a case variable set in the same trigger that calls PMFGenerateOutputDocument(), then the case variable will have to first be saved to the database using the PMFSendVariables() function.

For example, the template contains the variables @#ClientName and @#AccountNumber. Those variables will be saved to the database with PMFSendVariables() before calling PMFGenerateOutputDocument().

$vars = array("ClientName" => "Sally Simpson", "AccountNumber" => "G2938-238"); PMFSendVariables(@@APPLICATION,$vars);
$docId = '954109698491477e1986b43042252891'; //output document unique ID PMFGenerateOutputDocument($docId);

2. Generate an Output Document for the current case, then open the HTML file that was generated for it and insert it into an email template named "outDocMail.html", which has the inserted variable @#mailBody:

$docId = '954109698491477e1986b43042252891'; //set to the Output Document's unique ID PMFGenerateOutputDocument($docId);
//find the generated Output Document in the wf_&<WORKSPACE>.APP_DOCUMENT table
$query = "SELECT MAX(DOC_VERSION) AS MAX_VERSION, APP_DOC_UID FROM APP_DOCUMENT WHERE APP_UID = '$caseId' AND DOC_UID='$docId'" ;$result = executeQuery($query); if (is_array($result) and count($result) > 0) {$pathFilename = PATH_DOCUMENT . G::getPathFromUID(@@APPLICATION) . PATH_SEP . 'outdocs'. PATH_SEP .
$result[1]['APP_DOC_UID'] . '_' .$result[1]['MAX_VERSION'] . '.html';
$body = file_get_contents($pathFilename);
PMFSendMessage(@@APPLICATION, 'theboss@example.com', userInfo(@@USER_LOGGED)['mail'], '', '',
'Generated Output Document', 'outDocMail.html', array('mailBody' => $body)); } To send a generated Output Document file as an attachment in an email, see this example. 3. Generate an Output Document for the current case and then look up the generated Output Document files in the APP_DOCUMENT table. Copy the generated DOC and PDF files to another directory in the same server using the copy() function and to a remote server using the ssh2_scp_send() function.$caseId = @@APPLICATION;
$docId = '954109698491477e1986b43042252891'; //set to the Output Document's unique ID PMFGenerateOutputDocument($docId);
//find the generated Output Document in the wf_<WORKSPACE>.APP_DOCUMENT table
$query = "SELECT MAX(DOC_VERSION) AS MAX_VERSION, APP_DOC_UID FROM APP_DOCUMENT WHERE APP_UID = '$caseId' AND DOC_UID='$docId'" ;$result = executeQuery($query); if (is_array($result) and count($result) > 0) {$docPath = PATH_DOCUMENT . G::getPathFromUID(@@APPLICATION) . PATH_SEP . 'outdocs'. PATH_SEP;
$filename =$result[1]['APP_DOC_UID'] . '_' . $result[1]['MAX_VERSION']; //copy to another directory on the same server:$otherDir = 'C:\path\to\file\\'; //set to path for another directory
copy("$docPath$filename.doc", "$otherDir$filename.doc"); //if generating DOC files
copy("$docPath$filename.pdf", "$otherDir$filename.pdf"); //if generating PDF files

//copy to a remote server:
$remoteDir = '/path/to/file/'; //set to directory path on remote server$conn = ssh2_connect('www.example.com', 22); //set to URL for remote server
ssh2_auth_password($conn, 'username', 'password'); //set the username and password ssh2_scp_send($conn, "$docPath$filename.doc", "$remoteDir$filename.doc");
ssh2_scp_send($conn, "$docPath$filename.pdf", "$remoteDir$filename.pdf"); } ## Unique ID Functions ### generateCode() generateCode() creates a random string of letters and/or numbers of a specified length, which can be used as the PINs (public identification numbers) and codes for cases. For more info, see setCaseTrackerCode(). string generateCode(int size, string type) Parameters: • int size: The number of characters to be generated. • string type: The type of of characters to be generated, which can be 'ALPHA' (only letters), 'NUMERIC' (only numbers), and 'ALPHANUMERIC' (both letters and numbers). Return Value: The generated string of random characters. Note: There is no checking whether the string returned by generateCode() is unique, so do not use this function to uniquely identify any object in ProcessMaker. For that purpose, use the G::generateUniqueID() function. Example: To create a random string like "4NJQEWPT89AH": @@CaseCode = generateCode(10, 'ALPHANUMERIC'); ### PMFGeti18nText() Available version: 3.0.1.8 and later. PMFGeti18nText() returns the translation for a property of an object in ProcessMaker for a specified language. For example, this function can be used to look up the French translation of a task's title and description. These translations were entered by the process designer and stored in the wf_WORKSPACE.CONTENT table of the database. string PMFGeti18nText(string$id, string $category, string$lang = "en")

Parameters:

• string $id: The unique ID of the object whose property will be looked up to find a translation. • string$category: The category of the property to look up, such as 'GRP_TITLE' (a group's title) or 'INP_DOC_DESCRIPTION' (an Input Document's description. See this list of the available categories.
• string $lang: Optional. The code of the language to be retrieved, such as 'es' (Spanish) or 'pt-BR' (Brazilian Portuguese). Use the @@SYS_LANG system variable to look up the translation for the current system language of the logged-in user. If not included, then will return English by default. Return Value: Returns the translation stored in the CON_VALUE field of the CONTENT table. Example: Look up the description in Spanish of a trigger with the unique ID "63754922456d8c321a978c6078216529": @@DATOS = PMFGeti18nText("63754922456d8c321a978c6078216529", "TRI_DESCRIPTION", "es"); Which will get the text in Spanish as seen in the image below. If the same text in French (from France) is needed: @@DATOS = PMFGeti18nText("63754922456d8c321a978c6078216529", "TRI_DESCRIPTION", "fr-FR"); Then, it will get the text in French as seen in the image below. Note:Note that this function will only return a translation if there is an existing one for the specified language stored in the wf_WORKSPACE.CONTENT table. ### PMFGetUidFromText() Available Version: From 3.0.1.8 and on. The PMFGetUidFromText() returns the identifier of a process element using a text value from the Content table. Take into consideration that multiple results could be returned. array PMFGetUidFromText(string Text, string Category, string ProcessUid, string Language); Parameters: • Text: The text is the name of the element being searched. It must be the same to the one in the column CON_VALUE of the CONTENT table. • Category: The category of the text. Must be the same as the one in the column CON_CATEGORY of the table. The full list of all the paramenters in the CONTENT table can be found here. • ProcessUid: The Process UID is a string of 32 hexidecimal numbers generated by ProcessMaker. • Language: The SYS_LANG of the ProcessMaker system. Return Value: An array with the content ID values (CON_ID) of the elements that match the Text. Example: PMFGetUidFromText("CaseNumber", "TRI_TITLE", "22396981456f06b9998a366025856777", @@SYS_LANG); The returned value will show the ID values of the process elements that match the "CaseNumber" text: Array ( [0] => 61640608657d3322c37a9e5028591983 [1] => 80118505857b74527a89783055697820 [2] => 804473876582619454b70f1053825402 [3] => 9076538085824e8ae72c0e9058419541 ) ## Date Functions ### formatDate() formatDate() formats a date string according to a given date format and given language. Note that ProcessMaker stores the input in date fields in DynaForms as strings. string formatDate(string date, string format, string language='en') Parameters: • string date: The input date to be reformatted. The input date must be a string in the format 'yyyy-mm-dd' or 'yyyy-mm-dd h:i:s', such as '2015-12-31' or '1998-02-07 22:50:08'. This is the same format used to store dates and datetimes by the MySQL database and datetime fields in DynaForms. • string format: The format of the date that will be returned. It can contain the following codes: • yyyy - shows the year with four numbers (e.g. it shows the year 2008 as 2008) • yy - shows the year with two numbers (e.g. it shows the year 2008 as 08) • mm - shows the month with two numbers (e.g. it shows June as 06) • m - shows the month with a simple number (e.g. it shows June as 6) • M - shows the word for the month in the selected language (e.g. if the month is June, it shows June in English and junio in Spanish) • dd - shows the month with two numbers (e.g. the first day of the month is 01) • d - shows the month with a simple number (e.g. the first day of the month is 1) • h - shows the hours with two numbers in a 24 hour clock (e.g. 2pm is 14) • i - shows the minutes with two numbers (e.g. first minute is 01) • s - shows the seconds with two numbers (e.g. first second is 01) • string language: The language used to reformat the date. It can be 'en' (English), 'es' (Spanish) or 'fa' (Persian). If not included, English is set as the default language. Return value: • string: It returns the passed date according to the given date format. Note: For other languages, use PHP's strftime() function. See Formatting Dates in Other Locales. Examples: The value of @@textBox will be 'June 11, 2008': @@textBox = formatDate('2008-06-11', 'M dd,yyyy', 'en'); The value of @@textBox will be '7 de Junio del 2008': @@textBox = formatDate('2008-06-07', 'd de M del 2008', 'es'); The value of @@textBox will be '07/06/08 06:45:04': @@textBox = formatDate('2008-06-07 06:45:04', 'dd/mm/yy h:i:s'); (in this example, the language parameter is omitted and English is used by default) ### getCurrentDate() getCurrentDate() retrieves the current date in the format "yyyy-mm-dd", with leading zeros in the month and day if less than 10. This function is equivalent to PHP's date("Y-m-d"). string getCurrentDate() Parameters: • This function does not need any parameter. Return value: • string: It returns the current date as a string value. Example: If the current date is December 16, 2009: @@myTextBox = getCurrentDate(); The value of @@mytextBox will be '2009-12-16'. ### getCurrentTime() getCurrentTime() returns a string with the current time in the format "hh:mm:ss" with leading zeros when the hours, minutes or seconds are less than 10. The hour is expressed in the 24 hour format (military time) and is a number between 00 and 23. This function is equivalent to PHP's date('H:i:s'). string getCurrentTime(void) Parameters: • This function does not need any parameters. Return value: • string: The function returns the current time as a string. Example: If the current time is 9:13 am, then: @@curTime = getCurrentTime(); The value of the @@curTime will be '09:13:23'. ### literalDate() literalDate() returns a specified date written out in a given language, (e.g, English: "2008-06-11" returns "June 11, 2008", Spanish: "2008-06-11" returns "11 de Junio de 2008"). string literalDate(string date, string Language='en') Parameters: • string date: The input date in standard YYYY-MM-DD format that is a string. • string Language: The language to display, which can be 'en' (English) or 'es' (Spanish). If not included, then it will be English by default. Return value: The literal date is returned as a string. Note: For other languages, use PHP's strftime() function. See Formatting Dates in Other Locales. Example: @@textBox = literalDate("2009-12-17", "en"); The returned value stored in @@textBox will be 'December 17, 2009'. ## String Functions ### capitalize() capitalize() converts the first letter in each word into an uppercase letter. Subsequent letters in each word are changed into lowercase letters. string capitalize(string textToConvert) Parameters: • string textToConvert: The string to capitalize. Return value: • string: It returns the introduced text with the first letter capitalized in each word and the subsequent letters into lowercase letters. Example: @@phrase1 = capitalize("hello world"); @@phrase2 = capitalize("hElLo wOrLd"); Both @@phrase1 and @@phrase2 will be set to "Hello World". ### lowerCase() lowerCase() returns a string with all the letters converted into lower case letters. string lowerCase(string textToConvert) Parameters: • string textToConvert: A string to convert to lower case letters. Return value: • The function returns a string with the text converted into lower case letters. Example: @@phrase1 = lowerCase('HELLO WORLD'); @@phrase2 = lowerCase('HeLlO WoRlD'); Both @@phrase1 and @@phrase2 will be set to "hello world". ### upperCase() upperCase() returns a string converted into all UPPERCASE letters. string upperCase(string textToConvert) Parameters: • string textToConvert: A string to convert to UPPERCASE letters. Return value: A string converted into UPPERCASE letters. Example: @@phrase1 = upperCase('hello world'); @@phrase2 = upperCase('helLO WORld'); Both @@phrase1 and @@phrase2 will be set to "HELLO WORLD". ## Database Functions ### executeQuery() executeQuery() executes an SQL statement in a database connection or in one of ProcessMaker's internal databases. From Version: 3.0.1.8 and later. To avoid database integrity issues when SQL Queries are executed directly into the ProcessMaker Core tables, the executeQuery() function has been improved to protect Processmaker Core tables and PM_Tables defined by the user, for more information go to Protecting Processmaker Core Tables and PM_Tables. variant executeQuery(string SqlStatement, string DBConnectionUID='workflow') Parameters: • string SqlStatement: The SQL statement to be executed, which must begin with SELECT, INSERT, UPDATE, DELETE, EXECUTE, EXEC, SHOW, DESCRIBE, EXPLAIN or BEGIN. To learn basic SQL syntax, see this tutorial. Do NOT include the database name in the SQL statement. For example, use "SELECT * FROM USERS", instead of "SELECT * FROM wf_workflow.USERS". SQL key words such as "SELECT" and "WHERE" are case insensitive and can be written as "select" and "Where". If ProcessMaker is installed in Windows, the table and field names in its MySQL databases are also case insensitive by default, but in UNIX/Linux they are case sensitive by default (although this can be changed with the lower_case_table_names setting). If consulting ProcessMaker databases, it is recommended that all table and field names be in UPPERCASE in the SQL statement, so the processes will be exportable between Windows and UNIX/Linux. • string DBConnectionUID: Optional. The unique ID of the database connection where the SQL statement will be executed. The unique ID is a string of 32 hexadecimal numbers that uniquely identifies database connections, and can be found by opening a process, going to DATABASE CONNECTIONS, and clicking on its Show ID button in the list. If this parameter is not included, the SQL statement will execute in the wf_<WORKSPACE> database of the current workspace automatically, which is named wf_workflow by default. In ProcessMaker 3, each workspace has only 1 database by default, but each workspace upgraded from version 2 will have three databases by default, which can be accessed: • 'workflow' for the wf_<WORKSPACE> database. • 'rbac' for the rb_<WORKSPACE> database. • 'rp' for the rp_<WORKSPACE> database. To access a ProcessMaker database in a workspace that is not the current workspace, create a Database Connection to the database and use its UID. Return value: If executing a SELECT, EXECUTE, EXEC, SHOW, DESCRIBE, EXPLAIN or BEGIN statement, it returns an associative array of associative arrays in the format: array( '1' => array( 'FIELD1' => 'VALUE1', 'FIELD2' => 'VALUE2', ... ), '2' => array( 'FIELD1' => 'VALUE1', 'FIELD2' => 'VALUE2', ... ), ... ) The counting of the outer array starts from 1 (not 0 like a normal PHP array). All field values returned by SELECT statements will be strings, regardless of their original type in the database. In most cases, it is not necessary to explicitly convert the values with type casting, because PHP will gracefully convert integers and floating point numbers automatically if a field value is used in a mathematical operation. Datetime controls in DynaForms treat dates as strings, so date values generally do not need to be converted either. For INSERT statements, the function returns 1 if the operation was successful; otherwise it returns 0. For UPDATE and DELETE statements, the function will return the number of affected rows. If an error occurs in the database query, it returns a string containing the error message. If an error occurs, subsequent executeQuery() function that call to the same database in the same trigger will not execute correctly. If the SQL statement starts with an unrecognized SQL command, then executeQuery() will return FALSE. Example 1: Look up information about the logged-in ProcessMaker user:$uid = @@USER_LOGGED;   #assign to normal PHP variable to insert in string
$result = executeQuery("SELECT * FROM USERS WHERE USR_UID='$uid'");
if (is_array($result) and count($result) > 0) {
@@UserFirstName = $result[1]['USR_FIRSTNAME']; @@UserLastName =$result[1]['USR_LASTNAME'];
}

Note 1:

ProcessMaker system and case variables can NOT be inserted in double quoted strings, like this:

$result = executeQuery("SELECT * FROM USERS WHERE USR_UID='@@USER_LOGGED'"); Instead, ProcessMaker system and case variables need to be first assigned to normal PHP variables in order to be inserted inside a double quoted string, like this:$uid = @@USER_LOGGED;   #assign to normal PHP variable to insert in string
$result = executeQuery("SELECT * FROM USERS WHERE USR_UID='$uid'");

Also note that single quoted strings are treated as literal strings, so PHP variables can NOT be inserted in a single quoted string like this:

$result = executeQuery('SELECT * USERS WHERE USR_UID=\'$uid\'');

Note 2:

String, date and datetime values in SQL queries should be enclosed within single quoted strings, while integer and floating-point values should NOT be enclosed within single quotes. If it is necessary to insert an apostrophe into a string, escape it with a backslash. For example:

$result = executeQuery("SELECT FIRSTNAME, LASTNAME FROM CLIENTS WHERE ID=8734 AND STATUS='Don\'t wait'"); Some databases like MySQL will accept double quotation marks in place of single quotation marks around strings and dates, but they are not recommended because it is not part of the SQL standard. When using text input by a user in a database query, it is strongly recommended to pass that text through mysql_real_escape_string() if using a MySQL database, pg_escape_string() if using a PostgreSQL database, or addslashes() for other types of databases to avoid code injection attacks. For example, the following code uses text entered in a DynaForm field named "clientName" in the SQL query, so problematic characters are escaped with backslashes by using mysql_real_escape_string():$db = '89445967454f5d18dd694f4084525230'; //unique ID of database connection
$client = mysql_real_escape_string(@@clientName);$result = executeQuery("SELECT * FROM CLIENTS WHERE CLIENT_NAME='$client'",$db);
if (is_array($result) and count($result) > 0) {
@@contractAmount = $result[1]['CONTRACT_AMOUNT']; } Example 2: Look up all the users in a ProcessMaker group named "accounting":$query = "SELECT U.USR_FIRSTNAME AS FNAME, U.USR_LASTNAME AS LNAME " .
"FROM USERS U, CONTENT C, GROUP_USER GU WHERE " .
"U.USR_UID = GU.USR_UID AND GU.GRP_UID = C.CON_ID AND " .
"CON_VALUE = 'accounting'";
$result = executeQuery($query, 'workflow');

if (is_array($result)) { #loop to extract the returned rows foreach ($result as $row) @@GroupMembers[] =$row['FNAME'] . ' ' . $row['LNAME']; } Example 3: The Unique ID for the database connection is different in each process. If planning to reuse the same same code in multiple processes, this code shows how to look up the unique ID for a database connection to an external database named "company_data" with the table "clients" at 192.168.2.100. This example also shows how to insert, update and delete records in the database: #first look up the UID of the database connection$proc = @@PROCESS;
$result = executeQuery("SELECT DBS_UID FROM DB_SOURCE WHERE PRO_UID='$proc' " .
"AND DBS_DATABASE_NAME='company_data' AND DBS_SERVER='192.168.2.100'");

if (!is_array($result) or count($result) == 0)
die("Error: Unable to look up UID for database 'company_data'!");

$db =$result[1]['DBS_UID'];
$query = "INSERT INTO CLIENTS (FNAME, LNAME, COMPANY) VALUES ('Jane', 'Doe', NULL)"; if (executeQuery($query, $db) == 0) die("Unable to insert record into company_data.CLIENTS table");$query = "UPDATE CLIENTS SET COMPANY='Acme Inc.' WHERE FNAME='Jane' AND LNAME='Doe'";

if (executeQuery($query,$db) == 0)
die("Unable to update the company_data.CLIENTS table");

$query = "DELETE FROM CLIENTS WHERE FNAME='Jane' AND LNAME='Doe'"; if (executeQuery($query, $db) == 0) die("Unable to delete record in company_data.CLIENTS table"); Example 4: In this example, executeQuery() is used to look up the next available case to which the logged in user is assigned. If a case is found, then the web browser will automatically be redirected to that case with the G::header() function, otherwise the browser will be redirected to the Case List page. Before redirecting the browser, the current task is automatically routed to the next task in the process with PMFDerivateCase(). This trigger code can be added after the last step in the task, to avoid the user having to see the screen that displays the next assigned user and clicking "Continue".$userId = @@USER_LOGGED;
$query = "SELECT APP_UID, DEL_INDEX FROM APP_DELEGATION " . "WHERE USR_UID = '$userId' AND DEL_THREAD_STATUS = 'OPEN' " .
"ORDER BY DEL_DELEGATE_DATE DESC";
$queryResult = executeQuery($query);

if (is_array($queryResult) && count($queryResult) > 0)
$caseURL = 'cases_Open?APP_UID=' .$queryResult[1]['APP_UID'] .
'&DEL_INDEX=' . $queryResult[1]['DEL_INDEX']; else$caseURL = 'casesListExtJs';

//Route the current case to the next task in process:
PMFDerivateCase(@@APPLICATION, @%INDEX);
//Redirect the web browser to a new location:
die();

Other examples:

For an example using executeQuery() to access information about DynaForm file objects and write files to a database, see Accessing Files with PHP. For an example using executeQuery() to populate a grid, see Accessing Grids with PHP.

## Grid Functions

### orderGrid()

orderGrid() sorts a grid according to a specified field in ascending or descending order.

array orderGrid(array gridName, string field, string criteria='ASC')

Parameters:

• array gridName: A grid, which is a numbered array containing associative arrays with field names and their values, has to be set like this "@=".
• string field: The name of the field by which the grid will be sorted.
• string criteria: Optional parameter. The order can either be 'ASC' (ascending) or 'DESC' (descending). If not included, 'ASC' will be used by default.

Note: The result of this function has to be saved in a Grid in order to see the sorted information; it can be saved in the same grid or in another grid.

Example:

If your grid is like this:

MyGrid = ( [firstname][lastname] [1] ( 'erik', 'ortiz' ) [2] ( 'ana', 'castro' ) [3] ( 'naira', 'jimenez' ) [4] ( 'jessica', 'martinez') )

Then sort the grid by the 'firstname' field:

@=MyGrid = orderGrid(@=MyGrid, 'firstname', 'ASC');

The result will be the following grid:

MyGrid = ( [firstname][lastname] [1] ( 'ana', 'castro' ) [2] ( 'erik', 'ortiz' ) [3] ( 'jessica', 'martinez') [4] ( 'naira', 'Jimenez' ) )

### evaluateFunction()

evaluateFunction() executes a function on each row in a grid, using the grid fields in operations such as + (addition), - (subtraction), * (multiplication), / (division), and % (remainder). The formula can also use ( ) to group together operations.

array evaluateFunction(array gridName, string Expression)

Parameters:

• grid gridName: The input grid.
• string Expression: The input expression for the operation among grid fields. The expression always must be enclosed within double quotes, otherwise a fatal error will occur.

Return Value:
This function returns an associative array of associative arrays, which is how grids are internally stored in ProcessMaker.

Example:

MyGrid = ( [name] [salary] [discount] [total] [1] ( 'ana', 1000, 100, 0 ) [2] ( 'erik', 2000, 0, 0 ) [3] ( 'jessi', 1200, 400, 0 ) [4] ( 'naira', 2000, 0, 0 ) )

The following function is executed, which subtracts the 'salary' field from the 'discount' field in each row and assigns the result to the 'total' field:

@=MyGrid = evaluateFunction(@=MyGrid, "@#total = @#salary - @#discount");

The result will be the following grid:

MyGrid = ( [name] [salary] [discount] [total] [1] ( 'ana', 2000, 100, 1900 ) [2] ( 'erik', 2000, 0, 2000 ) [3] ( 'jessi', 1200, 400, 800 ) [4] ( 'naira', 2000, 0, 2000 ) )