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 Choose Files button of the control. The dialog box to select the files will vary according to browser. After being selected, the file will be listed below the field. The upload process is immediate, meaning that as soon as the user selects the file, a progress bar will show the percentage of the upload completed. It will turn green to indicate that the file has been completely uploaded to the ProcesssMaker server. This makes it possible to save time when 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

When the control is added to the Dynaform designer, the control field will look like the image below:

While designing a Dynaform or in preview mode, it is not possible to upload a file, but it is possible to preview how uploaded files will be listed.

This control has a progress bar that indicates how long a file will take to upload.

The desktop version of ProcessMaker allows users to attach multiple files to the Dynaform. When running a case or previewing a Dynaform, the Multiple File Uploader control field 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 about 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 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 verifies that there is a file attached to the control, but does not check if the current user had attached another a new file.

File extensions

Set the allowed file extensions in this property. 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 field can be edited by the end user when the Dynaform is rendered.
  • view: the control can only be viewed when it is rendered. The content can’t be edited.
  • disabled: the control field will be disabled and displayed in gray when the Dynaform is rendered. 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 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 allows 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, the file control will verify that it is a .txt file and allow the Dynaform to be submitted.

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 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 a 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 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 certain types of extensions and no file is attached, then the validation passes.
  • For required Multiple file fields
    • When running a case, if the field accepts all file extensions (*), and there is no file attached to the case, the validation will fail because the field is required and therefore the form cannot be submitted.

    • When running cases, if the field accepts all file extensions and a file is attached, then the validation PASSES unless it has a size limit; in that case another validation will be performed, as explained in the next property.

    • 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 nor 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, an 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 required field and 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 file again.

Multiple File Uploader Field in a Grid

Multiple File Uploader fields in grids have the same characteristics 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 data is not inserted into the database. This is because the grid MUST have an associated variable to correctly save the data.

The Multiple File Uploader control has a different appearance in 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 uploading files, 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 red.

Considerations:

  • For Multiple File fields that are NOT required
    • If the max file size limit validation for the file attached FAILS, the file is not uploaded to the field. Nevertheless, as the field is not required, the form can still 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 to the field and the form CAN NOT be submitted or sent.
  • Multiple File Uploader field in a grid
    • Files in grids have the same characteristics as explained previously, but in cases when the grid is not associated to a grid variable, and a valid file is attached and sent, the new data is not inserted into the database. This is because the grid MUST be related to a variable 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 image below shows what the control will look like when its rendered on the Dynaform.

Immediately after adding the control, the Create Variable window will appear. A variable can be created in this window, or can be selected from the existing process variables. A variable can also be created by clicking on the Variables button. A new variable will need to be created for this example, so stay in the Create/Select Variable window. Even though the variable name can be edited, keep it as "multipleFileVar001". Click on the underlined Settings option to display more variable configurations.

The options available in the setting change depending on the type of control. For example, the multiplefile control only has one setting: "Type". The Type setting has only one option, "Multiple File". To learn how to assign an Input Document, read this documentation. Then in the Create Variable window, click on the Save button to finish this configuration.

Click on the empty space in the control field to display its properties in the left side panel.

Another way to add a variable is by clicking on the underlined ellipsis next to the Variable property, as observed in the image.

The Create Variable window will appear, where a variable can be created or selected from existing variables. Once a variable is chosen, the Variable Data Type and the ID properties will be automatically filled in with the name of the variable.

The ID property can be used with JavaScript code. To add JavaScript to the ID property, click on the light grey border of the Dynaform (which is the space outside of the control fields) to display the Dynaform properties. When the properties are displayed, locate the javascript property and click on the edit... button to open the JavaScript editor.

In the JavaScript editor, add code to set the label of the control (read this section for more information). 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. By default, a control with this property has the same name 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 in the property.

Continuing on, the Label property changes the label of the control, which will be displayed in the control field when the Dynaform is rendered.

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 form won't be able to be submitted until the field is properly filled in.

The Display Mode property determines whether the control is editable, viewable, disabled or uses the same display mode set for the entire Dynaform. The image below shows what the control looks like in each view mode.

Attaching an Input Document File Using the Multiple File Uploader

It is possible to attach an Input Document to a Dynaform using the Multiple File Uploader field by going to the Multiple File control properties. This means that files uploaded to the Multiple File Uploader field in a Dynaform can be displayed at a later point in an Input Document step. One advantage of associating these fields with an input document, is that the Input Document interface can be used to view all the files uploaded. The user can also delete or add new versions of the files if they have the correct process permissions and versioning is enabled. Another advantage is that Input Documents allow the uploaded file to be tagged and placed into a specific folder under Home > Documents, so it is easier to find the uploaded files later.

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

Then, simply click on the underlined ellipsis in the Multiple File Uploader control properties 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 the Multiple File Uploader field in a Dynaform is useful for uploading more than one file at the same time to an Input Document. To ensure that the user uploads a file to an Input Document, make the Multiple File Uploader field required.

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 take precedence 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 in the Dynaform, 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 used 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 of the 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 listed 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 that have already been added to the Input Document.
jQuery("#fieldID").getLabel() Returns the control field's label, which is the text displayed above or to the left of the field to identify it in the Dynaform.
jQuery("#fieldID").setLabel("newLabel") Sets the control field's label, which is the text displayed above or to the left of the field to identify it in the Dynaform.

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 that have been previously uploaded to the Input Document associated with the Multiple File Uploader 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 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 Multiple File control 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, the ID is divided into a series of 4 subdirectories to avoid the 32K file limits of Linux's ext3 file system. In a trigger, the current case ID of the current case is stored in the @@APPLICATION system variable, or 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, which is always set to 1, except when the Multiple file Uploader field is related to an Input Document that has versioning enabled and the user has uploaded a new version of the file (which file 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_1\processmaker\shared\sites\workflow\files\905\262\500\57158b1b439014072150115\74863719957158b39af56d2076904431_1.png

In a trigger, the file 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 the examples above:

$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 Multiple File Uploader 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 of 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 Multiple File Uploader field is associated with an Input Document. If there is no Input Document associated to the 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 not associated 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 is 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). No longer used in ProcessMaker 3.
  • APP_DOC_TAGS: If the field is associated with an Input Document, then this field lists the tags for the Input Document, which are separated by commas. By default, all Input Documents have the 'INPUT' tag, but other custom tags can be defined. If not associated to an Input Document, then set to NULL.
  • APP_DOC_STATUS: The status of the file, which is either 'ACTIVE' or 'DELETED'. Note that Multiple File Uploader 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 in Home > Documents. It can also be deleted if the field is associated with an Input Document that is a step in a task and the user has been assigned the 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:{}'.

Additionally, records are added to the CONTENT table, which contains 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, 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 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". 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 multiple file field doesn't have an associated array variable, then the selected files in the grid will not saved when the Dynaform is submitted.

After the Dynaform is submitted, the filenames of the selected files in the grid's case variable 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, to get the file's ID in the APP_DOC_UID field. Using 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 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 saved in the file system of the server where ProcessMaker is installed. The files are also 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

The files uploaded to Multiple File controls 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 Documen that has the Enable Versioning option selected.

For example, the following Multiple File control 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 that is set to execute after the Dynaform holding the multipleContractFile control is submitted, 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 the case the user used the Steps menu to skip the Dynaform), and use empty() to check whether at least one file was uploaded.

In contrast, if one of these files was uploaded using a traditional File control, which can only hold one file, the Multiple File case variable 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 Multiple File Controls

A file that was uploaded to 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 that was uploaded by the user is then transferred to a Multiple File control located in a second Dynaform:

A trigger that 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 that 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 the link and select "Save Link As").

Clearing All Files in a Multiple File Control

To clear all the files in a Multiple File control using 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();
}