+/**
+ * Saves form file uploads.
+ *
+ * The files will be added to the {file_managed} table as temporary files.
+ * Temporary files are periodically cleaned. Use the 'file.usage' service to
+ * register the usage of the file which will automatically mark it as permanent.
+ *
+ * @param array $element
+ * The FAPI element whose values are being saved.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The current state of the form.
+ * @param null|int $delta
+ * (optional) The delta of the file to return the file entity.
+ * Defaults to NULL.
+ * @param int $replace
+ * (optional) The replace behavior when the destination file already exists.
+ * Possible values include:
+ * - FILE_EXISTS_REPLACE: Replace the existing file.
+ * - FILE_EXISTS_RENAME: (default) Append _{incrementing number} until the
+ * filename is unique.
+ * - FILE_EXISTS_ERROR: Do nothing and return FALSE.
+ *
+ * @return array|\Drupal\file\FileInterface|null|false
+ * An array of file entities or a single file entity if $delta != NULL. Each
+ * array element contains the file entity if the upload succeeded or FALSE if
+ * there was an error. Function returns NULL if no file was uploaded.
+ *
+ * @deprecated in Drupal 8.4.x, will be removed before Drupal 9.0.0.
+ * For backwards compatibility use core file upload widgets in forms.
+ *
+ * @internal
+ * This function wraps file_save_upload() to allow correct error handling in
+ * forms.
+ *
+ * @todo Revisit after https://www.drupal.org/node/2244513.
+ */
+function _file_save_upload_from_form(array $element, FormStateInterface $form_state, $delta = NULL, $replace = FILE_EXISTS_RENAME) {
+ // Get all errors set before calling this method. This will also clear them
+ // from $_SESSION.
+ $errors_before = \Drupal::messenger()->deleteByType(MessengerInterface::TYPE_ERROR);
+
+ $upload_location = isset($element['#upload_location']) ? $element['#upload_location'] : FALSE;
+ $upload_name = implode('_', $element['#parents']);
+ $upload_validators = isset($element['#upload_validators']) ? $element['#upload_validators'] : [];
+
+ $result = file_save_upload($upload_name, $upload_validators, $upload_location, $delta, $replace);
+
+ // Get new errors that are generated while trying to save the upload. This
+ // will also clear them from $_SESSION.
+ $errors_new = \Drupal::messenger()->deleteByType(MessengerInterface::TYPE_ERROR);
+ if (!empty($errors_new)) {
+
+ if (count($errors_new) > 1) {
+ // Render multiple errors into a single message.
+ // This is needed because only one error per element is supported.
+ $render_array = [
+ 'error' => [
+ '#markup' => t('One or more files could not be uploaded.'),
+ ],
+ 'item_list' => [
+ '#theme' => 'item_list',
+ '#items' => $errors_new,
+ ],
+ ];
+ $error_message = \Drupal::service('renderer')->renderPlain($render_array);
+ }
+ else {
+ $error_message = reset($errors_new);
+ }
+
+ $form_state->setError($element, $error_message);
+ }
+
+ // Ensure that errors set prior to calling this method are still shown to the
+ // user.
+ if (!empty($errors_before)) {
+ foreach ($errors_before as $error) {
+ \Drupal::messenger()->addError($error);
+ }
+ }
+
+ return $result;
+}
+