Overview

The Multiple File control, which was added in version 3.1, allows more than one file to be uploaded and attached to the current case. To select and upload files, click on the control's "Choose Files" button. The dialog box to select the files varies according to browser. After being selected, the file will be listed below the field. The process of uploading files is asynchronous, meaning that it starts as soon as the user selects a file. This makes it possible to save time at the time of submitting the form. The icon of this control in the toolbar of the designer is the following:

Warning: The Multiple File Uploader control is not supported in Web Entries or External Registration, because it requires a case to be already created in ProcessMaker

Inside the designer that the control is added, located and configured. It's represented by the following figure:

While designing a Dynaform or Preview Mode, it is not possible to upload any file but it is possible to have a preview of how is going to be listed.

This control has a progress bar to review how long is taking to upload a file.

Users can attach as many files as necessary to the Dynaform. ProcessMaker desktop version allows to pick multiple files at the same time. When running a case or previewing a Dynaform, it is displayed as follows:

Properties

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

Type multipleFile (Read Only)
Variable

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

  • Multiple 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.

Label The label of the control
Input Document Used to link an Input Document to the control.
Required By checking this option, an asterisk is added in 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 if there is a file attached to the control, and not if the current user attaches a new file.

File extensions

Set in this property the validation of the file extensions. 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

Validate 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 edition when it is rendered.
  • view: the control can only be viewed when it is rendered. The content can’t be edited.
  • disabled: the control is displayed as disabled. The control is displayed in gray in order to indicate the disabled mode. The content can't be edited either.

File Extensions

The "File extensions" property defines the allowed extensions of the files that can be uploaded in the Multiple File Uploader field:

The allowed extensions are defined in the format filename.extension. Use * (asterisk) as a wildcard. * alone would allow 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 would allow only image files.

For example, if only Plain text files may be attached to the file control, then define this property as *.txt. When running cases, the File control dialog will indicate what type of file can be uploaded:

If a file named TextLetter.txt is uploaded, then the file control will validate it the DynaForm is submitting.

If a file with a different extension is attached, a validation error message is shown. Notice that even if a file is modified to have the allowed file extension, the multiple file control will check the real file type and will display the following message if the file is not allowed.

Considerations:

  • For multiple file fields which 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 fields 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 fields only accepts some types of extensions and a file is attached then, the validation passes unless the user attaches a file with a "no valid" extension. In that case, a message is shown with a warning that indicates that the file extension is not supported. Nevertheless, if the fields only accepts some types of extensions and no file is attached then, the validation passes.
  • For required Multiple file fields
    • If the field accepts all file extensions (*) and when running cases, no file is attached then, the validation FAILS (because of the Required Field) and the form can NOT be sent nor submitted.

    • If the field accepts all file extensions and when running cases, a file with that extension is attached then, the validation PASSES unless it has the size limit, in that case another validation, explained in the next property, is evaluated.

    • If the multiple fields only accepts some types of extensions and no file is attached then, the validation FAILS (because of the Required Field) and the form can NOT be sent nor submitted.
    • If the multiple fields 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 a "no valid" extension. In that case, a error message is shown 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 which is required and then the form is submitted to the next step but then the user goes back to the previous step, the file already submitted is shown as a link under the Multiple File Control.

      If the field is required, and the user removes all the files attached, it is necessary to upload at least one again.

Multiple File Uploader field in a Grids

Multiple File Uploader field in grids have the same considerations as explained above, but in cases when the grid is not associated with any grid variable and a valid file is attached and sent, the new date is not inserted in the data base. This is because the grid MUST have a associated variable so the data will be correctly saved.

The Multiple File Uploader control has a different interface on Grids. To upload a file, click on the green icon.

A new dialog window will be displayed to upload the files.

Click on the "Choose Files" button to upload multiple files. To edit a file, just delete it and upload it again. Once done, close the dialog.

The uploaded files will be listed in the Multiple File Uploader field inside the grid.

Max File Size

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

If set to zero (0), then the file size is unlimited.

When running a case, the multiple 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 control, the progress bar of the file will stay in red color.

Considerations:

  • For Multiple File fields which are NOT required
    • If the max file size limit validation for the file attached FAILS, the file is not uploaded in the field. Nevertheless, as the field is not required the form can be submitted or sent.
  • For required Multiple File fields
    • If the max file size limit validation for the file attached FAILS, the file is not uploaded in the field and the form CAN NOT be submitted nor sent.
  • Multiple File Uploader field in a grid
    • Files in grids have the same considerations as explained previously, but in cases when the grid is not associated to any grid and a valid file is attached and sent, the new date is not inserted in the data base. This is because the grid MUST have a variable associated for the data to be sent correctly.

Size Unit

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

Multiple File Uploader Control Example

For this example add a "fileupload" control by dragging and dropping it onto the Dynaform Designer, from the Web Controls panel. The result of adding this kind of control is shown in the image below.

Immediately after adding the control a "Create Variable" window will appear. A variable can be created directly from this window or select a variable already created from the process variables. Also a variable can be created using the variables interface by clicking on the Variables button. For this example a completely new variable will be created so stay on the "Create Variable" option(radio button). Maintain the "Variable Name" as "multipleFileVar001" 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 configuration for the variable.

Once displayed the "Settings" option will change depending on the control that has been aggregated. For example, the "multiplefile" control only has one setting which is "Type". The "Type" setting has only one option that is "Multiple File". To learn how to assign an Input Document, read this documentation. Then on the "Create Variable" window click on the "Save" button to finish this configuration.

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

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

The "Create Variable" window will appear where a variable can be create with the "Create variable" radio button or select a new one from the "Select variable" radio button. Once a variable is chosen the "variable data type" and the "id" properties will gain the name of the variable added.

Now, the "id" property can be used with JavaScript code. To do so click on the light grey 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 an editor.

On the javascript editor add code to set the label of the control, read this section for more information. Use one of the functions mentioned in this section. For this example, add the following code:

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

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

The following property is the "Name" property which is an HTML Field name. It is possible to add a name to some controls managed inside the designer. By default, the control with this property has the same name as the ID set by default. 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 in the property.

Continuing on, the "label" property will change the label of the control which will be displayed when rendered.

For the "required" property there is only a checkbox available. When checked an asterisk is added next to the control to indicate that the field is required and the form won't be able to move into the next one until the field is properly filled.

Finally, the "display mode" control will have different effects when rendering a case. Use the illustration below as guide of the properties functionality.

Associating an Input Document with a File

It is possible to associate an Input Document with a Multiple File Uploader field inside a DynaForm by going to the "Multiple File" control properties. This means that files uploaded to a Multiple File Uploader field in a DynaForm can be displayed at a later point inside an Input Document step. One advantage of associating a these fields with an Input Document, is that the Input Document interface can be used to view all the files uploaded (and delete files and add new versions if the user has the Process Permissions and versioning is enabled). Another advantage is that Input Documents all the uploaded file to have tags and to be placed in a specified folder under Home > Documents, so it is easier to later find the uploaded files.

To associate an Input Document with a Multiple File Uploader field, it is very recommended to first create the Input Document in the project.

Then, simply click on the underlined ellipsis as seen in the image below.

A new "Input Documents" window will appear. Select the available Input Document by clicking on it.

Uploading files to an Input Document through a Multiple File Uploader field in a DynaForm is useful if needing to upload more than one file at the same time to an Input Document. If needing to ensure that the user uploads a file to an Input Document, then make the Multiple File Uploader field required.

It is possible to associate Multiple File Uploader fields in a grid to an Input Document. If needing to upload more than one file to an Input Document, then a normal Input Document step should be used.

After associating the Multiple File variable with the Input Document, the Multiple File properties will be respect over the Input Document properties.

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, which 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 to manipulate Multiple 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 for files which 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 by the file control, but there can be multiple files which have already been 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 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 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.

Structure of Multiple File Uploader Controls

A Multiple File Uploader control consists of:

  • A visible <button> with the ID of the multiple file control, which is clicked to select a file to be uploaded. After a file is selected, the name of the selected file is displayed under this button.
  • A hidden field with the ID "form[id]" for each file selected, where the selected file is temporarily stored.
  • A hidden input field with the ID "form[id_label]", which holds an array of the files which 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>
  <div id="multipleFileVar001" name="field-multipleFileVar001"
     class="pmdynaform-field-multipleFile pmdynaform-edit-multipleFile  form-group col-sm-12 col-md-12 col-lg-12  pmdynaform-field">
    <div class="row">
      <label for="multipleFileVar001" class="col-md-2 col-lg-2 control-label pmdynaform-label">
        <span data-toggle="tooltip" data-placement="bottom" class="textlabel">multipleFile</span>
        <span class="pmdynaform-field-required">*</span>
      </label>
      <div class="col-md-10 col-lg-10 pmdynaform-field-control">
        <div class="pmdynaform-multiplefile-control">
          <button type="button" class="btn btn-uploadfile">Choose Files</button>
          <input type="file" multiple="multiple" accept="" style="display:none">
        </div>
      </div>
    </div>
    <div class="pmdynaform-multiplefile-box"><div class="multiplefile-row row">
      <div class="multiplefile-container col-xs-12">
        <div class="multiplefile-icon col-xs-1">
          <span class="multiplefile-icon">
            <i class="fa fa-file-image-o" aria-hidden="true"></i>
          </span>
        </div>
        <div class="pm-multiplefile-download col-xs-8">
          <div class="multiplefile-title">
            <div> 94f5432c6216e8141daa5980891fc766.jpg</div>
          </div>
        </div>
        <div class="multiplefile-buttons col-xs-3">
          <div class="multiplefile-button-delete col-xs-5">
            <i class="fa fa-trash" aria-hidden="true"></i>
          </div>
          <div class="multiplefile-button-download col-xs-5">
            <a href="http://192.168.51.113/sysdani31/en/{skin}/cases/cases_ShowDocument?a=86931799257ec16530e59c7069364091&amp;v=1">
              <i class="fa fa-download" aria-hidden="true"></i>
            </a>
            <a></a>
          </div>
          <a>
            <div class="multiplefile-button-pencil col-xs-5" style="display: none">
              <i class="fa fa-pencil" aria-hidden="true"></i>
            </div>
          </a>
        </div>
        <a></a>
      </div>
    </div>
    <div class="multiplefile-row row">
      <div class="multiplefile-container col-xs-12">
        <div class="multiplefile-icon col-xs-1">
          <span class="multiplefile-icon">
            <i class="fa fa-file-image-o" aria-hidden="true"></i>
          </span>
        </div>
        <div class="pm-multiplefile-download col-xs-8">
          <div class="multiplefile-title">
            <div> 3c5c332d7f8018d4447a771dcb284447.jpg</div>
          </div>
        </div>
        <div class="multiplefile-buttons col-xs-3">
          <div class="multiplefile-button-delete col-xs-5">
            <i class="fa fa-trash" aria-hidden="true"></i>
          </div>
          <div class="multiplefile-button-download col-xs-5">
            <a href="http://192.168.51.113/sysdani31/en/{skin}/cases/cases_ShowDocument?a=21786185157ec168f6d4e05077370210&amp;v=1">
              <i class="fa fa-download" aria-hidden="true"></i>
            </a>
            <a></a>
          </div>
          <a>
            <div class="multiplefile-button-pencil col-xs-5" style="display: none">
              <i class="fa fa-pencil" aria-hidden="true"></i>
            </div>
          </a>
        </div>
        <a></a>
      </div>
    </div>
  </div>
</div>
<input name="form[multipleFileVar001][0][appDocUid]" type="hidden" value="86931799257ec16530e59c7069364091">
<input name="form[multipleFileVar001][0][name]" type="hidden" value="94f5432c6216e8141daa5980891fc766.jpg">
<input name="form[multipleFileVar001][0][version]" type="hidden" value="1">
<input name="form[multipleFileVar001][1][appDocUid]" type="hidden" value="21786185157ec168f6d4e05077370210">
<input name="form[multipleFileVar001][1][name]" type="hidden" value="3c5c332d7f8018d4447a771dcb284447.jpg">
<input name="form[multipleFileVar001][1][version]" type="hidden" value="1">
</div>

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

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

File Storage

When a file is uploaded to a 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 by default is named "workflow" 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. 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 for the case-document, which is stored in the APP_DOCUMENT.APP_DOC_UID field in the database.
  • VERSION is the document version number which is always set to 1, except when the Multiple file Uploader field is associated with an Input Document which has enabled versioning and the user has uploaded a new version of the file (which field fields don't allow). The 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_1\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 would contain 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 would generate 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 which contains a Multiple File Uploader field is submitted, a new record is created about the uploaded file in the APP_DOCUMENT table in the database, which contains the following fields:

  • APP_DOC_UID: The unique ID for 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 which 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 when the file was uploaded.
  • DOC_UID: The unique ID of the Input Document which holds the file, if the Multiple File Uploader field is associated with an Input Document. An unassociated Multiple File Uploader field, 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 Multiple File Uploader 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.
  • FOLDER_UID: The unique ID of the folder where the file located in the graphical interface under Home > Documents. If the 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 an plugin to manage the files.
  • APP_DOC_TAGS: If the field is associated with an Input Document, then 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 an unassociated field, then set to NULL.
  • APP_DOC_STATUS: The status of the file, which is either 'ACTIVE' or 'DELETED'. Note that Multiple File Uploaderfields don't provide a way to delete uploaded files, but the file could be deleted by a user who has the PM_FOLDERS_ADD_FILE permission in his/her role and goes to Home > Documents. It can also be deleted if the field is associated with an Input Document which 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 field where the file was uploaded. If uploaded in a Multiple 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 Multiple File field has the name "contractFile". If the file was uploaded in an Input Document step (not a Multiple File Uploader field), then it is set to NULL.
  • APP_DOC_DRIVE_DOWNLOAD: Serialized information which is always set to 'a:0:{}'.

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

For example, the database has 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 with the query: SELECT CON_VALUE AS FILENAME FROM CONTENT WHERE CON_ID='XXXXXXXXXXXXXXXXXXXXXXX' AND CON_CATEGORY='APP_DOC_FILENAME'

Warning: If a user uploads a file into the multiple file control but the Dynaform containing the control is not submitted (like when closing the browser, refreshing the frame or leaving the form without saving), the files uploaded into the multiple file control won't be related to the assigned variable and won't be visible in next steps of the process. This behavior is a known issue that will be fixed in upcoming ProcessMaker versions.

Storage of files in grids

When a Multiple File Uploader field is placed in a grid, then a files 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 Multiple File Uploader 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 Multiple File field named "receiptFile", then the following information might be stored in the APP_DOCUMENT table about the three files:

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 grid field doesn't have an associated array variable, then any selected files in the grid will not saved when the DynaForm is submitted.

The filenames of the selected files in the grid's case variable when a grid containing files is submitted can be found doing 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 Multiple File field in the grid in order 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.

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 Multiple 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 Multiple Files with PHP

When the user selects files in a Multiple File control, the files are immediately uploaded and the files are saved in the file system of the server where ProcessMaker is installed. In addition, the files are stored in the APP_DOCUMENT table in the database. When the DynaForm holding a Multiple File control is submitted, a case variable is created for the Multiple File control with information about the uploaded files in an array of arrays.

Accessing the MultipleFile case variable

MultipleFiles are stored in a case variable with the following format: @=MultipleFileVariable = array( array( "appDocUid" => 'Unique_ID_AppDocument', "name" => 'filename.ext', "version" => "1" ), ... );

The version number will always be "1", unless the multipleFile field is associated with an Input Document which has the Enable Versioning option selected.

For example, the following MultipleFile associated with the @=multipleContractFiles variable has two files in it:

@=multipleContractFiles = array(
   array(
      "appDocUid" => "6994902925858ad7e22e275057848393",
      "name"      => "CateringServiceContract.docx",
      "version"   => "1"
   ),
   array(
      "appDocUid" => "9230004935858ad85ed6a21022202980",
      "name"      => "NewServiceContract.pdf",
      "version"   => "1"
   )
);

To obtain the ID and filename of the first file in the multipleContractFiles control, create a trigger which is set to execute after the Dynaform holding the multipleContractFile control, with the following PHP code:

if (isset(@=multipleContractFiles) and !empty(@=multipleContractFiles)) {
   @@firstFileId = @=multipleContractFiles[0]['appDocUid'];
   @@firstFilename = @=multipleContractFiles[0]['name'];
}

Before trying to access a Multiple File variable, it is a good idea to use isset() to check if the Multiple File variable was defined (in case the user used the Steps menu to skip the DynaForm) and to use empty() to check whether at least one file was uploaded.

In contrast, if one of these files was uploaded in traditional File control which can only hold one file, it might be stored in the following case variables which are JSON strings:

@@contractFile = '["6994902925858ad7e22e275057848393"]'; //variable only set if a file was selected
@@contractFile_label = '["CateringServiceContract.docx"]';

The unique ID and filename of the selected file in the File control can be obtained in this way, using the json_decode() function:

//if a selected file in the File control:
if (isset(@@contractFile) and @@contractFile != '[]') {
   $fileId = json_decode(@@contractFile)[0];
   $filename = json_decode(@@contractFile_label)[0];
}

Adding single Files to MultipleFiles

The file which is uploaded in a traditional File control can be transferred to a MultipleFile control. In the following example, a DynaForm contains a File control associated with the @@contractFile variable, where one file can be uploaded.

The file which was uploaded by the user is then transferred to a MultipleFile control located in a second DynaForm:

A trigger which is fired before the second DynaForm, copies the information about the uploaded file from the first DynaForm and adds it to the MultipleFile control associated with the @=multipleContractFiles variable. The following trigger code first checks whether a file was selected in the File control and then gets its unique ID and filename. It then checks whether the file as already been added to the MultipleFile control. If not, it adds an associative array of information about the file to the MultipleFile control:

//if a selected file in the File control:
if (isset(@@contractFile) and @@contractFile != '[]') {
   $fileId = json_decode(@@contractFile)[0];
   $filename = json_decode(@@contractFile_label)[0];
   //if the multipleFile doesn't yet exist, then create it:
   if (!isset(@=multipleContractFiles)) {
      @=multipleContractFiles = array();
   }
   //check whether the file as already been added:
   $addFile = true;
   foreach (@=multipleContractFiles as $aFile) {
      if ($aFile['appDocUid'] == $fileId) {
         $addFile = false;
         break;
      }
   }
   if ($addFile) {
      //add an additional file:
      @=multipleContractFiles[] = array(
        "appDocUid" => $fileId,
        "name"      => $filename,
        "version"   => "1"
      );
   }
}

To test a sample process which adds the selected file in a File control to a MultipleFile control, download and import the Add_File_to_MultipleFile_control-1.pmx process (right click on link and select "Save Link As").

Clearing all files in a Multiple File control

To clear all the files in a Multiple File control in a trigger, use for to loop through all the files in the Multiple File variable. For each file, use the AppDocument::Remove() method to mark the file as deleted in the database and unlink() to delete the file from the server's file system. Then, set the Multiple File variable to array() (an empty array) to remove its contents.

For example, if the variable associated with the Multiple File control is named "productSpecFiles", the following trigger will delete the files in the control if the "cancelProduct" checkbox is marked.

if (isset(@=cancelProduct) and @@cancelProduct == array(1) and
   isset(@=productSpecFiles) and !empty(@=productSpecFiles)) {
   $ad = new AppDocument();
   for (@=productSpecFiles as $aFile) {
      //mark as deleted in the APP_DOCUMENT table in database:
      $ad->remove($aFile['appDocUid'], $aFile['version']);
      //construct path to the stored file in the server's file system:
      $ext = pathinfo($aFile['name'], PATHINFO_EXTENSION);
      $g = new G();
      $path = PATH_DOCUMENT . $g->getPathFromUID(@@APPLICATION) . PATH_SEP .
         $aFile['appDocUid'] . '_' . $aFile['version'] . '.' . $ext;
      //delete file on server's file system:
      unlink($path);
   }
   //clear files in Multiple File variable
   @=productSpecFiles = array();
}