diff --git a/core/includes/file.inc b/core/includes/file.inc index b217edb..826262e 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -1023,16 +1023,14 @@ function file_unmanaged_delete_recursive($path, $callback = NULL) { } /** - * Saves a file upload to a new location. + * Saves file uploads to a new location. * - * The file will be added to the {file_managed} table as a temporary file. + * The files will be added to the {file_managed} table as temporary files. * Temporary files are periodically cleaned. Use file_usage()->add() to register * the usage of the file which will automatically mark it as permanent. * * @param $source - * A string specifying the filepath or URI of the uploaded file to save. - * @param $delta - * The delta of the file being uploaded. Used in conjunction with #multiple. + * A string specifying the filepath or URI of the uploaded files to save. * @param $validators * An optional, associative array of callback functions used to validate the * file. See file_validate() for a full discussion of the array format. @@ -1046,6 +1044,9 @@ function file_unmanaged_delete_recursive($path, $callback = NULL) { * A string containing the URI $source should be copied to. * This must be a stream wrapper URI. If this value is omitted, Drupal's * temporary files scheme will be used ("temporary://"). + * @param $position + * Delta of a file of only one file needs to be saved. All files + * will be saved if set to FALSE (default). * @param $replace * Replace behavior when the destination file already exists: * - FILE_EXISTS_REPLACE: Replace the existing file. @@ -1054,9 +1055,12 @@ function file_unmanaged_delete_recursive($path, $callback = NULL) { * - FILE_EXISTS_ERROR: Do nothing and return FALSE. * * @return - * An object containing the file information if the upload succeeded, FALSE - * in the event of an error, or NULL if no file was uploaded. The - * documentation for the "File interface" group, which you can find under + * Function returns array of files or a single file object if $position + * != FALSE. Each file object contains the file information if the + * upload succeeded or FALSE in the event of an error. Function + * returns NULL if no file was uploaded. + * + * The documentation for the "File interface" group, which you can find under * Related topics, or the header at the top of this file, documents the * components of a file entity. In addition to the standard components, * this function adds: @@ -1068,7 +1072,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE, static $upload_cache; // Return cached objects without processing since the file will have - // already been processed and the paths in _FILES will be invalid. + // already been processed and the paths in $_FILES will be invalid. if (isset($upload_cache[$source])) { if ($position === FALSE) { return $upload_cache[$source]; @@ -1244,17 +1248,10 @@ function file_save_upload($source, $validators = array(), $destination = FALSE, $files[$delta] = $file; } - // Add file to the cache. + // Add files to the cache. $upload_cache[$source] = $files; - if ($position === FALSE) { - return $files; - } - else { - return $files[$position]; - } - - return $files; + return $position === FALSE ? $files : $files[$position]; } /** diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc index 9dd0373..c9300c4 100644 --- a/core/modules/file/file.field.inc +++ b/core/modules/file/file.field.inc @@ -396,6 +396,39 @@ function file_field_widget_value($element, $input = FALSE, $form_state) { } /** + * Validation callback for upload element on file widget. Checks if + * user has uploaded more files than allowed. + * + * This validator is used only when cardinality not set to 1 or unlimited. + */ +function file_field_widget_multiple_count_validate($element, &$form_state, $form) { + $parents = $element['#array_parents']; + $values = NestedArray::getValue($form_state['values'], $parents); + + array_pop($parents); + $current = count(element_children(NestedArray::getValue($form, $parents))) - 1; + + $field = field_info_field($element['#field_name']); + $uploaded = count($values['fids']); + $count = $uploaded + $current; + if ($count > $field['cardinality']) { + $keep = $uploaded - $count + $field['cardinality']; + drupal_set_message( + t( + 'Field %field can hold only @max values. Only @count values were uploaded.', + array( + '%field' => $field['field_name'], + '@max' => $field['cardinality'], + '@count' => $keep) + ), + 'warning' + ); + $values['fids'] = array_slice($values['fids'], 0, $keep); + NestedArray::setValue($form_state['values'], $element['#array_parents'], $values); + } +} + +/** * Render API callback: Processes a file_generic field element. * * Expands the file_generic type to include the description and display fields. diff --git a/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php b/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php index e6973a6..9842ad6 100644 --- a/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php +++ b/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php @@ -197,6 +197,9 @@ public function formElement(array $items, $delta, array $element, $langcode, arr if (empty($element['#default_value']['fids'])) { $element['#description'] = theme('file_upload_help', array('description' => $element['#description'], 'upload_validators' => $element['#upload_validators'])); $element['#multiple'] = $this->field['cardinality'] != 0 ? TRUE : FALSE; + if ($this->field['cardinality'] != 1 && $this->field['cardinality'] != -1) { + $element['#element_validate'] = array('file_field_widget_multiple_count_validate'); + } } return $element;