reverted: --- b/core/modules/media/config/optional/system.action.media_delete_action.yml +++ /dev/null @@ -1,10 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - media -id: media_delete_action -label: 'Delete media' -type: media -plugin: media_delete_action -configuration: { } reverted: --- b/core/modules/media/config/optional/system.action.media_publish_action.yml +++ /dev/null @@ -1,10 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - media -id: media_publish_action -label: 'Publish media' -type: media -plugin: media_publish_action -configuration: { } reverted: --- b/core/modules/media/config/optional/system.action.media_save_action.yml +++ /dev/null @@ -1,10 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - media -id: media_save_action -label: 'Save media' -type: media -plugin: media_save_action -configuration: { } reverted: --- b/core/modules/media/config/optional/system.action.media_unpublish_action.yml +++ /dev/null @@ -1,10 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - media -id: media_unpublish_action -label: 'Unpublish media' -type: media -plugin: media_unpublish_action -configuration: { } diff -u b/core/modules/media/config/schema/media.schema.yml b/core/modules/media/config/schema/media.schema.yml --- b/core/modules/media/config/schema/media.schema.yml +++ b/core/modules/media/config/schema/media.schema.yml @@ -36,22 +36,6 @@ sequence: type: string -action.configuration.media_delete_action: - type: action_configuration_default - label: 'Delete media configuration' - -action.configuration.media_save_action: - type: action_configuration_default - label: 'Save media configuration' - -action.configuration.media_publish_action: - type: action_configuration_default - label: 'Publish media configuration' - -action.configuration.media_unpublish_action: - type: action_configuration_default - label: 'Unpublish media configuration' - field.formatter.settings.media_thumbnail: type: field.formatter.settings.image label: 'Media thumbnail field display format settings' reverted: --- b/core/modules/media/media.tokens.inc +++ /dev/null @@ -1,175 +0,0 @@ - t('Media'), - 'description' => t('Tokens related to individual media items.'), - 'needs-data' => 'media', - ]; - - // Core tokens for media. - $media['mid'] = [ - 'name' => t('Media ID'), - 'description' => t('The unique ID of the media item.'), - ]; - $media['uuid'] = [ - 'name' => t('Media UUID'), - 'description' => t('The unique UUID of the media item.'), - ]; - $media['vid'] = [ - 'name' => t('Revision ID'), - 'description' => t("The unique ID of the media item's latest revision."), - ]; - $media['bundle'] = [ - 'name' => t('Media type'), - ]; - $media['bundle-name'] = [ - 'name' => t('Media type name'), - 'description' => t('The human-readable name of the media type.'), - ]; - $media['langcode'] = [ - 'name' => t('Language code'), - 'description' => t('The language code of the language the media item is written in.'), - ]; - $media['name'] = [ - 'name' => t('Name'), - 'description' => t('The name of this media item.'), - ]; - $media['author'] = [ - 'name' => t('Author'), - 'type' => 'user', - ]; - $media['url'] = [ - 'name' => t('URL'), - 'description' => t('The URL of the media item.'), - ]; - $media['edit-url'] = [ - 'name' => t('Edit URL'), - 'description' => t("The URL of the media item's edit page."), - ]; - - // Chained tokens for media. - $media['created'] = [ - 'name' => t('Date created'), - 'type' => 'date', - ]; - $media['changed'] = [ - 'name' => t('Date changed'), - 'description' => t('The date the media item was most recently updated.'), - 'type' => 'date', - ]; - - return [ - 'types' => ['media' => $type], - 'tokens' => ['media' => $media], - ]; -} - -/** - * Implements hook_tokens(). - */ -function media_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) { - $token_service = \Drupal::token(); - - $url_options = ['absolute' => TRUE]; - if (isset($options['langcode'])) { - $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']); - $langcode = $options['langcode']; - } - else { - $langcode = LanguageInterface::LANGCODE_DEFAULT; - } - - $replacements = []; - if ($type === 'media' && !empty($data['media'])) { - /** @var \Drupal\media\MediaInterface $media */ - $media = \Drupal::service('entity.repository')->getTranslationFromContext($data['media'], $langcode, ['operation' => 'media_entity_tokens']); - - foreach ($tokens as $name => $original) { - switch ($name) { - // Simple key values on the media_entity. - case 'mid': - $replacements[$original] = $media->id(); - break; - - case 'uuid': - $replacements[$original] = $media->uuid(); - break; - - case 'vid': - $replacements[$original] = $media->getRevisionId(); - break; - - case 'bundle': - $replacements[$original] = $media->bundle(); - break; - - case 'bundle-name': - $replacements[$original] = $media->bundle->entity->label(); - break; - - case 'langcode': - $replacements[$original] = $media->language()->getId(); - break; - - case 'name': - $replacements[$original] = $media->label(); - break; - - case 'url': - $replacements[$original] = $media->toUrl('canonical', $url_options); - break; - - case 'edit-url': - $replacements[$original] = $media->toUrl('edit-form', $url_options); - break; - - // Default values for the chained tokens handled below. - case 'author': - $account = $media->getOwner(); - $bubbleable_metadata->addCacheableDependency($account); - $replacements[$original] = $account->label(); - break; - - case 'created': - $date_format = DateFormat::load('medium'); - $bubbleable_metadata->addCacheableDependency($date_format); - $replacements[$original] = \Drupal::service('date.formatter')->format($media->getCreatedTime(), $date_format->id(), '', NULL, $langcode); - break; - - case 'changed': - $date_format = DateFormat::load('medium'); - $bubbleable_metadata->addCacheableDependency($date_format); - $replacements[$original] = \Drupal::service('date.formatter')->format($media->getChangedTime(), $date_format->id(), '', NULL, $langcode); - break; - } - } - - if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) { - $account = $media->get('uid')->entity; - $replacements += $token_service->generate('user', $author_tokens, ['user' => $account], $options, $bubbleable_metadata); - } - - if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) { - $replacements += $token_service->generate('date', $created_tokens, ['date' => $media->getCreatedTime()], $options, $bubbleable_metadata); - } - - if ($changed_tokens = $token_service->findWithPrefix($tokens, 'changed')) { - $replacements += $token_service->generate('date', $changed_tokens, ['date' => $media->getChangedTime()], $options, $bubbleable_metadata); - } - } - - return $replacements; -} diff -u b/core/modules/media/src/Entity/Media.php b/core/modules/media/src/Entity/Media.php --- b/core/modules/media/src/Entity/Media.php +++ b/core/modules/media/src/Entity/Media.php @@ -145,6 +145,12 @@ * * @return \Drupal\media\MediaInterface * The updated media item. + * + * @internal + * + * @todo There has been some disagreement about how to handle updates to + * thumbnails. We need to decide on what the API will be for this. + * https://www.drupal.org/node/2878119 */ protected function updateThumbnail($from_queue = FALSE) { $file_storage = \Drupal::service('entity_type.manager')->getStorage('file'); @@ -205,18 +211,20 @@ } /** - * Gets a file URI for a media item. + * Gets the URI for the thumbnail of a media item. * - * If thumbnail fetching should be queued then temporary use default - * thumbnail for new files or temporary keep existing thumbnail for - * updates. - * Immediately fetch a new thumbnail from the media source otherwise. + * If thumbnail fetching is queued, new media items will use the default + * thumbnail, and existing media items will use the current thumbnail, until + * the queue is processed and the updated thumbnail has been fetched. + * Otherwise, the new thumbnail will be fetched immediately. * * @param bool $from_queue * Specifies whether the thumbnail is being fetched from the queue. * - * @return \Drupal\media\MediaInterface + * @return string * The file URI for the thumbnail of the media item. + * + * @internal */ protected function getThumbnailUri($from_queue) { $thumbnails_queued = $this->bundle->entity->thumbnailDownloadsAreQueued(); @@ -239,8 +247,10 @@ * * @return bool * TRUE if the source field value changed, FALSE otherwise. + * + * @internal */ - protected function sourceFieldChanged() { + protected function hasSourceFieldChanged() { $source_field_name = $this->getSource()->getConfiguration()['source_field']; $current_value = $this->get($source_field_name)->getValue(); return (isset($this->original) && $current_value != $this->original->get($source_field_name)->getValue()); @@ -258,21 +268,16 @@ protected function shouldUpdateThumbnail($is_new = FALSE) { // Update thumbnail if we don't have a thumbnail yet or when the source // field value changes. - return !$this->get('thumbnail')->entity || $is_new || $this->sourceFieldChanged(); + return !$this->get('thumbnail')->entity || $is_new || $this->hasSourceFieldChanged(); } /** * {@inheritdoc} */ public function preSave(EntityStorageInterface $storage) { - // If the source plugin defines any constraints we enforce the validation. - $media_source = $this->getSource(); - if ($media_source instanceof MediaSourceEntityConstraintsInterface || $media_source instanceof MediaSourceFieldConstraintsInterface) { - $this->setValidationRequired(TRUE); - } - parent::preSave($storage); + $media_source = $this->getSource(); foreach ($this->translations as $langcode => $data) { if ($this->hasTranslation($langcode)) { $translation = $this->getTranslation($langcode); @@ -281,7 +286,7 @@ foreach ($translation->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) { // Only save value in entity field if empty. Do not overwrite existing // data. - if ($translation->hasField($entity_field_name) && ($translation->get($entity_field_name)->isEmpty() || $translation->sourceFieldChanged())) { + if ($translation->hasField($entity_field_name) && ($translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged())) { $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name)); } } diff -u b/core/modules/media/src/MediaAccessControlHandler.php b/core/modules/media/src/MediaAccessControlHandler.php --- b/core/modules/media/src/MediaAccessControlHandler.php +++ b/core/modules/media/src/MediaAccessControlHandler.php @@ -54,7 +54,7 @@ * {@inheritdoc} */ protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { - return AccessResult::allowedIfHasPermission($account, 'create media'); + return AccessResult::allowedIfHasPermissions($account, ['administer media', 'create media'], 'OR'); } } reverted: --- b/core/modules/media/src/Plugin/Action/DeleteMedia.php +++ /dev/null @@ -1,98 +0,0 @@ -currentUser = $current_user; - $this->tempStore = $temp_store_factory->get('media_multiple_delete_confirm'); - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('user.private_tempstore'), - $container->get('current_user') - ); - } - - /** - * {@inheritdoc} - */ - public function executeMultiple(array $entities) { - $info = []; - /** @var \Drupal\media\MediaInterface $media */ - foreach ($entities as $media) { - $langcode = $media->language()->getId(); - $info[$media->id()][$langcode] = $langcode; - } - $this->tempStore->set($this->currentUser->id(), $info); - } - - /** - * {@inheritdoc} - */ - public function execute($object = NULL) { - $this->executeMultiple($object ? [$object] : []); - } - - /** - * {@inheritdoc} - */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { - /** @var \Drupal\media\MediaInterface $object */ - return $object->access('delete', $account, $return_as_object); - } - -} reverted: --- b/core/modules/media/src/Plugin/Action/PublishMedia.php +++ /dev/null @@ -1,40 +0,0 @@ -setPublished()->save(); - } - } - - /** - * {@inheritdoc} - */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { - /** @var \Drupal\media\MediaInterface $object */ - $result = $object->access('update', $account, TRUE) - ->andIf($object->status->access('update', $account, TRUE)); - - return $return_as_object ? $result : $result->isAllowed(); - } - -} reverted: --- b/core/modules/media/src/Plugin/Action/SaveMedia.php +++ /dev/null @@ -1,40 +0,0 @@ -changed = 0; - $entity->save(); - } - } - - /** - * {@inheritdoc} - */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { - /** @var \Drupal\media\MediaInterface $object */ - return $object->access('update', $account, $return_as_object); - } - -} reverted: --- b/core/modules/media/src/Plugin/Action/UnpublishMedia.php +++ /dev/null @@ -1,40 +0,0 @@ -setUnpublished()->save(); - } - } - - /** - * {@inheritdoc} - */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { - /** @var \Drupal\media\MediaInterface $object */ - $result = $object->access('update', $account, TRUE) - ->andIf($object->status->access('update', $account, TRUE)); - - return $return_as_object ? $result : $result->isAllowed(); - } - -} diff -u b/core/modules/media/src/Plugin/Field/FieldFormatter/MediaThumbnailFormatter.php b/core/modules/media/src/Plugin/Field/FieldFormatter/MediaThumbnailFormatter.php --- b/core/modules/media/src/Plugin/Field/FieldFormatter/MediaThumbnailFormatter.php +++ b/core/modules/media/src/Plugin/Field/FieldFormatter/MediaThumbnailFormatter.php @@ -35,7 +35,7 @@ protected $renderer; /** - * Constructs an ImageFormatter object. + * Constructs an MediaThumbnailFormatter object. * * @param string $plugin_id * The plugin_id for the formatter. diff -u b/core/modules/media/templates/media.html.twig b/core/modules/media/templates/media.html.twig --- b/core/modules/media/templates/media.html.twig +++ b/core/modules/media/templates/media.html.twig @@ -28,6 +28,9 @@ * * @see template_preprocess_media() * + * @todo Make the HTML wrapper tag for media items more semantically correct. + * https://www.drupal.org/node/2878115 + * * @ingroup themeable */ #} diff -u b/core/modules/media/tests/src/Functional/MediaAccessTest.php b/core/modules/media/tests/src/Functional/MediaAccessTest.php --- b/core/modules/media/tests/src/Functional/MediaAccessTest.php +++ b/core/modules/media/tests/src/Functional/MediaAccessTest.php @@ -38,6 +38,9 @@ $user_media->save(); // We are logged in as admin, so test 'administer media' permission. + $this->drupalGet('media/add/' . $media_type->id()); + $this->assertCacheContext('user.permissions'); + $assert_session->statusCodeEquals(200); $this->drupalGet('media/' . $user_media->id()); $this->assertCacheContext('user.permissions'); $assert_session->statusCodeEquals(200); reverted: --- b/core/modules/media/tests/src/Functional/MediaBulkFormTest.php +++ /dev/null @@ -1,113 +0,0 @@ -testMediaType = $this->createMediaType(); - - // Create some test media items. - $this->mediaItems = []; - for ($i = 1; $i <= 5; $i++) { - $media = Media::create([ - 'bundle' => $this->testMediaType->id(), - ]); - $media->save(); - $this->mediaItems[] = $media; - } - } - - /** - * Tests the media bulk form. - */ - public function testBulkForm() { - $session = $this->getSession(); - $page = $session->getPage(); - $assert_session = $this->assertSession(); - - // Check that all created items are present in the test view. - $view = Views::getView('test_media_bulk_form'); - $view->execute(); - $this->assertEquals($view->total_rows, 5); - - // Check the operations are accessible to the logged in user. - $this->drupalGet('test-media-bulk-form'); - // Current available actions: Delete, Save, Publish, Unpublish. - $available_actions = [ - 'media_delete_action', - 'media_publish_action', - 'media_save_action', - 'media_unpublish_action', - ]; - foreach ($available_actions as $action_name) { - $assert_session->optionExists('action', $action_name); - } - - // Test unpublishing in bulk. - $page->checkField('media_bulk_form[0]'); - $page->checkField('media_bulk_form[1]'); - $page->checkField('media_bulk_form[2]'); - $page->selectFieldOption('action', 'media_unpublish_action'); - $page->pressButton('Apply to selected items'); - $assert_session->pageTextContains('Unpublish media was applied to 3 items'); - $this->assertFalse($this->storage->loadUnchanged(1)->isPublished(), 'The unpublish action failed in some of the media items.'); - $this->assertFalse($this->storage->loadUnchanged(2)->isPublished(), 'The unpublish action failed in some of the media items.'); - $this->assertFalse($this->storage->loadUnchanged(3)->isPublished(), 'The unpublish action failed in some of the media items.'); - - // Test publishing in bulk. - $page->checkField('media_bulk_form[0]'); - $page->checkField('media_bulk_form[1]'); - $page->selectFieldOption('action', 'media_publish_action'); - $page->pressButton('Apply to selected items'); - $assert_session->pageTextContains('Publish media was applied to 2 items'); - $this->assertTrue($this->storage->loadUnchanged(1)->isPublished(), 'The publish action failed in some of the media items.'); - $this->assertTrue($this->storage->loadUnchanged(2)->isPublished(), 'The publish action failed in some of the media items.'); - - // Test deletion in bulk. - $page->checkField('media_bulk_form[0]'); - $page->checkField('media_bulk_form[1]'); - $page->selectFieldOption('action', 'media_delete_action'); - $page->pressButton('Apply to selected items'); - $assert_session->pageTextContains('Are you sure you want to delete these items?'); - $page->pressButton('Delete'); - $assert_session->pageTextContains('Deleted 2 media items.'); - $this->assertNull($this->storage->loadUnchanged(1), 'Could not delete some of the media items.'); - $this->assertNull($this->storage->loadUnchanged(2), 'Could not delete some of the media items.'); - } - -} diff -u b/core/modules/media/tests/src/Kernel/MediaSourceTest.php b/core/modules/media/tests/src/Kernel/MediaSourceTest.php --- b/core/modules/media/tests/src/Kernel/MediaSourceTest.php +++ b/core/modules/media/tests/src/Kernel/MediaSourceTest.php @@ -278,22 +278,14 @@ 'MediaTestConstraint' => [], ]); - // Create media that uses source plugin with constraints and make sure it - // can't be saved without validating them. + // Create a media item media that uses a source plugin with constraints and + // make sure the constraints works as expected when validating. /** @var \Drupal\media\MediaInterface $media */ $media = Media::create([ 'bundle' => $this->testConstraintsMediaType->id(), 'name' => 'I do not like Drupal', 'field_media_test_constraints' => 'Not checked', ]); - try { - $media->save(); - $this->fail('Save was allowed without validation.'); - } - catch (EntityStorageException $exception) { - $this->assertEquals('Entity validation was skipped.', $exception->getMessage(), 'Incorrect validation message.'); - $this->assertTrue(TRUE, 'Validation was enforced before save.'); - } // Validate the entity and make sure violation is reported. /** @var \Drupal\Core\Entity\EntityConstraintViolationListInterface $violations */ @@ -325,14 +317,6 @@ 'name' => 'Not checked', 'field_media_test_constraints' => 'I do not like Drupal', ]); - try { - $media->save(); - $this->fail('Save was allowed without validation.'); - } - catch (EntityStorageException $exception) { - $this->assertEquals('Entity validation was skipped.', $exception->getMessage(), 'Incorrect validation message.'); - $this->assertTrue(TRUE, 'Validation was enforced before save.'); - } // Validate the entity and make sure violation is reported. /** @var \Drupal\Core\Entity\EntityConstraintViolationListInterface $violations */ reverted: --- b/core/modules/media/tests/src/Kernel/MediaTokensTest.php +++ /dev/null @@ -1,74 +0,0 @@ -installEntitySchema('file'); - $this->installSchema('file', 'file_usage'); - $this->installEntitySchema('media'); - $this->installConfig(['language', 'datetime', 'field', 'system']); - } - - /** - * Tests some of the tokens provided by Media. - */ - public function testMediaEntityTokens() { - // Create a test media type. - $media_type_name = $this->randomMachineName(); - - MediaType::create([ - 'id' => $media_type_name, - 'label' => $media_type_name, - 'source' => 'test', - 'source_configuration' => ['test_config_value' => 'Kakec'], - 'field_map' => [], - 'status' => 1, - 'new_revision' => FALSE, - ])->save(); - - // Create a media item. - $media = Media::create([ - 'name' => $this->randomMachineName(), - 'bundle' => $media_type_name, - 'uid' => '1', - 'langcode' => Language::LANGCODE_DEFAULT, - 'status' => TRUE, - ]); - $media->save(); - - $token_service = $this->container->get('token'); - - $replaced_value = $token_service->replace('[media:name]', ['media' => $media]); - $this->assertEquals($media->label(), $replaced_value, 'Token replacement for the media label was successful.'); - } - -} diff -u b/core/modules/path/path.module b/core/modules/path/path.module --- b/core/modules/path/path.module +++ b/core/modules/path/path.module @@ -62,7 +62,7 @@ * Implements hook_entity_base_field_info(). */ function path_entity_base_field_info(EntityTypeInterface $entity_type) { - if (in_array($entity_type->id(), ['taxonomy_term', 'node', 'media'])) { + if (in_array($entity_type->id(), ['taxonomy_term', 'node', 'media'], TRUE)) { $fields['path'] = BaseFieldDefinition::create('path') ->setLabel(t('URL alias')) ->setTranslatable(TRUE)