diff -u b/core/modules/media/src/Form/MediaBulkUploadForm.php b/core/modules/media/src/Form/MediaBulkUploadForm.php --- b/core/modules/media/src/Form/MediaBulkUploadForm.php +++ b/core/modules/media/src/Form/MediaBulkUploadForm.php @@ -14,7 +14,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * An AJAX multi-step form to bulk create media entities. + * An AJAX multi-step form to bulk create media entities from uploaded files. */ class MediaBulkUploadForm extends FormBase { @@ -89,13 +89,6 @@ public function __construct(EntityTypeManagerInterface $entityTypeManager, ElementInfoManagerInterface $element_info) { $this->entityTypeManager = $entityTypeManager; $this->elementInfo = $element_info; - - // Store media types the current user can create as early as possible. - $media_type_storage = $this->entityTypeManager->getStorage('media_type'); - $types = $media_type_storage->loadMultiple(); - $types = $this->filterTypesWithFileSource($types); - $types = $this->filterTypesWithCreateAccess($types); - $this->types = $types; } /** @@ -133,27 +126,40 @@ $form['progress'] = $this->getFormProgress($form_state); // Determine what step of the form we're on. switch ($this->step) { - case NULL: - $form = $this->buildUploadForm($form, $form_state); - break; - case 'select_media_type': - $form = $this->buildMediaTypeSelectionForm($form, $form_state); - break; + return $this->buildMediaTypeSelectionForm($form, $form_state); case 'show_media_form': - $form = $this->buildMediaForm($form, $form_state); - break; + return $this->buildMediaForm($form, $form_state); case 'finished': - $form = $this->buildFinishedForm($form, $form_state); - break; + return $this->buildFinishedForm($form, $form_state); + + default: + return $this->buildUploadForm($form, $form_state); } - return $form; } /** - * Returns a render array representing the form process. + * Returns media types which use files that the current user can create. + * + * @return \Drupal\media\MediaTypeInterface[] + * Media types that are valid for this form. + */ + protected function getTypes() { + // Cache results if possible. + if (!$this->types) { + $media_type_storage = $this->entityTypeManager->getStorage('media_type'); + $types = $media_type_storage->loadMultiple(); + $types = $this->filterTypesWithFileSource($types); + $types = $this->filterTypesWithCreateAccess($types); + $this->types = $types; + } + return $this->types; + } + + /** + * Gets a render array representing the current progress of the bulk upload. * * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state. @@ -164,6 +170,7 @@ protected function getFormProgress(FormStateInterface $form_state) { $element = []; if ($this->originalFileCount > 1 && $this->step !== 'finished') { + // Determine how many files are left to process. $remaining = ($this->originalFileCount - count($this->files)); $element = [ '#theme' => 'progress_bar', @@ -189,11 +196,11 @@ * The form render array. */ protected function buildUploadForm(array $form, FormStateInterface $form_state) { - $element_info = $this->elementInfo->getInfo('managed_file'); - $upload_validators = $this->mergeUploadValidators($this->types); + $process = $this->elementInfo->getInfoProperty('managed_file', '#process'); + $upload_validators = $this->mergeUploadValidators($this->getTypes()); $form['upload'] = [ '#type' => 'managed_file', - '#process' => array_merge($element_info['#process'], ['::processUpload']), + '#process' => array_merge($process, ['::processUpload']), '#upload_validators' => $upload_validators, '#multiple' => TRUE, ]; @@ -222,11 +229,11 @@ 'callback' => '::updateFormCallback', 'wrapper' => 'media-build-upload-form-wrapper', ]; - // Hide the Managed File element's table display - we don't use it. - $element['remove_button']['#access'] = FALSE; + // Remove the Managed File element's table display - we don't use it. + unset($element['remove_button']); foreach ($element['#value']['fids'] as $fid) { if (isset($element['file_' . $fid])) { - $element['file_' . $fid]['#access'] = FALSE; + unset($element['file_' . $fid]); } } return $element; @@ -246,7 +253,6 @@ $this->files = $this->entityTypeManager->getStorage('file')->loadMultiple($fids); $this->originalFileCount = count($this->files); $this->prepareForNextFile($form_state); - $form_state->setRebuild(); } /** @@ -262,9 +268,9 @@ */ protected function buildMediaTypeSelectionForm(array $form, FormStateInterface $form_state) { /** @var \Drupal\file\FileInterface $file */ - $valid_types = $this->filterTypesThatAcceptFile($this->currentFile, $this->types); + $valid_types = $this->filterTypesThatAcceptFile($this->currentFile, $this->getTypes()); $form['title'] = [ - '#markup' => t('
Select media type to create with @file
', [ + '#markup' => t('Select which media type to create for @file
', [ '@file' => $this->currentFile->label(), ]), ]; @@ -331,6 +337,8 @@ '#weight' => $form['subform']['actions']['submit']['#weight'], ]; // Replace relative (::*) callbacks in the media form. + // \Drupal\Core\Entity\ContentEntityForm adds #entity_builders + // \Drupal\Core\Entity\EntityForm adds #process foreach (['#process', '#entity_builders'] as $key) { foreach ($form['subform'][$key] as &$callback) { if (is_string($callback) && substr($callback, 0, 2) == '::') { @@ -369,7 +377,6 @@ $media->save(); $this->newMedia[] = $media; $this->prepareForNextFile($form_state); - $form_state->setRebuild(); } /** @@ -380,8 +387,8 @@ * @param \Drupal\media\MediaTypeInterface $type * A media Type. * - * @return \Drupal\Core\Entity\EntityFormInterface|false - * A media form object, or FALSE if there was an error. + * @return \Drupal\Core\Entity\EntityFormInterface + * A media form object. */ public function createMediaForm(FileInterface $file, MediaTypeInterface $type) { // Move the temporary file to the correct destination. @@ -415,7 +422,7 @@ // Get the next file and update the form state. $this->currentFile = array_shift($this->files); // Determine if we can skip the media type selection page. - $valid_types = $this->filterTypesThatAcceptFile($this->currentFile, $this->types); + $valid_types = $this->filterTypesThatAcceptFile($this->currentFile, $this->getTypes()); if (count($valid_types) === 1) { $this->prepareForMediaForm($form_state, reset($valid_types)); } @@ -531,7 +538,7 @@ * Access callback to check that the user can create file based media. */ public function access() { - return AccessResultAllowed::allowedIf(count($this->types))->mergeCacheMaxAge(0); + return AccessResultAllowed::allowedIf(count($this->getTypes()))->mergeCacheMaxAge(0); } } diff -u b/core/modules/media/src/MediaUploadTrait.php b/core/modules/media/src/MediaUploadTrait.php --- b/core/modules/media/src/MediaUploadTrait.php +++ b/core/modules/media/src/MediaUploadTrait.php @@ -3,6 +3,7 @@ namespace Drupal\media; use Drupal\file\FileInterface; +use Drupal\media\Plugin\media\Source\File as MediaFileSource; use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\file\Plugin\Field\FieldType\FileItem; @@ -31,16 +32,12 @@ * An array of media types that accept the file. */ protected function filterTypesThatAcceptFile(FileInterface $file, array $types) { - $valid_types = []; $types = $this->filterTypesWithFileSource($types); - foreach ($types as $type) { + return array_filter($types, function ($type) use ($file) { $validators = $this->getUploadValidatorsForType($type); $errors = file_validate($file, $validators); - if (empty($errors)) { - $valid_types[] = $type; - } - } - return $valid_types; + return empty($errors); + }); } /** @@ -53,14 +50,10 @@ * An array of media types that accept file sources. */ protected function filterTypesWithFileSource(array $types) { - $valid_types = []; - foreach ($types as $type) { - $source = $type->getSource(); - if (is_a($source, 'Drupal\media\Plugin\media\Source\File')) { - $valid_types[] = $type; - } - } - return $valid_types; + return array_filter($types, function ($type) { + /** @var \Drupal\media\MediaTypeInterface $type */ + return ($type->getSource() instanceof MediaFileSource); + }); } /** @@ -79,8 +72,16 @@ $types = $this->filterTypesWithFileSource($types); foreach ($types as $type) { $validators = $this->getUploadValidatorsForType($type); - $max_size = max($max_size, $validators['file_validate_size'][0]); - $extensions = array_unique(array_merge($extensions, explode(' ', $validators['file_validate_extensions'][0]))); + if (isset($validators['file_validate_size'])) { + $max_size = max($max_size, $validators['file_validate_size'][0]); + } + if (isset($validators['file_validate_extensions'])) { + $extensions = array_unique(array_merge($extensions, explode(' ', $validators['file_validate_extensions'][0]))); + } + } + // If no field defines a max size, default to the system wide setting. + if ($max_size === 0) { + $max_size = file_upload_max_size(); } return [ 'file_validate_extensions' => [implode(' ', $extensions)], @@ -89,39 +90,37 @@ } /** - * Gets upload validators for a given Media Type. + * Gets upload validators for a given media type. * * @param \Drupal\media\MediaTypeInterface $type - * A Media Type. + * A media type. * * @return array * An array suitable for passing to file_save_upload() or the file field * element's '#upload_validators' property. */ protected function getUploadValidatorsForType(MediaTypeInterface $type) { - $file_item = $this->getFileItemForType($type); - return $file_item->getUploadValidators(); + return $this->getFileItemForType($type)->getUploadValidators(); } /** - * Gets upload destination for a given Media Type. + * Gets upload destination for a given media type. * * @param \Drupal\media\MediaTypeInterface $type - * A Media Type. + * A media type. * * @return string * An unsanitized file directory URI with tokens replaced. */ protected function getUploadLocationForType(MediaTypeInterface $type) { - $file_item = $this->getFileItemForType($type); - return $file_item->getUploadLocation(); + return $this->getFileItemForType($type)->getUploadLocation(); } /** - * Creates a file item for a given Media Type. + * Creates a file item for a given media type. * * @param \Drupal\media\MediaTypeInterface $type - * A Media Type. + * A media type. * * @return \Drupal\file\Plugin\Field\FieldType\FileItem * The file item. @@ -142,14 +141,11 @@ * An array of media types that accept file sources. */ protected function filterTypesWithCreateAccess(array $types) { - $valid_types = []; $access_handler = $this->getEntityTypeManager()->getAccessControlHandler('media'); - foreach ($types as $type) { - if ($access_handler->createAccess($type->id())) { - $valid_types[] = $type; - } - } - return $valid_types; + return array_filter($types, function ($type) use ($access_handler) { + /** @var \Drupal\media\MediaTypeInterface $type */ + return $access_handler->createAccess($type->id()); + }); } } diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaBulkUploadFormTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaBulkUploadFormTest.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaBulkUploadFormTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaBulkUploadFormTest.php @@ -69,14 +69,14 @@ $file = reset($test_files['jpg']); $page->attachFileToField('files[upload][]', $file_system->realpath($file->uri)); $assert->assertWaitOnAjaxRequest(); - $assert->pageTextNotContains('Select media type to create'); + $assert->pageTextNotContains('Select which media type to create'); // Try a GIF, which should prompt for a media type to create. $this->drupalGet('/admin/content/media/upload'); $file = reset($test_files['gif']); $page->attachFileToField('files[upload][]', $file_system->realpath($file->uri)); $assert->assertWaitOnAjaxRequest(); - $assert->pageTextContains('Select media type to create'); + $assert->pageTextContains('Select which media type to create'); $assert->elementExists('css', '[value="animated_image"]'); $assert->elementExists('css', '[value="image"]'); $page->pressButton('animated_image');