Overview

This control allows files to be uploaded to a Dynaform and attached to the current case. To attach files, use the Choose Files button when this control is rendered. Select the files to be attached following the directions provided by the browser. After being attached, the files will be listed in the control field on the Dynaform. The icon of this control in the toolbar of the designer is the following:

While designing a Dynaform, it is not possible to upload any files or preview them. When the Dynaform is rendered, the end user will be able to upload and preview files using the control field. When the File control is added to the Dynaform, it will look like this:

This control allows users to attach as many files as necessary to the Dynaform. When running a case or previewing a Dynaform, it is displayed as follows:

It is possible to view a file previously attached to a form after submitting or sending the form by going back to the previous step and clicking on the file's link.

Warning: The File control is no longer supported as a grid column and will no longer be available in upcoming releases of ProcessMaker. In ProcessMaker 3.1 or later, please use the Multiple File Uploader control instead.

Properties

It is possible to customize a File control's functionality and behavior by configuring its properties:

Type file (read-only)
Variable

Click on the ... option to select a variable from the list of available variables. See this section to learn more about how to relate a variable to a control.
The type of variable supported by this control is the following:

  • File
Variable Data Type After a variable has been related to the control, this property shows the data type of the variable (read-only).

ID

[Required]

Field and HTML unique identifier.

Name HTML Field name
Label The label of the control
Hint Used to show help when the control is rendered (in the preview or when running cases). It is shown when the pointer of the mouse is hovered over the ? icon.
Required

By checking this option, an asterisk is added to the label to indicate that the field is required, meaning that a file must be uploaded to the field.

Note: The Required property only validates that there is a file attached to the web control, and not that the current user attaches a new file.

File Extensions

Use this property to define the file extensions allowed. Use a comma to separate all the extensions that will be enabled for the control. For example “.jpg, .png, .pdf

If this property is not defined, then any file extension is allowed.

Max File Size

Set the maximum allowed file size of the file to be uploaded. By default the maximum file size is 1024 KB.

Size Unit Define the unit (KB or MB) of the maximum file size.
Display Mode

[Required]

Display mode:

  • parent: Inherits the display mode defined in the parent container (form/grid).
  • edit: The control is enabled for editing when it is rendered.
  • view: The control can only be viewed when it is rendered and the content can’t be edited.
  • disabled: The control is displayed in gray to indicate that the disabled mode is on. The content can't be edited either.

File Extensions

The File Extensions property defines the file extensions that can be uploaded to the field:

The allowed extensions are defined in the format filename.extension. Use * (asterisk) as a wildcard. * alone allows all types of files. Use *.extension to allow a specific type of file, such as *.pdf or *.doc. To allow multiple types of files, separate them with , (commas). For example, *.png, *.jpg, *.jpeg, *.tif, *.tiff, *.gif only allows image files.

For example, if only PDF files may be attached to the file control, then set this property to *.pdf. When running cases, the File control will indicate what type of file can be uploaded:

If a file named pm_ListParticipants.pdf is uploaded, then the file control will validate it as the Dynaform is being submitted.

If a file with a different extension is attached, a validation error message will be shown:

Considerations:

  • For file fields that are NOT required
    • If the field accepts all file extensions and no file is attached when running a case, then the validation passes and the form can be sent or submitted without restrictions.
    • If the field accepts all file extensions and a file is attached when running a case, then the validation passes unless it has the size limit, in that case another validation, explained in the next property is evaluated. Nevertheless, if the field only accepts some types of extensions and no file is attached, then the validation passes.
    • If the field only accepts some types of extensions and no file is attached, then the validation passes and the form can be sent or submitted without restrictions.
    • If the field only accepts certain types of extensions and a file is attached, then the validation passes unless the user attaches a file with an invalid extension. In that case, a message is shown with a warning that indicates that the file extension is not supported. Nevertheless, if the field only accepts some types of extensions and no file is attached then the validation passes.
  • For required file fields
    • If the field accepts all file extensions and no file is attached, then the validation FAILS because the field is required and the form can NOT be sent or submitted.
    • If the field accepts all file extensions and a file with one of those extensions is attached, then the validation PASSES unless it has a size limit; in that case another validation, explained in the next property, is evaluated.
    • If the field only accepts some types of extensions and no file is attached, then the validation FAILS because the field is required and the form can NOT be sent or submitted.
    • If the field only accepts some types of extensions and a file with the correct extension is attached, then the validation passes unless the user attaches a file with an invalid extension. In that case, a message is shown with a warning that indicates that the file extension is not supported. In that case, the form can NOT be submitted until a valid file is attached.
  • Special case
    • When running cases, if a file is attached to a field that is required and the form is submitted to the next step, but then the user goes back to the previous step, the file will be shown as a link under the attachment button of the file field. It will not be necessary to attach another file, since the previous file attach will still count for the required field, so the form can be submitted or sent without any restrictions.
  • File field in a grid
    • Files in grids have the same considerations as explained above, but in cases when the grid is not associated with a variable and a valid file is attached and sent, the new data is not added to the database. This is because the grid MUST have an associated variable to correctly save the data.

Max File Size

This property defines the maximum allowed size of uploaded files. By default, this property is set to 1024 KB. To define this property, enter a positive number greater than zero:

Leave the field blank to allow the file size to be unlimited.

When running a case, the file field will validate the size of the file before attaching it to the field. If the size of the file surpasses the size defined in this property, a message is shown and the file is not attached to the field:

Considerations:

  • For file fields that are NOT required
    • If the max file size limit validation of the file attached FAILS, the file is not attached to the field. Nevertheless, as the field is not required, the form can be submitted or sent.
  • For required File fields
    • If the max file size limit validation of the file attached FAILS, the file is not attached to the field and the form CAN NOT be submitted or sent.
  • Special case
    • When running cases, if a file is attached to a required field and the form is submitted to the next step, but then the user goes back to the previous step, the submitted file is shown as a link under the attachment button of the file field. It will not be necessary to attach another file, since the previous file attach will still count for the required field, so the form can be submitted or sent without any restrictions.
  • File field in a grid
    • Files in grids have the same considerations as explained above, but in cases when the grid is not associated with a variable and a valid file is attached and sent, the new data is not added to the database. This is because the grid MUST have an associated variable to correctly save the data.

Size Unit

This property defines the unit (KB, MB) of the size defined in the Max File Size property.

When running a case, the control will validate the size of the file before attaching it to the field. If the size of the file surpasses the size defined in this control, a message like the following is shown:

File Control Example

For this example, add a File control to the Dynaform by dragging and dropping it onto the Dynaform designer from the Web Controls panel. After the File control is dropped onto the Dynaform, the control field will look like the image below:

Immediately after adding the control, the Create Variable window will appear, where a variable can be created or a previously created variable can be selected to store the information entered into the control field by the end user. A variable can also be created using the variables interface by clicking on the Variables button. For this example, a new variable will be created, so select the Create Variable option. Keep the variable name as "filevar", but this name can be changed by simply erasing this name and adding a new one. Click on the underlined Settings option to display more configurations for the variable.

The File control only has two settings: Type and Input Document (required field). The Type setting has only one option, "File". For the Input Document setting, an input document must be chosen. To learn how to create an Input Document, read this documentation. To add an input document, simply click on the underlined ellipsis, as seen in the image below.

A new Input Documents window within the Create Variable window will appear. Select an input document from the list by clicking on it. Then, in the Create Variable window, click on the Save button to finish this configuration.

Click in the empty space of the control and its properties will be displayed in the left side panel.

Another way to add a variable is by exiting the Create Variable window and in the properties, click on the underlined ellipsis next to the Variable property as shown in the image.

The Create Variable window will appear, where a variable can be created by selecting "Create variable" radio button or chosen from a list of existing variables by selecting the "Select variable" radio button. Once a variable is chosen, the variable data type and the id properties will have the same name as the variable added.

Now, the id property can be used with JavaScript code. To add JavaScript code to the variable, click on the light gray border of the Dynaform (which is the space outside the controls) to display the properties of the Dynaform. When the properties are displayed, locate the javascript property and click on the edit... button to open the editor.

In the JavaScript editor, add code that sets the label of the control. Read this section for more information. For this example, add the following code:

jQuery("#fileVar").setLabel("ProcessMaker");

When the control is rendered, the label will then be set to "ProcessMaker", as seen in the image below.

The following property is the Name property, which is the HTML Field name. By default, the name property is the same as the ID. When the ID is changed by the user, the name does not change and keeps its original configuration. The name can also be changed by entering a new value into the property.

Continuing on, the label property changes the label of the control displayed on the Dynaform. Add a label, such as "Upload a File:", to label the control on the Dynaform.

The Hint property is used to show help when the control is rendered. For this example, add the following sentence to the property: "Select a file to upload". When the control is rendered hover the pointer of the mouse over the (i) icon to show the hint added.

For the Required property there is only a checkbox available. When checked, an asterisk is added next to the control field to indicate that the field is required and the user will not be able to submit the form until the field is properly filled in.

The file extensions property validates the extensions of files uploaded to the control. For this example add ".doc", this means that the control won't accept other extensions besides the one specified in this property.

Now, the max file size and the size unit properties will determine the maximum allowed file size and will define the size unit (KB, MB) of the file uploaded.

Finally, the display mode control will have different effects when rendering a Dynaform. Use the illustration below as guide to the property's functionality.

Associating an Input Document with a File

Available Version: ProcessMaker 3.0.1.5 on.

As of version 3.0.1.5 on, it is possible to associate an Input Document with a File field inside a Dynaform by using a File variable. This means that files uploaded to a File field in a Dynaform can be displayed at a later point inside an Input Document step. One advantage of associating a File field with an Input Document is that the Input Document interface can be used to view all the files uploaded (as well as delete files and add new versions if the user has the proper Process Permissions and versioning is enabled). Another advantage is that in Input Documents, all the uploaded files have tags and are placed in a specified folder under Home > Documents, so it is easier to find the uploaded files later.

Uploading a file to an Input Document through a File field in a Dynaform is useful when only uploading one file to an Input Document. To ensure that the user uploads a file to an Input Document, then make the File field required. It is not possible to associate File fields in a grid to an Input Document, because fields inside grids do not have a variable. To upload more than one file to an Input Document, then a normal Input Document step should be used.

To associate an Input Document with a File field, it is recommended to first create the Input Document in the project. Then, create the variable that will be related to the File control. To do this, go to the Process Objects toolbox and hover the pointer of the mouse over the + icon next to the Variables option. Click on Create. In the window that opens, enter the name of the variable in the Variable Name field and select the option ·File" from the dropdown in the Variable Type field. (See Defining Variables.)

Associate the variable with the previously created Input Document in the Related Input Document field by selecting it from the dropdown box, or by creating a new Input Document.

To edit the Input Document selected in the Related Input Document field, click on the Edit button.

After creating the File variable, open a Dynaform where the File control will be placed. Add a File field to the design and click on it to view its properties. Go to the Variable property and click on the ... button.

Select the File variable that will be associated with the File control from the list of available File variables.

After selecting the variable, the Input Document will be associated with the control.

After associating the File variable with the control, the File Extensions, Max File Size and Size Unit properties will be disabled. These properties are automatically set to the Input Document's settings. Make sure to set a Max File Size greater than zero for the Input Document.

Note: The file fields fails to respect the configuration made in the PATH of the Input Document. This consideration will be solved in future versions.

Warning: The name property of the File field must have the same name as the variable associated with the field. If they are different, then the uploaded files will not be associated with the Input Document and will be treated as normal attached files.

Accessing Files with JavaScript

To learn how to manipulate Dynaform controls using JavaScript, see JavaScript in DynaForms.

Files in ProcessMaker 3 have the following field components:

  • Label: The text displayed above or to the left of the field on the Dynaform that identifies it.
  • Value: The filename of the last file selected in the file control.
  • Text: An array of the filename(s) in the file control.

JavaScript Methods

Some of the JavaScript methods used to manipulate file fields include:

Method Description
jQuery("#fieldID").getValue() Returns the filename of the last file selected in the file control, or the last file added to its associated Input Document if no file has been selected.
jQuery("#fieldID").getText() Returns an array of the filenames of files that were previously added to the Input Document associated with the file control, plus the filename of the last file selected in the file control (if any). The filenames are in the order that the files were added. Remember that only one file can be added using the file control, but multiple files can be added to the Input Document.
jQuery("#fieldID").getLabel() Returns the field's label, which is the text displayed above or to the left of the field on the Dynaform to identify it.
jQuery("#fieldID").setLabel("newLabel") Sets the field's label, which is the text displayed above or to the left of the field on the Dynaform to identify it.

Note: The setValue() and setText() methods exist for file controls, but do not have any effect, since files can only be selected manually by the user.

To see code examples for these methods, see JavaScript Functions and Methods.

Clearing File Controls

The file selected in a File control cannot be set using JavaScript, because this requires user action. However, it is possible to use JavaScript to clear the selected file in a File control.

To remove the selected file, change the value of the file field with the ID "form[file-id]" to "". Also, change the value of the hidden field with the ID "form[file-id_label]" from '["filename"]' to '[]' (an empty array in a JSON string). The filename of the selected file also needs to be replaced in the File control with the phrase "Allowed file extensions: *".

$("#file-id").find('input[type=file]').val(""); $("#file-id").find('input[type=hidden]').val("[]"); $("#file-id").find("button").html("Allowed file extensions: *"); $("#file-id").find("button").prop("title", "Allowed file extensions: *");

Note that * depends on the configuration of the File control or its associated Input Document, so it is recommended to save the text displayed by the File control when the DynaForm first loads.

var message = $('#file-id').find("button").text();

For example, a Dynaform has a File control with the ID "contractFile" and a button with the ID "clearContract".

The following JavaScript code clears the "contractFile" File control when the user clicks on the "clearContract" button:

$("#clearContract").find("button").click( function() {
    $("#contractFile").find('input[type=file]').val(""); //clear file field
    $("#contractFile").find('input[type=hidden]').val("[]"); //clear hidden field
    $("#contractFile").find("button").html("Allowed file extensions: *");
    $("#contractFile").find("button").prop("title", "Allowed file extensions: *");
});

Structure of File Controls

A file control consists of:

  • A visible <button> that is inside a DIV tag with the ID of the file control that is clicked to select a file to be uploaded. After a file is selected, the name of the selected file is displayed in this button.
  • A hidden file field with the ID "form[id]", where the selected file is temporarily stored.
  • A hidden input field with the ID "form[id_label]", which holds an array of the files that have been previously uploaded to the Input Document associated with the file control, plus the last file selected with the file control.

For example, a file control with the ID "receipts" might have the following HTML structure:

<div id="receipts" name="field-receipts" class="pmdynaform-field-file  form-group col-sm-12 col-md-12 col-lg-12  pmdynaform-edit-file pmdynaform-field">
  <label for="receipts" class="col-md-2 col-lg-2 control-label pmdynaform-label">
    <span class="textlabel">Receipts</span>
  </label>
  <div class="pmdynaform-file-control col-md-10 col-lg-10 pmdynaform-field-control">
    <div class="pmdynaform-file-container col-xs-12 col-sm-12 col-md-12 col-lg-12">
      <div class="pmdynaform-file-btn-container">
        <button title="receipt_2015-02-25.doc" type="button" class="pmdynaform-control-file form-control">receipt_2015-02-25.doc</button>
      </div>
      <input id="form[receipts]" name="form[receipts]" style="visibility:hidden;" type="file">
      <input value="[&quot;lunchReceipt_2015-02-25.jpg&quot;]" id="form[receipts_label]" name="form[receipts_label]" type="hidden">
      <div name="button-all" class="btn-group btn-group-justified" style="display: none;">
        <div class="pmdynaform-file-buttonup btn-group">
          <button class="glyphicon glyphicon-upload btn btn-success btn-sm">
            All
          </button>
        </div>
        <div class="pmdynaform-file-buttoncancel btn-group" style="display: none;">
          <button class="glyphicon glyphicon-remove btn btn-danger btn-sm">
            All
          </button>
        </div>
        <div class="pmdynaform-file-buttonremove btn-group">
          <button class="glyphicon glyphicon-trash btn btn-danger btn-sm">
            All
          </button>
        </div>
      </div>
    <div class="pmdynaform-file-list" style="display:none"></div>
    </div>
  </div>
</div>

The user interacts with the visible button, which doesn't have an ID, but can be searched for using its "pmdynaform-control-file" class. For example, the following code changes the border color of the button used by the "receipts" file control:

$("#receipts").find("button.pmdynaform-control-file").css("border", "1px solid red");

The setOnchange() method doesn't work with file controls, but the hidden file field can be used to set a change event handler. For example, the following event handler checks whether the uploaded file matches the pattern receipt_YYYY-MM-DD.doc, so that its filename contains the date:

function checkFilename() {
    //if filename doesn't match "receipt_YYYY-MM-DD.doc":
    var n = this.value.search(/receipt_20[0-9][0-9]-[0-1][0-9]-[0-2][0-9]\.doc$/g);
    alert (n);
        if (n === -1) {
        alert("Please rename the file '" + this.value + "' to match the pattern 'receipt_YYYY-MM-DD.doc' and upload it again.");
        }
}
$("#receipts").find('input[type=file]').change(checkFilename);

File Storage

When a file is uploaded to a file field while running a case, it is stored in the file system of the ProcessMaker server. It is renamed with its unique ID for the case-document and its version number, but it retains its original extension.

Files are stored in the following location on the server:
    INSTALL-DIRECTORY/shared/sites/WORKSPACE/files/XXX/XXX/XXX/XXXXXXXXXXXXXXXXXXXXXXX/CASE-DOCUMENT-UID_VERSION.EXT

Where:

  • WORKSPACE is the name of the workspace, which is named "workflow" by default, and can be specified with the @@SYS_SYS system variable in a trigger.
  • XXX/XXX/XXX/XXXXXXXXXXXXXXXXXXXXXXX represents the case's unique ID. By default this is divided into a series of 4 subdirectories to avoid the 32K file limits of Linux's ext3 file system, but it may be a single directory if using a workspace upgraded from ProcessMaker 2. In a trigger, the case ID of the current case is stored in the @@APPLICATION system variable or it can be looked up in the APPLICATION.APP_UID, APP_CACHE_VIEW.APP_UID or APP_DOCUMENT.APP_UID fields in the database. The G::getPathFromUID() method can be used in a trigger to automatically generate the correct path from the case ID.
  • CASE-DOCUMENT-UID is the unique ID of the case-document, which is stored in the APP_DOCUMENT.APP_DOC_UID field in the database.
  • VERSION is the document version number and is always set to 1, except when the file field is associated with an Input Document that has enabled versioning and the user has uploaded a new version of the file (which field fields don't allow). The new version can be found in the APP_DOCUMENT.DOC_VERSION field in the database.
  • EXT is the extension of the uploaded file, such as doc or jpg. The file extension can be found by using the AppDocument::Load() method or by looking up the filename of the uploaded file with the following database query: SELECT CON_VALUE AS FILENAME FROM CONTENT WHERE CON_ID='CASE-UID' AND CON_CATEGORY='APP_DOC_FILENAME'

Example path in Linux/UNIX:
    /opt/processmaker/shared/sites/workflow/files/905/262/500/57158b1b439014072150115/74863719957158b39af56d2076904431_1.png

Example path in Windows Vista and later:
    C:\User\Bob\AppData\Roaming\ProcessMaker-3_0_1_7\processmaker\shared\sites\workflow\files\905\262\500\57158b1b439014072150115\74863719957158b39af56d2076904431_1.png

In a trigger, the path to a file can be determined using the defined constants PATH_DOCUMENT (which contains a path such as "/opt/processmaker/shared/sites/workflow/files/") and PATH_SEP (which is "/" or "\" depending on the operating system).

For example, the following trigger code generates the same path as in the above examples:

$g = new G();
$path = PATH_DOCUMENT . $g->getPathFromUID('90526250057158b1b439014072150115') . PATH_SEP . '74863719957158b39af56d2076904431_1.png';

File Storage in the Database

When a Dynaform that contains a file field is submitted, a new record is created for the uploaded file in the APP_DOCUMENT table in the database, which contains the following fields:

  • APP_DOC_UID: The unique ID of the case document, which identifies the uploaded file.
  • DOC_VERSION: The version of the case document file, which is an integer counting the version starting from 1. It can only be greater than 1 if the file is associated with a variable for an Input Document that has versioning enabled.
  • APP_UID: The unique ID of the case where the file was uploaded.
  • DEL_INDEX: The delegation index of the task in the case where the file was uploaded.
  • DOC_UID: The unique ID of the Input Document that holds the file, if the file field is associated with an Input Document. If the file is not associated with ah Input Document, then it is set to '-1'.
  • USR_UID: The unique ID of the user who uploaded the file.
  • APP_DOC_TYPE: The type of case document, which is 'ATTACHED' if the file field is unassociated with an Input Document, or 'INPUT' if it is associated with an Input Document.
  • APP_DOC_CREATE_DATE: The datetime in 'YYYY-MM-DD HH:MM:SS' format when the file was uploaded.
  • APP_DOC_INDEX: The document index of the file, which counts the order by which files are added to a case, regardless of whether it is an Input Document file, Output Document file or attached in a file field. The first file is 1, the second file is 2, etc.
  • FOLDER_UID: The unique ID of the folder where the file is located in the interface under Home > Documents. If the file field is not associated with an Input Document or the Input Document has no specified folder, this field is set to '' (empty string).
  • APP_DOC_PLUGIN: Always set to '' (empty string) if not using a plugin to manage the files.
  • APP_DOC_TAGS: If the file field is associated with an Input Document, then this field contains the tags for the Input Document, which are separated by commas. By default all Input Documents have the tag of 'INPUT', but other custom tags can be defined. If the file field is not associated with an Input Document, then this field is set to NULL.
  • APP_DOC_STATUS: The status of the file, which is either 'ACTIVE' or 'DELETED'. Note that file fields don't provide a way to delete uploaded files, but the file can be deleted by a user who has the PM_FOLDERS_ADD_FILE permission in his/her role. It can also be deleted if the file field is associated with an Input Document that is a step in the task and the user has been assigned Process Permissions to delete files in the Input Document.
  • APP_DOC_STATUS_DATE: Always set to NULL.
  • APP_DOC_FIELDNAME: The name (not its id) of the file field where the file was uploaded. If uploaded in a file field in a grid, then it is set to 'grid-variable_row-number_file-field-name'. For example, a value of 'clientList_2_contractFile', means that the file was uploaded to the second row of a grid whose variable is "clientList" and whose file field has the name "contractFile". If the file was uploaded in an Input Document step (not a file field), then it is set to NULL.
  • APP_DOC_DRIVE_DOWNLOAD: The serialized ID of the uploaded file when ProcessMaker is syncronized with Google Drive. If the uploaded file is not synchronized with Google Drive, this field is always set to 'a:0:{}'.

In addition, records that contain information about the uploaded file are added to the CONTENT table.

For example, the database contains the following information about an uploaded file with the unique ID '74863719957158b39af56d2076904431':

mysql> select * from CONTENT where CON_ID='74863719957158b39af56d2076904431'; +------------------+------------+----------------------------------+----------+---------------------+ | CON_CATEGORY | CON_PARENT | CON_ID | CON_LANG | CON_VALUE | +------------------+------------+----------------------------------+----------+---------------------+ | APP_DOC_COMMENT | 1 | 74863719957158b39af56d2076904431 | en | | | APP_DOC_FILENAME | 1 | 74863719957158b39af56d2076904431 | en | scannedContract.png | | APP_DOC_TITLE | 1 | 74863719957158b39af56d2076904431 | en | | +------------------+------------+----------------------------------+----------+---------------------+ 3 rows in set (0.00 sec)

The filename of the uploaded file is found WHERE CON_CATEGORY='APP_DOC_FILENAME'. File fields do not allow the user to add a comment when uploading a file, but the interface for Input Documents does allow the user to add a comment about an uploaded file. The title field is outdated and no longer used.

Variable Storage

When a Dynaform containing a file field is submitted, a case variable named @@file-field-name_label will be created. Remember that the name of the case variable is based on the name of the field field, not its ID and not its associated variable. The case variable will be created when the Dynaform is submitted, even if the file field has no selected file to upload. The file field does not need to be associated with a file variable. In fact, no case variable is created for file variables when running cases.

The case variable @@file-field-name_label will hold a JSON string that contains an array with the filename of the selected file inside: '["filename"]'
If no file was selected, then the JSON string will be an empty array: '[]'
In version 3.0.1.6 and earlier, file fields were capable of displaying multiple files, so the array could hold multiple filenames. In version 3.0.1.7 and later, file fields are only capable of displaying a single file, so the array will only hold one filename. The json_decode() function can be used to convert the string into an array and obtain the filename inside the array.

For example, if a file field has the name "receiptFile" and a file named "monthlyReport.doc" is selected, then its case variable will be named @@receiptFile_label and it will hold the array '["monthlyReport.doc"]'. The following trigger code can be used to obtain the filename of the selected file:

$aReceipt = json_decode(@@receiptFile_label);
$filename = empty($aReceipt) ? '' : $aReceipt[0];

When a file control in a Dynaform is submitted, the unique ID of the uploaded file is placed in an array and converted to a JSON string, which is stored in the variable associated with the file field. For example, if the file control is associated with @@contractFile and the user uploads a file, then the @@contractFile variable might have a value such as: '["16820977557c7577c2e5c42054010817"]'

The unique ID of the uploaded file can be obtained with the following trigger code:

if (isset(@@contractFile) and @@contractFile != '[]') {
   $fileId = json_decode(@@contractFile)[0];
}

If no file was selected, then @@contractFile_label will be set to '[]' and @@contractFile will be undefined. To deal with this, use isset() to check whether @@contractFile is defined before trying to access it.

With the ID of the uploaded file, other information about the file can be looked up using the AppDocument::Load()method. See Getting file info in v.3.0.1.8 and later below.

Storage of Files in Grids

When a file field is placed in a grid, then a file can be selected for each row in the grid to be uploaded when the Dynaform is submitted. Each file is stored separately in the server's file system and a separate record is created for each file in the APP_DOCUMENT table. The only difference from a normal file field is that the APP_DOCUMENT.APP_DOC_FIELDNAME field will contain 'grid-variable_row-number_file-name'.

For example, a grid whose variable is named "receipts" is submitted and it has three rows with a file field named "receiptFile". The following information about the three files might be stored in the APP_DOCUMENT table:

mysql> select APP_DOC_UID, DOC_VERSION, APP_UID, DOC_UID, APP_DOC_TYPE, APP_DOC_INDEX, APP_DOC_FIELDNAME from APP_DOCUMENT;
APP_DOC_UIDDOC_VERSIONAPP_UIDDOC_UIDAPP_DOC_TYPEAPP_DOC_INDEXAPP_DOC_FIELDNAME
9981562705718050e816959058033346 1 2490631975717ff351ccda1005474345 -1 ATTACHED 1 receipts_1_receiptFile
9208148915718050e921ba1095027176 1 2490631975717ff351ccda1005474345 -1 ATTACHED 2 receipts_2_receiptFile
6366198845716e982128ba0053902036 1 3202231885716e94385eca5078684093 -1 ATTACHED 3 receipts_3_receiptFile

Note: If a grid containing a file field doesn't have an associated array variable, then any selected files in the grid will not be saved when the Dynaform is submitted.

Unfortunately, ProcessMaker currently does not save the filenames of the selected files in the grid's case variable when a grid containing files is submitted. The only way to find the filenames of the files in a grid is to do a search in the APP_DOCUMENT table for the case ID and for APP_DOC_FIELDNAME, which contains the name of the grid variable and the name of the file field in the grid used to get the file's ID in the APP_DOC_UID field. With the file's ID, its filename can be found by querying the CONTENT table or by calling the AppDocument::Load() method.

The following trigger example creates an array of the filenames uploaded in the current case to a grid whose variable is named "clientList" and its file field is named "contractFile":

$caseId    = @@APPLICATION;
$gridVar   = 'clientList';
$fileField = 'contractFile';
$aFiles    = array();
$query = "SELECT C.CON_VALUE AS FILENAME, AD.* FROM CONTENT C, APP_DOCUMENT AD
   WHERE AD.APP_UID='$caseId' AND APP_DOC_FIELDNAME LIKE '{$gridVar}_%_{$fileField}' AND
   AD.APP_DOC_STATUS = 'ACTIVE' AND AD.APP_DOC_UID = C.CON_ID AND
   C.CON_CATEGORY = 'APP_DOC_FILENAME' ORDER BY AD.APP_DOC_FIELDNAME"
;
$results = executeQuery($query);

if (is_array($results)) {
   for ($i=0; $i < count($results); $i++) {
      $aFiles[] = $results[$i]['FILENAME'];
   }
}

Accessing files with PHP

Link to file

If a file was uploaded to a File field that isn't associated with an Input Document, then the next time that the File field is displayed in a case, there will be link(s) below the File field to the file(s) that were previously uploaded to the field. However, ProcessMaker currently has a bug that prevents File fields that are associated with Input Documents from displaying link(s) to previously uploaded files(s).

Trigger code can be used to look up a file that was uploaded to a File field in the database and construct its URL to download it in a subsequent Link field in a Dynaform. In this example, the "name" of the File field is "receiptFile". The following trigger code uses the filename of the uploaded file in the @@receiptFile_label variable to look up the file in the database so it can create the URL and assign it to the @@receiptUrl variable. It also looks up the filename of this file and assigns it to the @@receiptFilename variable.

$fileField = 'receiptFile'; //set to name of the file field
$aReceipt = json_decode(@@receiptFile_label);
@@receiptFilename = empty($aReceipt) ? '' : $aReceipt[0];
@@receiptUrl = '';

if (!empty(@@receiptFilename)) {
   $caseId = @@APPLICATION;  //ID of the current case
   //Use ORDER BY APP_DOC_INDEX DESC to get the last file uploaded to the File field
   $query = "SELECT APP_DOC_UID, DOC_VERSION FROM APP_DOCUMENT
      WHERE APP_UID='$caseId' AND APP_DOC_FIELDNAME='$fileField' AND
      APP_DOC_STATUS = 'ACTIVE' ORDER BY APP_DOC_INDEX DESC"
;
   $results = executeQuery($query) or die("Error in query: $query");

   if (is_array($results) and count($results) > 0) {
      @@receiptUrl = '../cases/cases_ShowDocument?a=' . $results[1]['APP_DOC_UID'] .
         '&v='. $results[1]['DOC_VERSION'];
   }
}

Set this trigger to fire after the Dynaform containing the File field. Then add a Link field to a subsequent Dynaform. In the properties of that link field, set the display text property to @@receiptFilename and the href property to @@receiptUrl.

Link to Files in Grids

When a grid contains a file field, files can be uploaded for each row in the grid. However, if that same grid is redisplayed in a subsequent Dynaform, the uploaded files will not be displayed in the grid.

This example shows how to get around this problem by displaying links to the uploaded files in a second grid.

First, create the first Dynaform where the user will upload files. Inside this Dynaform, place a grid with the name and variable "Documents". Inside this grid place a file control named "Receipts".

Then, create the second Dynform to display the file links. Inside this Dynaform place a grid with the ID and name "FilesList" with the following controls:

  • A textbox with ID "fileName",
  • A link control with ID "fileLink",
  • A textbox with ID "uploader",
  • A datetime control with ID "date".

Once done, create the following trigger that is set to fire BEFORE the second Dynaform:

$caseId = @@APPLICATION;
$query = "SELECT D.*, C.CON_VALUE FROM CONTENT C, APP_DOCUMENT D
   WHERE D.APP_DOC_UID = C.CON_ID AND D.APP_UID = '$caseId' AND
   C.CON_CATEGORY =  'APP_DOC_FILENAME' "
;
$result = executeQuery($query);
$dataGrid = array();
$i = 1;
foreach ($result as $row) {
   $server = (G::is_https() ? 'https://':'http://') . $_SERVER['SERVER_NAME'] .':'. $_SERVER['SERVER_PORT'];
   $inputDocPath = $server . '/sys' . @@SYS_SYS .'/'. @@SYS_LANG .'/'. @@SYS_SKIN .
      '/cases/cases_ShowDocument?a='. $row['APP_DOC_UID'];
   $aUser = userInfo($row['USR_UID']);
   $uploader = $aUser['firstname'] .' '. $aUser['lastname'] .' ('. $aUser['username'] . ')';

   $dataGrid[$i] = array(
      'fileName' => $row['CON_VALUE'],
      'fileLink' => $inputDocPath,
      'uploader' => $uploader,
      'date'     => $row['APP_DOC_CREATE_DATE'],
   );
   $i++;
}

if (is_array($dataGrid) && count($dataGrid) > 0) {
        @=FilesList = $dataGrid;
}

The query used in the trigger searches all the files uploaded using the control in the current case:

SELECT D. * , C.CON_VALUE
FROM CONTENT C, APP_DOCUMENT D
WHERE D.APP_DOC_UID = C.CON_ID
AND D.APP_UID = '".@@APPLICATION."'
AND C.CON_CATEGORY =  'APP_DOC_FILENAME'
AND C.CON_LANG = '".@@SYS_LANG."'"

When a case is run, the files that were uploaded in the first Dynaform grid:

Will be listed with a link to be downloaded, the username of the user who uploaded the file and the date when the file was uploaded in the second Dynaform grid:

To see a process that demonstrates how to use this code, download and import this sample process.

Getting File Information

It is much easier to get information about a file uploaded in a File control because a variable is created that holds an array with the file's unique ID in a JSON string. See Variable Storage above. This trigger example shows how to use the AppDocument::Load() method to get information about the uploaded file and construct a URL to download the file and the path to open the file.

if (isset(@@contractFile) and @@contractFile != '[]') {
    $fileId = json_decode(@=contractFile)[0];
    $d = new AppDocument();
    $aFile = $d->Load($fileId); //get most recent version of file
    $aUser = userInfo($aFile['USR_UID']);
    @@fileUploader = "{$aUser['firstname']} {$aUser['lastname']} ({$aUser['username']})";
    @@filename = $aFile['APP_DOC_FILENAME'];
    @@fileComment = $aFile['APP_DOC_COMMENT'];
    @@dateUploaded = $aFile['APP_DOC_CREATE_DATE'];
    //for email and output document templates:
    @@fileUrl  = "http://{$_SERVER['SERVER_ADDR]}:{$_SERVER['SERVER_PORT']}/sys" . @@SYS_SYS .
                    "/en/neoclassic/cases/cases_ShowDocument?a=$fileId&v={$aFile['DOC_VERSION']}";
    //for links in DynaForms:
    @@fileRelativeUrl  = "../cases/cases_ShowDocument?a=$fileId&v={$aFile['DOC_VERSION']}";
    //path where file is stored on server
    $g = new G();
    @@filePath = PATH_DOCUMENT . $g->getPathFromUID($aFile["APP_UID"]) . PATH_SEP . $fileId .
         '_' . $aFile['DOC_VERSION'] . '.' . pathinfo(@@filename, PATHINFO_EXTENSION);
}

The variables @@fileUploader, @@filename, @@fileComment, @@dateUploaded and @@fileUrl can be used in a template file for an email or Output Document, or can be the variables associated with controls in a Dynaform. To display a link in a Dynaform to download the file, place @@fileUrl in the srcproperty (used to be named href) of the Link control. See Manipulating Links in Triggers.