diff --git a/core/modules/media_entity/config/schema/media_entity.schema.yml b/core/modules/media_entity/config/schema/media_entity.schema.yml index bca1a93eb8b5b748ebfed3bed8556f8fd2488a44..68f5962fb21b39ca2705e29f3cb40aafd7a8a290 100644 --- a/core/modules/media_entity/config/schema/media_entity.schema.yml +++ b/core/modules/media_entity/config/schema/media_entity.schema.yml @@ -36,6 +36,14 @@ media_entity.bundle.*: sequence: type: string +media_entity.bundle.type.file: + type: mapping + label: 'File handler configuration' + mapping: + source_field: + type: string + label: 'Field with source information' + action.configuration.media_delete_action: type: action_configuration_default label: 'Delete media configuration' diff --git a/core/modules/media_entity/src/Plugin/MediaEntity/Type/File.php b/core/modules/media_entity/src/Plugin/MediaEntity/Type/File.php new file mode 100644 index 0000000000000000000000000000000000000000..8933daa2258e7e1d365cd6a4740df06ef226c7a9 --- /dev/null +++ b/core/modules/media_entity/src/Plugin/MediaEntity/Type/File.php @@ -0,0 +1,121 @@ + $this->t('MIME type'), + 'size' => $this->t('Size'), + ]; + } + + /** + * {@inheritdoc} + */ + public function getField(MediaInterface $media, $name) { + $source_field = $this->configuration['source_field']; + + // Get the file. + /** @var \Drupal\file\FileInterface $file */ + $file = $media->{$source_field}->entity; + + // Return the field. + switch ($name) { + case 'mime': + return $file->getMimeType() ?: FALSE; + + case 'size': + $size = $file->getSize(); + return is_numeric($size) ? $size : FALSE; + } + + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function thumbnail(MediaInterface $media) { + $source_field = $this->configuration['source_field']; + /** @var \Drupal\file\FileInterface $file */ + $file = $media->{$source_field}->entity; + $icon_base = $this->configFactory->get('media_entity.settings')->get('icon_base'); + $thumbnail = FALSE; + if ($file) { + $mimetype = $file->getMimeType(); + $mimetype = explode('/', $mimetype); + $thumbnail = $icon_base . "/{$mimetype[0]}--{$mimetype[1]}.png"; + + if (!is_file($thumbnail)) { + $thumbnail = $icon_base . "/{$mimetype[1]}.png"; + } + } + + if (!is_file($thumbnail)) { + $thumbnail = $icon_base . '/generic.png'; + } + + return $thumbnail; + } + + /** + * {@inheritdoc} + */ + public function getDefaultName(MediaInterface $media) { + // The default name will be the filename of the source_field, if present. + $source_field = $this->configuration['source_field']; + + /** @var \Drupal\file\FileInterface $file */ + if (!empty($source_field) && ($file = $media->{$source_field}->entity)) { + return $file->getFilename(); + } + + return parent::getDefaultName($media); + } + + /** + * {@inheritdoc} + */ + protected function createSourceFieldStorage() { + return $this->entityTypeManager + ->getStorage('field_storage_config') + ->create([ + 'entity_type' => 'media', + 'field_name' => $this->getSourceFieldName(), + 'type' => 'file', + ]); + } + + /** + * {@inheritdoc} + */ + protected function createSourceField(MediaBundleInterface $bundle) { + /** @var \Drupal\field\FieldConfigInterface $field */ + return $this->entityTypeManager + ->getStorage('field_config') + ->create([ + 'field_storage' => $this->getSourceFieldStorage(), + 'bundle' => $bundle->id(), + ]); + } + +} diff --git a/core/modules/media_entity/tests/src/FunctionalJavascript/FileTest.php b/core/modules/media_entity/tests/src/FunctionalJavascript/FileTest.php new file mode 100644 index 0000000000000000000000000000000000000000..51af1a73bf92a3794d40db49a7dcf51f71342012 --- /dev/null +++ b/core/modules/media_entity/tests/src/FunctionalJavascript/FileTest.php @@ -0,0 +1,51 @@ +getSession(); + $page = $session->getPage(); + $assert_session = $this->assertSession(); + + // We rely on an automatic source field being created at this point. + // @see MediaTypeBase::getSourceFieldName(). + $source_field_name = 'field_media_file'; + $bundle_name = strtolower($this->randomMachineName(12)); + $provided_fields = ['mime', 'size']; + $bundle = $this->createMediaBundleTest($bundle_name, 'file', $provided_fields); + // Adjust the allowed extensions on the source field. + \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + $bundle->getType() + ->getSourceField($bundle) + ->setSetting('file_extensions', 'txt') + ->save(); + // Hide the media name to test default name generation. + $this->hideMediaField('name', $bundle_name); + // Create a media item. + $this->drupalGet("media/add/$bundle_name"); + $page->attachFileToField('files[' . $source_field_name . '_0]', \Drupal::root() . '/sites/README.txt'); + $assert_session->assertWaitOnAjaxRequest(); + $page->pressButton('Save and publish'); + + $assert_session->addressEquals('media/1'); + // Make sure the thumbnail shows up. + $assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', 'generic.png'); + // Load the media and check its default name. + $media = Media::load(1); + $this->assertEquals($media->label(), 'README.txt'); + + } + +} diff --git a/core/modules/media_entity/tests/src/FunctionalJavascript/MediaHandlerTestBase.php b/core/modules/media_entity/tests/src/FunctionalJavascript/MediaHandlerTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..0f6a79d90ed2860a4d23b21fb57013f60b8bb132 --- /dev/null +++ b/core/modules/media_entity/tests/src/FunctionalJavascript/MediaHandlerTestBase.php @@ -0,0 +1,97 @@ +removeComponent($field_name)->save(); + } + + /** + * Helper to test a generic bundle creation. + * + * @param string $bundle_name + * The bundle machine name. + * @param string $bundle_type + * The bundle type ID. + * @param array $provided_fields + * (optional) An array of field machine names this type provides. + * + * @return \Drupal\media_entity\MediaBundleInterface + * The bundle created. + */ + public function createMediaBundleTest($bundle_name, $bundle_type, array $provided_fields = []) { + $session = $this->getSession(); + $page = $session->getPage(); + $assert_session = $this->assertSession(); + + $this->drupalGet('admin/structure/media/add'); + $page->fillField('label', $bundle_name); + // assertWaitOnAjaxRequest() doesn't work on the machine name element. + $session->wait(5000, "jQuery('.machine-name-value').text() === '$bundle_name'"); + + // Make sure the bundle type is available as plugin type. + $assert_session->optionExists('type', $bundle_type); + $page->selectFieldOption('type', $bundle_type); + $assert_session->assertWaitOnAjaxRequest(); + + // Make sure the provided fields are visible on the form. + if (!empty($provided_fields)) { + foreach ($provided_fields as $provided_field) { + $assert_session->selectExists("field_mapping[$provided_field]"); + } + } + + // Save the page to create the bundle. + $page->pressButton('Save'); + $assert_session->pageTextContains('The media type ' . $bundle_name . ' has been added.'); + $this->drupalGet('admin/structure/media'); + $assert_session->pageTextContains($bundle_name); + + // Bundle definitions are statically cached in the context of the test, we + // need to make sure we have updated information before proceeding with the + // actions on the UI. + \Drupal::service('entity_type.bundle.info')->clearCachedBundles(); + + return MediaBundle::load($bundle_name); + } + + /** + * Helper to assert presence/absence of select options. + * + * @param string $select + * One of id|name|label|value for the select field. + * @param array $expected_options + * An indexed array of expected option names. + * @param array $non_expected_options + * An indexed array of non-expected option names. + * + * @see \Drupal\Tests\WebAssert::optionExists() + * @see \Drupal\Tests\WebAssert::optionNotExists() + */ + protected function assertSelectOptions($select, $expected_options = [], $non_expected_options = []) { + $assert_session = $this->assertSession(); + foreach ($expected_options as $expected_option) { + $assert_session->optionExists($select, $expected_option); + } + foreach ($non_expected_options as $non_expected_option) { + $assert_session->optionNotExists($select, $non_expected_option); + } + } + +} diff --git a/core/profiles/standard/config/optional/media_entity.bundle.file.yml b/core/profiles/standard/config/optional/media_entity.bundle.file.yml new file mode 100644 index 0000000000000000000000000000000000000000..acdf44e1c24f29001215c4e68a353a3e3f412148 --- /dev/null +++ b/core/profiles/standard/config/optional/media_entity.bundle.file.yml @@ -0,0 +1,14 @@ +langcode: en +status: true +dependencies: + module: + - media_entity +id: file +label: File +description: 'Use the "File" media type for uploading local files.' +type: file +queue_thumbnail_downloads: false +new_revision: false +type_configuration: + source_field: field_media_file +field_map: { }