diff -u b/core/modules/media/js/media_type_form.js b/core/modules/media/js/media_type_form.js --- b/core/modules/media/js/media_type_form.js +++ b/core/modules/media/js/media_type_form.js @@ -1,6 +1,6 @@ /** * @file - * Javascript for the media type form. + * Defines JavaScript behaviors for the media type form. */ (function ($, Drupal) { diff -u b/core/modules/media/media.module b/core/modules/media/media.module --- b/core/modules/media/media.module +++ b/core/modules/media/media.module @@ -20,11 +20,11 @@ switch ($route_name) { case 'help.page.media': $output = '

' . t('About') . '

'; - $output .= '

' . t('The Media module manages the creation, editing, deletion, settings and display of media. Items are typically images, documents, slideshows, YouTube videos, Tweets, Instagram photos, etc. You can reference media items from any other content on your site. For more information, see the online documentation for the Media module.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '

'; + $output .= '

' . t('The Media module manages the creation, editing, deletion, settings and display of media. Items are typically images, documents, slideshows, YouTube videos, tweets, Instagram photos, etc. You can reference media items from any other content on your site. For more information, see the online documentation for the Media module.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '

'; $output .= '

' . t('Uses') . '

'; $output .= '
'; $output .= '
' . t('Creating media items') . '
'; - $output .= '
' . t('When a new media item is created, the Media module records basic information about it, including the author, date of creation, and the Media type. It also manages the publishing options, which define whether or not the item is published. Default settings can be configured for each type of media on your site.', [':media-type' => Url::fromRoute('entity.media_type.collection')->toString()]) . '
'; + $output .= '
' . t('When a new media item is created, the Media module records basic information about it, including the author, date of creation, and the media type. It also manages the publishing options, which define whether or not the item is published. Default settings can be configured for each type of media on your site.', [':media-type' => Url::fromRoute('entity.media_type.collection')->toString()]) . '
'; $output .= '
' . t('Creating custom media types') . '
'; $output .= '
' . t('The Media module gives users with the Administer media types permission the ability to create new media types in addition to the default ones already configured. Each media type has an associated media source (such as the image source) which support thumbnail generation and metadata extraction. Fields managed by the Field module may be added for storing that metadata, such as width and height, as well as any other associated values.', [':media-new' => Url::fromRoute('entity.media_type.add_form')->toString(), ':field' => Url::fromRoute('help.page', ['name' => 'field'])->toString()]) . '
'; $output .= '
' . t('Creating revisions') . '
'; @@ -52,7 +52,7 @@ * * Fix broken operations array in field UI for entities with restricted access. * - * @todo: This hook can be removed when issue 2836384 is fixed. + * @todo This hook can be removed when issue #2836384 is done. * @see https://www.drupal.org/node/2836384 */ function media_entity_operation_alter(array &$operations, EntityInterface $entity) { diff -u b/core/modules/media/media.routing.yml b/core/modules/media/media.routing.yml --- b/core/modules/media/media.routing.yml +++ b/core/modules/media/media.routing.yml @@ -6 +6 @@ - _permission: 'delete any media' + _permission: 'administer media' diff -u b/core/modules/media/media.tokens.inc b/core/modules/media/media.tokens.inc --- b/core/modules/media/media.tokens.inc +++ b/core/modules/media/media.tokens.inc @@ -30,7 +30,7 @@ ]; $media['vid'] = [ 'name' => t('Revision ID'), - 'description' => t("'The unique ID of the media item's latest revision."), + 'description' => t("The unique ID of the media item's latest revision."), ]; $media['bundle'] = [ 'name' => t('Media type'), diff -u b/core/modules/media/src/Annotation/MediaSource.php b/core/modules/media/src/Annotation/MediaSource.php --- b/core/modules/media/src/Annotation/MediaSource.php +++ b/core/modules/media/src/Annotation/MediaSource.php @@ -60,11 +60,11 @@ /** * A filename for the default thumbnail. * - * The thumbnails are placed in the directory defined in - * media.settings.icon_base_uri. When using custom icons, make sure the + * The thumbnails are placed in the directory defined by the config setting + * 'media.settings.icon_base_uri'. When using custom icons, make sure the * module provides a hook_install() implementation to copy the custom icons * to this directory. The media_install() function provides a clear example - * on how to do this. + * of how to do this. * * @var string * 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 @@ -2,10 +2,10 @@ namespace Drupal\media\Entity; -use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityPublishedTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\RevisionableContentEntityBase; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\media\MediaInterface; @@ -17,7 +17,7 @@ /** * Defines the media entity class. * - * @todo Remove default/fallback entity form operation when #2006348 lands. + * @todo Remove default/fallback entity form operation when #2006348 is done. * @see https://www.drupal.org/node/2006348. * * @ContentEntityType( @@ -77,7 +77,7 @@ * } * ) */ -class Media extends ContentEntityBase implements MediaInterface { +class Media extends RevisionableContentEntityBase implements MediaInterface { use EntityChangedTrait; use EntityPublishedTrait; @@ -95,7 +95,6 @@ */ public function setCreatedTime($timestamp) { $this->set('created', $timestamp); - return $this; } /** @@ -110,7 +109,6 @@ */ public function setOwner(UserInterface $account) { $this->set('uid', $account->id()); - return $this; } /** @@ -125,7 +123,6 @@ */ public function setOwnerId($uid) { $this->set('uid', $uid); - return $this; } /** @@ -166,9 +163,10 @@ } // Set the thumbnail alt. - $plugin_definition = $this->getSource()->getPluginDefinition(); + $media_source = $this->getSource(); + $plugin_definition = $media_source->getPluginDefinition(); if (!empty($plugin_definition['thumbnail_alt_metadata_attribute'])) { - $this->thumbnail->alt = $this->getSource()->getMetadata($this, $plugin_definition['thumbnail_alt_metadata_attribute']); + $this->thumbnail->alt = $media_source->getMetadata($this, $plugin_definition['thumbnail_alt_metadata_attribute']); } else { $this->thumbnail->alt = $this->t('Thumbnail'); @@ -176,7 +174,7 @@ // Set the thumbnail title. if (!empty($plugin_definition['thumbnail_title_metadata_attribute'])) { - $this->thumbnail->title = $this->getSource()->getMetadata($this, $plugin_definition['thumbnail_title_metadata_attribute']); + $this->thumbnail->title = $media_source->getMetadata($this, $plugin_definition['thumbnail_title_metadata_attribute']); } else { $this->thumbnail->title = $this->label(); @@ -208,11 +206,12 @@ * The file URI for the thumbnail of the media item. */ protected function getThumbnailUri($from_queue) { - if ($this->bundle->entity->thumbnailDownloadsAreQueued() && $this->isNew()) { + $thumbnails_queued = $this->bundle->entity->thumbnailDownloadsAreQueued(); + if ($thumbnails_queued && $this->isNew()) { $default_thumbnail_filename = $this->getSource()->getPluginDefinition()['default_thumbnail_filename']; $thumbnail_uri = \Drupal::service('config.factory')->get('media.settings')->get('icon_base_uri') . '/' . $default_thumbnail_filename; } - elseif ($this->bundle->entity->thumbnailDownloadsAreQueued() && !$from_queue) { + elseif ($thumbnails_queued && !$from_queue) { $thumbnail_uri = $this->get('thumbnail')->entity->getFileUri(); } else { @@ -230,12 +229,8 @@ */ protected function sourceFieldChanged() { $source_field_name = $this->getSource()->getConfiguration()['source_field']; - - if (isset($this->original) && $this->get($source_field_name)->getValue() != $this->original->get($source_field_name)->getValue()) { - return TRUE; - } - - return FALSE; + $current_value = $this->get($source_field_name)->getValue(); + return (isset($this->original) && $current_value != $this->original->get($source_field_name)->getValue()); } /** @@ -258,7 +253,8 @@ */ public function preSave(EntityStorageInterface $storage) { // If the source plugin defines any constraints we enforce the validation. - if ($this->getSource() instanceof MediaSourceEntityConstraintsInterface || $this->getSource() instanceof MediaSourceFieldConstraintsInterface) { + $media_source = $this->getSource(); + if ($media_source instanceof MediaSourceEntityConstraintsInterface || $media_source instanceof MediaSourceFieldConstraintsInterface) { $this->setValidationRequired(TRUE); } @@ -269,14 +265,14 @@ foreach ($this->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) { // Only save value in entity field if empty. Do not overwrite existing // data. - if ($this->hasField($entity_field_name) && ($this->get($entity_field_name)->isEmpty() || $this->sourceFieldChanged()) && ($value = $this->getSource()->getMetadata($this, $metadata_attribute_name)) && $value !== NULL) { + if ($this->hasField($entity_field_name) && ($this->get($entity_field_name)->isEmpty() || $this->sourceFieldChanged()) && ($value = $media_source->getMetadata($this, $metadata_attribute_name)) && $value !== NULL) { $this->set($entity_field_name, $value); } } // Try to set a default name for this media item if no label is provided. if (!$this->label()) { - $this->set('name', $this->getSource()->getMetadata($this, $this->getSource()->getPluginDefinition()['default_name_metadata_attribute'])); + $this->set('name', $media_source->getMetadata($this, $media_source->getPluginDefinition()['default_name_metadata_attribute'])); } // Set thumbnail. @@ -292,8 +288,7 @@ parent::postSave($storage, $update); $is_new = !$update; if ($this->bundle->entity->thumbnailDownloadsAreQueued() && $this->shouldUpdateThumbnail($is_new)) { - $queue = \Drupal::queue('media_entity_thumbnail'); - $queue->createItem(['id' => $this->id()]); + \Drupal::queue('media_entity_thumbnail')->createItem(['id' => $this->id()]); } } @@ -303,17 +298,18 @@ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) { parent::preSaveRevision($storage, $record); - if (!$this->isNewRevision() && isset($this->original) && empty($record->revision_log)) { + $is_new_revision = $this->isNewRevision(); + if (!$is_new_revision && isset($this->original) && empty($record->revision_log_message)) { // If we are updating an existing media item without adding a - // new revision, we need to make sure $entity->revision_log is reset - // whenever it is empty. + // new revision, we need to make sure $entity->revision_log_message is + // reset whenever it is empty. // Therefore, this code allows us to avoid clobbering an existing log // entry with an empty one. - $record->revision_log = $this->original->revision_log->value; + $record->revision_log_message = $this->original->revision_log_message->value; } - if ($this->isNewRevision()) { - $record->revision_timestamp = self::getRequestTime(); + if ($is_new_revision) { + $record->revision_created = self::getRequestTime(); } } @@ -426,34 +422,6 @@ ->setTranslatable(TRUE) ->setRevisionable(TRUE); - $fields['revision_timestamp'] = BaseFieldDefinition::create('created') - ->setLabel(t('Revision timestamp')) - ->setDescription(t('The time the current revision was created.')) - ->setQueryable(FALSE) - ->setRevisionable(TRUE); - - $fields['revision_uid'] = BaseFieldDefinition::create('entity_reference') - ->setLabel(t('Revision authored by')) - ->setDescription(t('The user ID of the author of the current revision.')) - ->setDefaultValueCallback(static::class . '::getCurrentUserId') - ->setSetting('target_type', 'user') - ->setQueryable(FALSE) - ->setRevisionable(TRUE); - - $fields['revision_log'] = BaseFieldDefinition::create('string_long') - ->setLabel(t('Revision Log')) - ->setDescription(t('The log entry explaining the changes in this revision.')) - ->setRevisionable(TRUE) - ->setTranslatable(TRUE) - ->setDefaultValue('') - ->setDisplayOptions('form', [ - 'type' => 'string_textarea', - 'weight' => 25, - 'settings' => [ - 'rows' => 4, - ], - ]); - return $fields; } @@ -478,62 +446,2 @@ - /** - * {@inheritdoc} - */ - public function getRevisionCreationTime() { - return $this->revision_timestamp->value; - } - - /** - * {@inheritdoc} - */ - public function setRevisionCreationTime($timestamp) { - $this->revision_timestamp->value = $timestamp; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getRevisionUser() { - return $this->revision_uid->entity; - } - - /** - * {@inheritdoc} - */ - public function setRevisionUser(UserInterface $account) { - $this->revision_uid->entity = $account; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getRevisionUserId() { - return $this->revision_uid->target_id; - } - - /** - * {@inheritdoc} - */ - public function setRevisionUserId($user_id) { - $this->revision_uid->target_id = $user_id; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getRevisionLogMessage() { - return $this->revision_log->value; - } - - /** - * {@inheritdoc} - */ - public function setRevisionLogMessage($revision_log_message) { - $this->revision_log->value = $revision_log_message; - return $this; - } - } diff -u b/core/modules/media/src/Entity/MediaType.php b/core/modules/media/src/Entity/MediaType.php --- b/core/modules/media/src/Entity/MediaType.php +++ b/core/modules/media/src/Entity/MediaType.php @@ -150,8 +150,7 @@ * {@inheritdoc} */ public function setDescription($description) { - $this->description = $description; - return $this; + return $this->set('description', $description); } /** @@ -165,8 +164,7 @@ * {@inheritdoc} */ public function setQueueThumbnailDownloadsStatus($queue_thumbnail_downloads) { - $this->queue_thumbnail_downloads = $queue_thumbnail_downloads; - return $this; + return $this->set('queue_thumbnail_downloads', $queue_thumbnail_downloads); } /** @@ -207,8 +205,7 @@ * {@inheritdoc} */ public function setNewRevision($new_revision) { - $this->new_revision = $new_revision; - return $this; + return $this->set('new_revision', $new_revision); } /** @@ -221,9 +218,8 @@ /** * {@inheritdoc} */ - public function setFieldMap($map) { - $this->field_map = $map; - return $this; + public function setFieldMap(array $map) { + return $this->set('field_map', $map); } } diff -u b/core/modules/media/src/Form/MediaDeleteMultipleConfirmForm.php b/core/modules/media/src/Form/MediaDeleteMultipleConfirmForm.php --- b/core/modules/media/src/Form/MediaDeleteMultipleConfirmForm.php +++ b/core/modules/media/src/Form/MediaDeleteMultipleConfirmForm.php @@ -11,14 +11,14 @@ use Symfony\Component\HttpFoundation\RedirectResponse; /** - * Provides a confirmation form to delete media items. + * Provides a confirmation form to delete multiple media items at once. */ class MediaDeleteMultipleConfirmForm extends ConfirmFormBase { /** - * The array of media items to delete. + * The array of media items to delete, indexed by ID and language. * - * @var array + * @var string[][] */ protected $mediaItems = []; @@ -42,7 +42,7 @@ * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory * The tempstore factory. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $manager - * The entity manager. + * The entity type manager. */ public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityTypeManagerInterface $manager) { $this->tempStoreFactory = $temp_store_factory; @@ -92,7 +92,7 @@ /** * {@inheritdoc} * - * @todo: Change to trait or base class when #2843395 is done. + * @todo Change to trait or base class when #2843395 is done. * @see https://www.drupal.org/node/2843395 */ public function buildForm(array $form, FormStateInterface $form_state) { @@ -145,7 +145,7 @@ /** * {@inheritdoc} * - * @todo: Change to trait or base class when #2843395 is done. + * @todo Change to trait or base class when #2843395 is done. * @see https://www.drupal.org/node/2843395 */ public function submitForm(array &$form, FormStateInterface $form_state) { diff -u b/core/modules/media/src/Form/MediaTypeDeleteConfirmForm.php b/core/modules/media/src/Form/MediaTypeDeleteConfirmForm.php --- b/core/modules/media/src/Form/MediaTypeDeleteConfirmForm.php +++ b/core/modules/media/src/Form/MediaTypeDeleteConfirmForm.php @@ -23,7 +23,7 @@ * Constructs a new MediaTypeDeleteConfirm object. * * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory - * The entity query object. + * The entity query factory. */ public function __construct(QueryFactory $query_factory) { $this->queryFactory = $query_factory; 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 @@ -23,19 +23,27 @@ $is_owner = ($account->id() && $account->id() === $entity->getOwnerId()); switch ($operation) { case 'view': - return AccessResult::allowedIf($account->hasPermission('view media') && $entity->isPublished())->cachePerPermissions()->addCacheableDependency($entity); + return AccessResult::allowedIf($account->hasPermission('view media') && $entity->isPublished()) + ->cachePerPermissions() + ->addCacheableDependency($entity); case 'update': if ($account->hasPermission('update any media')) { return AccessResult::allowed()->cachePerPermissions(); } - return AccessResult::allowedIf($account->hasPermission('update media') && $is_owner)->cachePerPermissions()->cachePerUser()->addCacheableDependency($entity); + return AccessResult::allowedIf($account->hasPermission('update media') && $is_owner) + ->cachePerPermissions() + ->cachePerUser() + ->addCacheableDependency($entity); case 'delete': if ($account->hasPermission('delete any media')) { return AccessResult::allowed()->cachePerPermissions(); } - return AccessResult::allowedIf($account->hasPermission('delete media') && $is_owner)->cachePerPermissions()->cachePerUser()->addCacheableDependency($entity); + return AccessResult::allowedIf($account->hasPermission('delete media') && $is_owner) + ->cachePerPermissions() + ->cachePerUser() + ->addCacheableDependency($entity); default: return AccessResult::neutral()->cachePerPermissions(); diff -u b/core/modules/media/src/MediaForm.php b/core/modules/media/src/MediaForm.php --- b/core/modules/media/src/MediaForm.php +++ b/core/modules/media/src/MediaForm.php @@ -91,11 +91,11 @@ // If already published, the 'publish' button is primary. if ($media->isPublished()) { - unset($element['unpublish']['#button_type']); + $element['publish']['#button_type'] = 'primary'; } // Otherwise, the 'unpublish' button is primary and should come first. else { - unset($element['publish']['#button_type']); + $element['unpublish']['#button_type'] = 'primary'; $element['unpublish']['#weight'] = -10; } diff -u b/core/modules/media/src/MediaInterface.php b/core/modules/media/src/MediaInterface.php --- b/core/modules/media/src/MediaInterface.php +++ b/core/modules/media/src/MediaInterface.php @@ -9,13 +9,16 @@ use Drupal\user\EntityOwnerInterface; /** - * Provides an interface defining a entity for media items. + * Provides an interface defining an entity for media items. */ interface MediaInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface, EntityOwnerInterface, EntityPublishedInterface { /** * Returns the media item creation timestamp. * + * @todo Remove and use the new interface when #2833378 is done. + * @see https://www.drupal.org/node/2833378 + * * @return int * Creation timestamp of the media item. */ @@ -24,6 +27,9 @@ /** * Sets the media item creation timestamp. * + * @todo Remove and use the new interface when #2833378 is done. + * @see https://www.drupal.org/node/2833378 + * * @param int $timestamp * The media creation timestamp. * diff -u b/core/modules/media/src/MediaSourceBase.php b/core/modules/media/src/MediaSourceBase.php --- b/core/modules/media/src/MediaSourceBase.php +++ b/core/modules/media/src/MediaSourceBase.php @@ -76,6 +76,8 @@ $this->entityFieldManager = $entity_field_manager; $this->fieldTypeManager = $field_type_manager; $this->configFactory = $config_factory; + + // Add the default configuration of the media source to the plugin. $this->setConfiguration($configuration); } @@ -146,10 +148,10 @@ /** * Get the source field options for the media type form. * - * This returns all fields related to media entities, filtered by the - * allowed types in the media source annotation. + * This returns all fields related to media entities, filtered by the allowed + * field types in the media source annotation. * - * @return array + * @return string[] * A list of source field options for the media type form. */ protected function getSourceFieldOptions() { diff -u b/core/modules/media/src/MediaSourceEntityConstraintsInterface.php b/core/modules/media/src/MediaSourceEntityConstraintsInterface.php --- b/core/modules/media/src/MediaSourceEntityConstraintsInterface.php +++ b/core/modules/media/src/MediaSourceEntityConstraintsInterface.php @@ -3,10 +3,10 @@ namespace Drupal\media; /** - * Defines a interface for a media source with entity constraints. + * Defines an interface for a media source with entity constraints. * * This allows a media source to optionally add entity validation constraints - * for media items. To add contraints at source field level a media source + * for media items. To add contraints at the source field level, a media source * can also implement MediaSourceFieldConstraintsInterface. * * @see \Drupal\media\MediaSourceInterface diff -u b/core/modules/media/src/MediaSourceFieldConstraintsInterface.php b/core/modules/media/src/MediaSourceFieldConstraintsInterface.php --- b/core/modules/media/src/MediaSourceFieldConstraintsInterface.php +++ b/core/modules/media/src/MediaSourceFieldConstraintsInterface.php @@ -3,10 +3,10 @@ namespace Drupal\media; /** - * Defines a interface for a media source with source field constraints. + * Defines an interface for a media source with source field constraints. * * This allows a media source to optionally add source field validation - * constraints for media items. To add contraints at entity level a + * constraints for media items. To add contraints at the entity level, a * media source can also implement MediaSourceEntityConstraintsInterface. * * @see \Drupal\media\MediaSourceInterface diff -u b/core/modules/media/src/MediaSourceInterface.php b/core/modules/media/src/MediaSourceInterface.php --- b/core/modules/media/src/MediaSourceInterface.php +++ b/core/modules/media/src/MediaSourceInterface.php @@ -9,15 +9,14 @@ /** * Defines the interface for media source plugins. * - * Media sources provide the critical link between media items in Drupal and - * the actual media itself, which typically exists independently of Drupal. - * Each media source works with a certain kind of media. For example, - * local files and Youtube videos can both be catalogued in a similar way - * as Media entity items, but they need very different handling to actually - * display them. + * Media sources provide the critical link between media items in Drupal and the + * actual media itself, which typically exists independently of Drupal. Each + * media source works with a certain kind of media. For example, local files and + * YouTube videos can both be catalogued in a similar way as media items, but + * they need very different handling to actually display them. * - * Each Media type needs exactly one source. A single source can be used on - * many media types. + * Each media type needs exactly one source. A single source can be used on many + * media types. * * Examples of possible sources are: * - File: handles local files, @@ -26,30 +25,29 @@ * - YouTube: handles YouTube videos, * - SoundCould: handles SoundCloud audio, * - Instagram: handles Instagram posts, - * - Twitter: handles Tweets, + * - Twitter: handles tweets, * - ... * * Their responsibilities are: * - Defining how media is represented (stored). Media sources are not - * responsible to actually store the media. They only define how it is + * responsible for actually store the media. They only define how it is * represented on a media item (usually using some kind of a field). * - Providing thumbnails. Media sources that are responsible for remote - * media will generally fetch the image from the 3rd party API and make + * media will generally fetch the image from a third-party API and make * it available for the local usage. Media sources that represent local * media (such as images) will usually use some locally provided image. - * Both will also fall back to a pre-defined default thumbnail if + * Media sources should fall back to a pre-defined default thumbnail if * everything else fails. * - Validating a media item before it is saved. The entity constraint system * will be used to ensure the valid structure of the media item. * For example, media sources that represent remote media might check the * URL or other identifier, while sources that represent local files might * check the MIME type of the file. - * - Providing a default value for the media name field. This will save users - * from manually entering the name when it can be reliably set - * automatically. Media sources for local files will generally use the - * filename, while media sources for remote resources might obtain a title - * attribute through the 3rd party API. The name can always be overridden - * by the user. + * - Providing a default name for a media item. This will save users from + * manually entering the name when it can be reliably set automatically. + * Media sources for local files will generally use the filename, while media + * sources for remote resources might obtain a title attribute through a + * third-party API. The name can always be overridden by the user. * - Providing metadata specific to the given media type. For example, remote * media sources generally get information available through the * 3rd party API and make it available to Drupal, while local media sources @@ -69,6 +67,11 @@ interface MediaSourceInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface { /** + * Default empty value for metadata fields. + */ + const METADATA_FIELD_EMPTY = '_none'; + + /** * Gets a list of metadata attributes provided by this plugin. * * Most media sources have associated metadata, describing attributes @@ -80,7 +83,7 @@ * - location * - permalink * - licensing information - * - … + * - ... * * This method should list all metadata attributes that a media source MAY * offer. In other words: it is possible that a particular media item does @@ -119,8 +122,8 @@ * A media type. * * @return \Drupal\field\FieldConfigInterface|null - * The source field definition, or NULL if it doesn't exists yet - * or has not been set in the $source configuration. + * The source field definition, or NULL if it doesn't exist or has not been + * configured yet. */ public function getSourceFieldDefinition(MediaTypeInterface $type); diff -u b/core/modules/media/src/MediaTypeForm.php b/core/modules/media/src/MediaTypeForm.php --- b/core/modules/media/src/MediaTypeForm.php +++ b/core/modules/media/src/MediaTypeForm.php @@ -60,7 +60,7 @@ */ public function ajaxHandlerData(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $response->addCommand(new ReplaceCommand('#source-dependent', $form['source_dependent('])); + $response->addCommand(new ReplaceCommand('#source-dependent', $form['source_dependent'])); return $response; } @@ -111,12 +111,12 @@ $options[$plugin_id] = $definition['label']; } - $form['source_dependent('] = [ + $form['source_dependent'] = [ '#type' => 'container', '#attributes' => ['id' => 'source-dependent'], ]; - $form['source_dependent(']['source'] = [ + $form['source_dependent']['source'] = [ '#type' => 'select', '#title' => $this->t('Media source'), '#default_value' => $source ? $source->getPluginId() : NULL, @@ -132,17 +132,17 @@ if ($source) { // Media source plugin configuration. - $form['source_dependent(']['source_configuration'] = [ + $form['source_dependent']['source_configuration'] = [ '#type' => 'fieldset', '#title' => $this->t('Media source configuration'), '#tree' => TRUE, ]; - $form['source_dependent(']['source_configuration'] = $source->buildConfigurationForm($form['source_dependent(']['source_configuration'], $this->getSourceSubFormState($form, $form_state)); + $form['source_dependent']['source_configuration'] = $source->buildConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state)); } // Field mapping configuration. - $form['source_dependent(']['field_map'] = [ + $form['source_dependent']['field_map'] = [ '#type' => 'fieldset', '#title' => $this->t('Field mapping'), '#tree' => TRUE, @@ -152,10 +152,10 @@ ]; if (empty($source) || empty($source->getMetadataAttributes())) { - $form['source_dependent(']['field_map']['#access'] = FALSE; + $form['source_dependent']['field_map']['#access'] = FALSE; } else { - $options = ['_none' => $this->t('- Skip field -')]; + $options = [MediaSourceInterface::METADATA_FIELD_EMPTY => $this->t('- Skip field -')]; foreach ($this->entityFieldManager->getFieldDefinitions('media', $this->entity->id()) as $field_name => $field) { if (!($field instanceof BaseFieldDefinition) || $field_name === 'name') { $options[$field_name] = $field->getLabel(); @@ -164,11 +164,11 @@ $field_map = $this->entity->getFieldMap(); foreach ($source->getMetadataAttributes() as $metadata_attribute_name => $metadata_attribute_label) { - $form['source_dependent(']['field_map'][$metadata_attribute_name] = [ + $form['source_dependent']['field_map'][$metadata_attribute_name] = [ '#type' => 'select', '#title' => $metadata_attribute_label, '#options' => $options, - '#default_value' => isset($field_map[$metadata_attribute_name]) ? $field_map[$metadata_attribute_name] : '_none', + '#default_value' => isset($field_map[$metadata_attribute_name]) ? $field_map[$metadata_attribute_name] : MediaSourceInterface::METADATA_FIELD_EMPTY, ]; } } @@ -198,8 +198,8 @@ ]; $form['workflow']['options']['status']['#description'] = $this->t('Media will be automatically published when created.'); - $form['workflow']['options']['new_revision']['#description'] = $this->t('Automatically create new revisions. Users with the Administer media permission will be able to override this option.'); - $form['workflow']['options']['queue_thumbnail_downloads']['#description'] = $this->t('Download thumbnails via a queue.'); + $form['workflow']['options']['new_revision']['#description'] = $this->t('Automatically create new revisions. Users with the "Administer media" permission will be able to override this option.'); + $form['workflow']['options']['queue_thumbnail_downloads']['#description'] = $this->t('Download thumbnails via a queue. When using some remote media provides as source, the thumbnail generation could be a slow process. Using a queue allows for this process to be handled in background.'); if ($this->moduleHandler->moduleExists('language')) { $form['language'] = [ @@ -247,11 +247,11 @@ * @param \Drupal\Core\Form\FormStateInterface $form_state * Parent form state. * - * @return \Drupal\Core\Form\SubFormStateInterface + * @return \Drupal\Core\Form\SubformStateInterface * Sub-form state for the media source configuration form. */ protected function getSourceSubFormState(array $form, FormStateInterface $form_state) { - return SubformState::createForSubform($form['source_dependent(']['source_configuration'], $form, $form_state) + return SubformState::createForSubform($form['source_dependent']['source_configuration'], $form, $form_state) ->set('operation', $this->operation) ->set('type', $this->entity); } @@ -262,9 +262,9 @@ public function validateForm(array &$form, FormStateInterface $form_state) { parent::validateForm($form, $form_state); - if ($form['source_dependent(']['source_configuration']) { + if ($form['source_dependent']['source_configuration']) { // Let the selected plugin validate its settings. - $this->entity->getSource()->validateConfigurationForm($form['source_dependent(']['source_configuration'], $this->getSourceSubFormState($form, $form_state)); + $this->entity->getSource()->validateConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state)); } } @@ -275,19 +275,19 @@ $form_state->setValue('field_map', array_filter( $form_state->getValue('field_map', []), function ($item) { - return $item != '_none'; + return $item != MediaSourceInterface::METADATA_FIELD_EMPTY; } )); parent::submitForm($form, $form_state); - $this->entity->setQueueThumbnailDownloadsStatus((bool) $form_state->getValue(['options', 'queue_thumbnail_downloads'])); - $this->entity->setStatus((bool) $form_state->getValue(['options', 'status'])); - $this->entity->setNewRevision((bool) $form_state->getValue(['options', 'new_revision'])); + $this->entity->setQueueThumbnailDownloadsStatus((bool) $form_state->getValue(['options', 'queue_thumbnail_downloads'])) + ->setStatus((bool) $form_state->getValue(['options', 'status'])) + ->setNewRevision((bool) $form_state->getValue(['options', 'new_revision'])); - if ($form['source_dependent(']['source_configuration']) { + if ($form['source_dependent']['source_configuration']) { // Let the selected plugin save its settings. - $this->entity->getSource()->submitConfigurationForm($form['source_dependent(']['source_configuration'], $this->getSourceSubFormState($form, $form_state)); + $this->entity->getSource()->submitConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state)); } } @@ -316,7 +316,6 @@ $source_field = $source->getSourceFieldDefinition($media_type); if (!$source_field) { $source_field = $source->createSourceField($media_type); - /** @var \Drupal\field\FieldStorageConfigInterface $storage */ $storage = $source_field->getFieldStorageDefinition(); if ($storage->isNew() || !$storage->isLocked()) { @@ -355,7 +354,7 @@ } elseif ($status === SAVED_NEW) { drupal_set_message($this->t('The media type %name has been added.', $t_args)); - $this->logger('media')->notice('Added type %name.', $t_args); + $this->logger('media')->notice('Added media type %name.', $t_args); } // Override the "status" base field default value, for this media type. diff -u b/core/modules/media/src/MediaTypeInterface.php b/core/modules/media/src/MediaTypeInterface.php --- b/core/modules/media/src/MediaTypeInterface.php +++ b/core/modules/media/src/MediaTypeInterface.php @@ -9,10 +9,9 @@ /** * Provides an interface defining a media type entity. * - * Media types are bundles for the media entity. They are used to group media - * with the same semantics. Media types are not about where media comes from. - * They are about the semantics that media has in the context of a given Drupal - * site. + * Media types are bundles for media items. They are used to group media with + * the same semantics. Media types are not about where media comes from. They + * are about the semantics that media has in the context of a given Drupal site. * * Media sources, on the other hand, are aware where media comes from and know * how to represent and handle it in Drupal's context. They are aware of the low @@ -26,7 +25,8 @@ * different things. * - Media sources that represent files could be used with media types like * "Invoices", "Subtitles", "Meeting notes", etc. They are all files stored on - * some kind of storage, but their meaning is different. + * some kind of storage, but their meaning and uses in a Drupal site are + * different. * * @see \Drupal\media\MediaSourceInterface */ @@ -52,7 +52,7 @@ public function setQueueThumbnailDownloadsStatus($queue_thumbnail_downloads); /** - * Returns the media source. + * Returns the media source plugin. * * @return \Drupal\media\MediaSourceInterface * The media source. @@ -72,14 +72,14 @@ /** * Returns the metadata field map. * - * Field mapping allows site builders to map media item related metadata to + * Field mapping allows site builders to map media item-related metadata to * entity fields. This information will be used when saving a given media item * and if metadata values will be available they are going to be automatically * copied to the corresponding entity fields. * * @return array - * Field mapping array with fields provided by the type plugin as keys and - * Drupal Entity fields as values. + * Field mapping array provided by media source with metadata attribute + * names as keys and entity field names as values. */ public function getFieldMap(); @@ -88,10 +88,10 @@ * * @param array $map - * Field mapping with metadata attribute names as keys and entity field - * names as values. + * Field mapping array with metadata attribute names as keys and entity + * field names as values. * * @return $this */ - public function setFieldMap($map); + public function setFieldMap(array $map); } diff -u b/core/modules/media/src/MediaTypeListBuilder.php b/core/modules/media/src/MediaTypeListBuilder.php --- b/core/modules/media/src/MediaTypeListBuilder.php +++ b/core/modules/media/src/MediaTypeListBuilder.php @@ -10,7 +10,7 @@ /** * Provides a listing of media types. */ -class MediaTypeListBuilder extends ConfigEntityListBuilder implements EntityHandlerInterface { +class MediaTypeListBuilder extends ConfigEntityListBuilder { /** * {@inheritdoc} diff -u b/core/modules/media/src/MediaViewsData.php b/core/modules/media/src/MediaViewsData.php --- b/core/modules/media/src/MediaViewsData.php +++ b/core/modules/media/src/MediaViewsData.php @@ -5,7 +5,7 @@ use Drupal\views\EntityViewsData; /** - * Provides the views data for the media entity type. + * Provides the Views data for the media entity type. */ class MediaViewsData extends EntityViewsData { diff -u b/core/modules/media/src/Plugin/Action/PublishMedia.php b/core/modules/media/src/Plugin/Action/PublishMedia.php --- b/core/modules/media/src/Plugin/Action/PublishMedia.php +++ b/core/modules/media/src/Plugin/Action/PublishMedia.php @@ -4,7 +4,7 @@ use Drupal\Core\Action\ActionBase; use Drupal\Core\Session\AccountInterface; -use Drupal\media\Entity\Media; +use Drupal\media\MediaInterface; /** * Publishes a media item. @@ -20,8 +20,10 @@ /** * {@inheritdoc} */ - public function execute(Media $entity = NULL) { - $entity->setPublished()->save(); + public function execute(MediaInterface $entity = NULL) { + if ($entity) { + $entity->setPublished()->save(); + } } /** diff -u b/core/modules/media/src/Plugin/Action/SaveMedia.php b/core/modules/media/src/Plugin/Action/SaveMedia.php --- b/core/modules/media/src/Plugin/Action/SaveMedia.php +++ b/core/modules/media/src/Plugin/Action/SaveMedia.php @@ -4,9 +4,10 @@ use Drupal\Core\Action\ActionBase; use Drupal\Core\Session\AccountInterface; +use Drupal\media\MediaInterface; /** - * Provides an action that can save any entity. + * Saves a media item. * * @Action( * id = "media_save_action", @@ -19,11 +20,13 @@ /** * {@inheritdoc} */ - public function execute($entity = NULL) { - // We need to change at least one value, otherwise the changed timestamp - // will not be updated. - $entity->changed = 0; - $entity->save(); + public function execute(MediaInterface $entity = NULL) { + if ($entity) { + // We need to change at least one value, otherwise the changed timestamp + // will not be updated. + $entity->changed = 0; + $entity->save(); + } } /** diff -u b/core/modules/media/src/Plugin/Action/UnpublishMedia.php b/core/modules/media/src/Plugin/Action/UnpublishMedia.php --- b/core/modules/media/src/Plugin/Action/UnpublishMedia.php +++ b/core/modules/media/src/Plugin/Action/UnpublishMedia.php @@ -4,7 +4,7 @@ use Drupal\Core\Action\ActionBase; use Drupal\Core\Session\AccountInterface; -use Drupal\media\Entity\Media; +use Drupal\media\MediaInterface; /** * Unpublishes a media item. @@ -20,8 +20,10 @@ /** * {@inheritdoc} */ - public function execute(Media $entity = NULL) { - $entity->setUnpublished()->save(); + public function execute(MediaInterface $entity = NULL) { + if ($entity) { + $entity->setUnpublished()->save(); + } } /** 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 @@ -2,6 +2,7 @@ namespace Drupal\media\Plugin\Field\FieldFormatter; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountInterface; @@ -9,6 +10,7 @@ use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatter; use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; use Drupal\Core\Render\RendererInterface; +use Drupal\media\MediaInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Field\FieldDefinitionInterface; @@ -129,48 +131,31 @@ */ public function viewElements(FieldItemListInterface $items, $langcode) { $elements = []; - $media = $this->getEntitiesToView($items, $langcode); + $media_items = $this->getEntitiesToView($items, $langcode); // Early opt-out if the field is empty. - if (empty($media)) { + if (empty($media_items)) { return $elements; } - $url = NULL; - $image_link_setting = $this->getSetting('image_link'); - // Check if the formatter involves a link. - if ($image_link_setting == 'content') { - $entity = $items->getEntity(); - if (!$entity->isNew()) { - $url = $entity->toUrl(); - } - } - elseif ($image_link_setting === 'media') { - $link_media = TRUE; - } - $image_style_setting = $this->getSetting('image_style'); - /** @var \Drupal\media\MediaInterface[] $media */ - foreach ($media as $delta => $media_item) { - if (isset($link_media)) { - $url = $media_item->toUrl(); - } - + /** @var \Drupal\media\MediaInterface[] $media_items */ + foreach ($media_items as $delta => $media) { $elements[$delta] = [ '#theme' => 'image_formatter', - '#item' => $media_item->get('thumbnail'), + '#item' => $media->get('thumbnail')->first(), '#item_attributes' => [], - '#image_style' => $image_style_setting, - '#url' => $url, + '#image_style' => $this->getSetting('image_style'), + '#url' => $this->getMediaUrl($media, $items->getEntity()), ]; // Add cacheability of each item in the field. - $this->renderer->addCacheableDependency($elements[$delta], $media_item); + $this->renderer->addCacheableDependency($elements[$delta], $media); } // Add cacheability of the image style setting. - if ($image_link_setting && ($image_style = $this->imageStyleStorage->load($image_style_setting))) { + if ($this->getSetting('image_link') && ($image_style = $this->imageStyleStorage->load($image_style_setting))) { $this->renderer->addCacheableDependency($elements, $image_style); } @@ -183,8 +168,34 @@ public static function isApplicable(FieldDefinitionInterface $field_definition) { // This formatter is only available for entity types that reference // media items. - $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type'); - return $target_type == 'media'; + return ($field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'media'); + } + + /** + * Get the URL for the media thumbnail. + * + * @param \Drupal\media\MediaInterface $media + * The media item. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity that the field belongs to. + * + * @return \Drupal\Core\Url|null + * The URL object for the media item or null if we don't want to add + * a link. + */ + protected function getMediaUrl(MediaInterface $media, EntityInterface $entity) { + $url = NULL; + $image_link_setting = $this->getSetting('image_link'); + // Check if the formatter involves a link. + if ($image_link_setting == 'content') { + if (!$entity->isNew()) { + $url = $entity->toUrl(); + } + } + elseif ($image_link_setting === 'media') { + $url = $media->toUrl(); + } + return $url; } } diff -u b/core/modules/media/src/Plugin/QueueWorker/ThumbnailDownloader.php b/core/modules/media/src/Plugin/QueueWorker/ThumbnailDownloader.php --- b/core/modules/media/src/Plugin/QueueWorker/ThumbnailDownloader.php +++ b/core/modules/media/src/Plugin/QueueWorker/ThumbnailDownloader.php @@ -2,6 +2,7 @@ namespace Drupal\media\Plugin\QueueWorker; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\media\Entity\Media; use Drupal\Core\Queue\QueueWorkerBase; @@ -19,10 +20,27 @@ class ThumbnailDownloader extends QueueWorkerBase implements ContainerFactoryPluginInterface { /** - * {@inheritdoc} + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Constructs a new class instance. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * Entity type manager service. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->entityTypeManager = $entity_type_manager; } /** @@ -32,7 +50,8 @@ return new static( $configuration, $plugin_id, - $plugin_definition + $plugin_definition, + $container->get('entity_type.manager') ); } @@ -40,7 +59,8 @@ * {@inheritdoc} */ public function processItem($data) { - if ($media = Media::load($data['id'])) { + /** @var \Drupal\media\Entity\Media $media */ + if ($media = $this->entityTypeManager->getStorage('media')->load($data['id'])) { $media->updateQueuedThumbnail(); $media->save(); } diff -u b/core/modules/media/src/Plugin/views/wizard/Media.php b/core/modules/media/src/Plugin/views/wizard/Media.php --- b/core/modules/media/src/Plugin/views/wizard/Media.php +++ b/core/modules/media/src/Plugin/views/wizard/Media.php @@ -5,7 +5,7 @@ use Drupal\views\Plugin\views\wizard\WizardPluginBase; /** - * Provides views creation wizard for Media. + * Provides Views creation wizard for Media. * * @ViewsWizard( * id = "media", @@ -29,7 +29,7 @@ */ protected $filters = [ 'status' => [ - 'value' => TRUE, + 'value' => '1', 'table' => 'media_field_data', 'field' => 'status', 'plugin_id' => 'boolean', diff -u b/core/modules/media/src/Plugin/views/wizard/MediaRevision.php b/core/modules/media/src/Plugin/views/wizard/MediaRevision.php --- b/core/modules/media/src/Plugin/views/wizard/MediaRevision.php +++ b/core/modules/media/src/Plugin/views/wizard/MediaRevision.php @@ -5,7 +5,7 @@ use Drupal\views\Plugin\views\wizard\WizardPluginBase; /** - * Provides views creation wizard for Media revisions. + * Provides Views creation wizard for Media revisions. * * @ViewsWizard( * id = "media_revision", @@ -20,7 +20,7 @@ * * @var string */ - protected $createdColumn = 'created'; + protected $createdColumn = 'media_field_revision-created'; /** * Set default values for the filters. 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 @@ -4,7 +4,7 @@ * Default theme implementation to present a media item. * * Available variables: - * - media: The media item with limited access to object properties and + * - media: The media item, with limited access to object properties and * methods. Only method names starting with "get", "has", or "is" and * a few common methods such as "id", "label", and "bundle" are available. * For example: diff -u b/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php --- b/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php @@ -5,7 +5,7 @@ use Symfony\Component\Validator\Constraint; /** - * Checks if a value is a valid Tweet embed code/URL. + * A media test constraint. * * @Constraint( * id = "MediaTestConstraint", diff -u b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php --- b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php @@ -8,7 +8,7 @@ use Drupal\media\MediaSourceBase; /** - * Provides generic media type. + * Provides test media source. * * @MediaSource( * id = "test", @@ -23,6 +23,9 @@ * {@inheritdoc} */ public function getMetadataAttributes() { + // The metadata attributes are kept in state storage. This allows tests to + // change the metadata attributes and makes it easier to test different + // variations. $attributes = \Drupal::state()->get('media_source_test_attributes', [ 'attribute_1' => ['label' => $this->t('Attribute 1'), 'value' => 'Value 1'], 'attribute_2' => ['label' => $this->t('Attribute 2'), 'value' => 'Value 1'], @@ -76,7 +79,7 @@ $form['test_config_value'] = [ '#type' => 'textfield', '#title' => $this->t('Test config value'), - '#default_value' => empty($this->configuration['test_config_value']) ? NULL : $this->configuration['test_config_value'], + '#default_value' => $this->configuration['test_config_value'], ]; return $form; diff -u b/core/modules/media/tests/modules/media_test_type/config/install/media.type.test.yml b/core/modules/media/tests/modules/media_test_type/config/install/media.type.test.yml --- b/core/modules/media/tests/modules/media_test_type/config/install/media.type.test.yml +++ b/core/modules/media/tests/modules/media_test_type/config/install/media.type.test.yml @@ -10 +10,2 @@ -field_map: { } +field_map: + metadata_attribute: 'field_attribute_config_test' 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 @@ -17,34 +17,21 @@ use AssertPageCacheContextsAndTagsTrait; /** - * The test media type. - * - * @var \Drupal\media\MediaTypeInterface - */ - protected $testMediaType; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - $this->testMediaType = $this->createMediaType(); - } - - /** * Test some access control functionality. */ public function testMediaAccess() { $assert_session = $this->assertSession(); + $media_type = $this->createMediaType(); + // Create media. $media = Media::create([ - 'bundle' => $this->testMediaType->id(), + 'bundle' => $media_type->id(), 'name' => 'Unnamed', ]); $media->save(); $user_media = Media::create([ - 'bundle' => $this->testMediaType->id(), + 'bundle' => $media_type->id(), 'name' => 'Unnamed', 'uid' => $this->nonAdminUser->id(), ]); @@ -75,11 +62,11 @@ $assert_session->statusCodeEquals(200); // Test 'create media' permission. - $this->drupalGet('media/add/' . $this->testMediaType->id()); + $this->drupalGet('media/add/' . $media_type->id()); $this->assertCacheContext('user.permissions'); $assert_session->statusCodeEquals(403); $this->grantPermissions($role, ['create media']); - $this->drupalGet('media/add/' . $this->testMediaType->id()); + $this->drupalGet('media/add/' . $media_type->id()); $this->assertCacheContext('user.permissions'); $assert_session->statusCodeEquals(200); diff -u b/core/modules/media/tests/src/Functional/MediaCacheTagsTest.php b/core/modules/media/tests/src/Functional/MediaCacheTagsTest.php --- b/core/modules/media/tests/src/Functional/MediaCacheTagsTest.php +++ b/core/modules/media/tests/src/Functional/MediaCacheTagsTest.php @@ -15,7 +15,7 @@ */ class MediaCacheTagsTest extends EntityWithUriCacheTagsTestBase { - use MediaFunctionalTestTrait; + use MediaFunctionalTestCreateMediaTypeTrait; /** * {@inheritdoc} @@ -64,10 +64,9 @@ /** * {@inheritdoc} - * - * Each media item must have an author and a thumbnail. */ protected function getAdditionalCacheTagsForEntity(EntityInterface $media) { + // Each media item must have an author and a thumbnail. return [ 'user:' . $media->getOwnerId(), 'config:image.style.thumbnail', diff -u b/core/modules/media/tests/src/Functional/MediaFunctionalTestBase.php b/core/modules/media/tests/src/Functional/MediaFunctionalTestBase.php --- b/core/modules/media/tests/src/Functional/MediaFunctionalTestBase.php +++ b/core/modules/media/tests/src/Functional/MediaFunctionalTestBase.php @@ -6,12 +6,11 @@ /** * Base class for Media functional tests. - * - * @package Drupal\Tests\media\Functional */ abstract class MediaFunctionalTestBase extends BrowserTestBase { use MediaFunctionalTestTrait; + use MediaFunctionalTestCreateMediaTypeTrait; /** * Modules to enable. @@ -29,66 +28,2 @@ - /** - * Permissions for the admin user that will be logged in for test. - * - * @var array - */ - protected static $adminUserPermissions = [ - // Media entity permissions. - 'administer media', - 'administer media fields', - 'administer media form display', - 'administer media display', - 'administer media types', - 'view media', - 'create media', - 'update media', - 'update any media', - 'delete media', - 'delete any media', - // Other permissions. - 'administer views', - 'access content overview', - 'view all revisions', - 'administer content types', - 'administer node fields', - 'administer node form display', - 'bypass node access', - ]; - - /** - * An admin test user account. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $adminUser; - - /** - * A non-admin test user account. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $nonAdminUser; - - /** - * The storage handler. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected $storage; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - - // Have two users ready to be used in tests. - $this->adminUser = $this->drupalCreateUser(static::$adminUserPermissions); - $this->nonAdminUser = $this->drupalCreateUser([]); - // Start off logged in as admin. - $this->drupalLogin($this->adminUser); - - $this->storage = $this->container->get('entity_type.manager')->getStorage('media'); - } - } diff -u b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php --- b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php +++ b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php @@ -2,64 +2,73 @@ namespace Drupal\Tests\media\Functional; -use Drupal\media\Entity\MediaType; - /** * Trait with helpers for Media functional tests. */ trait MediaFunctionalTestTrait { /** - * Creates a media type. + * Permissions for the admin user that will be logged-in for test. + * + * @var array + */ + protected static $adminUserPermissions = [ + // Media entity permissions. + 'administer media', + 'administer media fields', + 'administer media form display', + 'administer media display', + 'administer media types', + 'view media', + 'create media', + 'update media', + 'update any media', + 'delete media', + 'delete any media', + // Other permissions. + 'administer views', + 'access content overview', + 'view all revisions', + 'administer content types', + 'administer node fields', + 'administer node form display', + 'bypass node access', + ]; + + /** + * An admin test user account. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $adminUser; + + /** + * A non-admin test user account. * - * @param array $values - * The media type values. - * @param string $source - * (optional) The media source plugin that is responsible for additional - * logic related to this media type. + * @var \Drupal\Core\Session\AccountInterface + */ + protected $nonAdminUser; + + /** + * The storage service. * - * @return \Drupal\media\MediaTypeInterface - * A newly created media type. + * @var \Drupal\Core\Entity\EntityStorageInterface */ - protected function createMediaType(array $values = [], $source = 'test') { - if (!isset($values['bundle'])) { - $id = strtolower($this->randomMachineName()); - } - else { - $id = $values['bundle']; - } - $values += [ - 'id' => $id, - 'label' => $id, - 'source' => $source, - 'source_configuration' => [], - 'field_map' => [], - 'new_revision' => FALSE, - ]; - - $media_type = MediaType::create($values); - $status = $media_type->save(); - - $this->assertEqual(SAVED_NEW, $status, 'Media type was created successfully.'); - - // Ensure that the source field exists. - $source = $media_type->getSource(); - $source_field = $source->getSourceFieldDefinition($media_type); - if (!$source_field) { - $source_field = $source->createSourceField($media_type); - /** @var \Drupal\field\FieldStorageConfigInterface $storage */ - $storage = $source_field->getFieldStorageDefinition(); - $storage->setLocked(TRUE)->save(); - $source_field->save(); - - $media_type - ->set('source_configuration', [ - 'source_field' => $source_field->getName(), - ]) - ->save(); - } + protected $storage; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Have two users ready to be used in tests. + $this->adminUser = $this->drupalCreateUser(static::$adminUserPermissions); + $this->nonAdminUser = $this->drupalCreateUser([]); + // Start off logged in as admin. + $this->drupalLogin($this->adminUser); - return $media_type; + $this->storage = $this->container->get('entity_type.manager')->getStorage('media'); } } diff -u b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php --- b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php +++ b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php @@ -22,13 +22,6 @@ ]; /** - * The test media type. - * - * @var \Drupal\media\MediaTypeInterface - */ - protected $testMediaType; - - /** * {@inheritdoc} */ protected function setUp() { @@ -59,7 +52,7 @@ $media_name = $this->randomMachineName(); $page->fillField('name[0][value]', $media_name); $revision_log_message = $this->randomString(); - $page->fillField('revision_log[0][value]', $revision_log_message); + $page->fillField('revision_log_message[0][value]', $revision_log_message); $page->pressButton('Save and publish'); $media_id = $this->container->get('entity.query')->get('media')->execute(); $media_id = reset($media_id); @@ -68,7 +61,8 @@ ->getStorage('media') ->loadUnchanged($media_id); $this->assertEquals($media->getRevisionLogMessage(), $revision_log_message); - $assert_session->titleEquals($media->label() . ' | Drupal'); + $this->assertEquals($media->label(), $media_name); + $assert_session->titleEquals($media_name . ' | Drupal'); // Tests media edit form. $media_type->setNewRevision(FALSE); @@ -79,6 +73,11 @@ $media_name = $this->randomMachineName(); $page->fillField('name[0][value]', $media_name2); $page->pressButton('Save and keep published'); + /** @var \Drupal\media\MediaInterface $media */ + $media = $this->container->get('entity_type.manager') + ->getStorage('media') + ->loadUnchanged($media_id); + $this->assertEquals($media->label(), $media_name2); $assert_session->titleEquals($media_name2 . ' | Drupal'); // Test that there is no empty vertical tabs element, if the container is @@ -92,19 +91,18 @@ $this->drupalLogin($this->nonAdminUser); // Check the container is not present. $this->drupalGet('media/' . $media_id . '/edit'); - // An empty tab container would look like this. - $raw_html = '
' . "\n" . '
'; - $assert_session->responseNotContains($raw_html); + $assert_session->elementNotExists('css', 'input.vertical-tabs__active-tab'); // Continue testing as admin. $this->drupalLogin($this->adminUser); // Enable revisions by default. + $previous_revision_id = $media->getRevisionId(); $media_type->setNewRevision(TRUE); $media_type->save(); $this->drupalGet('media/' . $media_id . '/edit'); $assert_session->checkboxChecked('edit-revision'); $page->fillField('name[0][value]', $media_name); - $page->fillField('revision_log[0][value]', $revision_log_message); + $page->fillField('revision_log_message[0][value]', $revision_log_message); $page->pressButton('Save and keep published'); $assert_session->titleEquals($media_name . ' | Drupal'); /** @var \Drupal\media\MediaInterface $media */ @@ -112,6 +110,7 @@ ->getStorage('media') ->loadUnchanged($media_id); $this->assertEquals($media->getRevisionLogMessage(), $revision_log_message); + $this->assertNotEquals($previous_revision_id, $media->getRevisionId()); // Tests media delete form. $this->drupalGet('media/' . $media_id . '/edit'); diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php @@ -3,16 +3,16 @@ namespace Drupal\Tests\media\FunctionalJavascript; use Drupal\FunctionalJavascriptTests\JavascriptTestBase; +use Drupal\Tests\media\Functional\MediaFunctionalTestCreateMediaTypeTrait; use Drupal\Tests\media\Functional\MediaFunctionalTestTrait; /** * Base class for Media functional JavaScript tests. - * - * @package Drupal\Tests\media\FunctionalJavascript */ abstract class MediaJavascriptTestBase extends JavascriptTestBase { use MediaFunctionalTestTrait; + use MediaFunctionalTestCreateMediaTypeTrait; /** * Modules to enable. @@ -29,70 +29,6 @@ ]; /** - * Permissions for the admin user that will be logged-in for test. - * - * @var array - */ - protected static $adminUserPermissions = [ - // Media entity permissions. - 'administer media', - 'administer media fields', - 'administer media form display', - 'administer media display', - 'administer media types', - 'view media', - 'create media', - 'update media', - 'update any media', - 'delete media', - 'delete any media', - // Other permissions. - 'administer views', - 'access content overview', - 'view all revisions', - 'administer content types', - 'administer node fields', - 'administer node form display', - 'bypass node access', - ]; - - /** - * An admin test user account. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $adminUser; - - /** - * A non-admin test user account. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $nonAdminUser; - - /** - * The storage service. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected $storage; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - - // Have two users ready to be used in tests. - $this->adminUser = $this->drupalCreateUser(static::$adminUserPermissions); - $this->nonAdminUser = $this->drupalCreateUser([]); - // Start off logged in as admin. - $this->drupalLogin($this->adminUser); - - $this->storage = $this->container->get('entity_type.manager')->getStorage('media'); - } - - /** * Waits and asserts that a given element is visible. * * @param string $selector diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaTypeCreationTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaTypeCreationTest.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaTypeCreationTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaTypeCreationTest.php @@ -87,7 +87,7 @@ $page->selectFieldOption('source_configuration[source_field]', 'field_media_test'); $page->pressButton('Save'); - // Check that there are not fields created. + // Check that no new fields were created. $this->drupalGet("admin/structure/media/manage/{$mediaTypeMachineName}/fields"); // The reused field should be present... $this->assertSession()->pageTextContains('field_media_test'); diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php @@ -5,6 +5,7 @@ use Drupal\field\FieldConfigInterface; use Drupal\media\Entity\Media; use Drupal\media\Entity\MediaType; +use Drupal\media\MediaSourceInterface; /** * Ensures that media UI works correctly. @@ -83,8 +84,8 @@ $this->assertFalse($source_field->isNew(), 'Source field was saved.'); /** @var \Drupal\field\FieldStorageConfigInterface $storage */ $storage = $source_field->getFieldStorageDefinition(); - $this->assertFalse($storage->isNew(), 'Source field definition was saved.'); - $this->assertTrue($storage->isLocked(), 'Source field definition was locked.'); + $this->assertFalse($storage->isNew(), 'Source field storage definition was saved.'); + $this->assertTrue($storage->isLocked(), 'Source field storage definition was locked.'); /** @var \Drupal\media\MediaTypeInterface $media_type_storage */ $media_type_storage = $this->container->get('entity_type.manager')->getStorage('media_type'); @@ -107,7 +108,7 @@ $assert_session->checkboxChecked('edit-options-status'); $assert_session->checkboxNotChecked('edit-options-queue-thumbnail-downloads'); $assert_session->pageTextContains('Create new revision'); - $assert_session->pageTextContains('Automatically create new revisions. Users with the Administer media permission will be able to override this option.'); + $assert_session->pageTextContains('Automatically create new revisions. Users with the "Administer media" permission will be able to override this option.'); $assert_session->pageTextContains('Download thumbnails via a queue.'); $assert_session->pageTextContains('Media will be automatically published when created.'); $assert_session->pageTextContains('Media sources can provide metadata fields such as title, caption, size information, credits, etc. Media can automatically save this metadata information to entity fields, which can be configured below. Information will only be mapped if the entity field is empty.'); @@ -147,7 +148,7 @@ $assert_session->checkboxChecked('options[queue_thumbnail_downloads]'); $assert_session->fieldValueEquals('Test config value', 'This is new config value.'); $assert_session->fieldValueEquals('Attribute 1', 'name'); - $assert_session->fieldValueEquals('Attribute 2', '_none'); + $assert_session->fieldValueEquals('Attribute 2', MediaSourceInterface::METADATA_FIELD_EMPTY); /** @var \Drupal\media\MediaTypeInterface $loaded_media_type */ $loaded_media_type = $this->container->get('entity_type.manager') @@ -182,7 +183,8 @@ $assert_session->addressEquals('admin/structure/media'); $assert_session->pageTextContains('The media type ' . $new_name . ' has been deleted.'); - // Test type delete prevention when there is existing media. + // Test that the system for preventing the deletion of media types works + // (they cannot be deleted if there is media content of that type/bundle). $media_type2 = $this->createMediaType(); $label2 = $media_type2->label(); $media = Media::create(['name' => 'lorem ipsum', 'bundle' => $media_type2->id()]); diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaViewsWizardTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaViewsWizardTest.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaViewsWizardTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaViewsWizardTest.php @@ -31,7 +31,6 @@ $page->checkField('page[create]'); $page->fillField('page[path]', $this->randomMachineName(16)); $page->pressButton('Save and edit'); - $assert_session->assertWaitOnAjaxRequest(); $this->assertEquals($session->getCurrentUrl(), $this->baseUrl . '/admin/structure/views/view/' . $view_id); $view = Views::getView($view_id); @@ -65,7 +64,6 @@ $page->checkField('page[create]'); $page->fillField('page[path]', $this->randomMachineName(16)); $page->pressButton('Save and edit'); - $assert_session->assertWaitOnAjaxRequest(); $this->assertEquals($session->getCurrentUrl(), $this->baseUrl . '/admin/structure/views/view/' . $view_id); $view = Views::getView($view_id); diff -u b/core/modules/media/tests/src/Kernel/BasicCreationTest.php b/core/modules/media/tests/src/Kernel/BasicCreationTest.php --- b/core/modules/media/tests/src/Kernel/BasicCreationTest.php +++ b/core/modules/media/tests/src/Kernel/BasicCreationTest.php @@ -32,7 +32,7 @@ // Source field is not set on the media source, but it should never // be created automatically when a config is being imported. $this->assertEquals(['source_field' => '', 'test_config_value' => 'Kakec'], $test_media_type->get('source_configuration'), 'Could not assure the correct media source configuration.'); - $this->assertEquals([], $test_media_type->get('field_map'), 'Could not assure the correct field map.'); + $this->assertEquals(['metadata_attribute' => 'field_attribute_config_test'], $test_media_type->get('field_map'), 'Could not assure the correct field map.'); } /** @@ -52,7 +52,7 @@ $this->assertEquals($this->testMediaType->id(), $media->bundle(), 'The media item was not created with the correct type.'); $this->assertEquals('Unnamed', $media->label(), 'The media item was not created with the correct name.'); $source_field_name = $media->bundle->entity->getSource()->getSourceFieldDefinition($media->bundle->entity)->getName(); - $this->assertEquals('Nation of sheep, ruled by wolves, owned by pigs.', $media->get($source_field_name)->value, 'Source returns correct source field.'); + $this->assertEquals('Nation of sheep, ruled by wolves, owned by pigs.', $media->get($source_field_name)->value, 'Source returns incorrect source field value.'); } } 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 @@ -22,10 +22,11 @@ // Make sure that the default name is set if not provided by the user. /** @var \Drupal\media\MediaInterface $media */ $media = Media::create(['bundle' => $this->testMediaType->id()]); - $this->assertEquals('default_name', $media->getSource()->getPluginDefinition()['default_name_metadata_attribute'], 'Default metadata attribute is used for the default name.'); - $this->assertEquals('media:' . $media->bundle() . ':' . $media->uuid(), $media->getSource()->getMetadata($media, 'default_name'), 'Value of the default name metadata attribute looks correct.'); + $media_source = $media->getSource(); + $this->assertEquals('default_name', $media_source->getPluginDefinition()['default_name_metadata_attribute'], 'Default metadata attribute is not used for the default name.'); + $this->assertEquals('media:' . $media->bundle() . ':' . $media->uuid(), $media_source->getMetadata($media, 'default_name'), 'Value of the default name metadata attribute does not look correct.'); $media->save(); - $this->assertEquals('media:' . $media->bundle() . ':' . $media->uuid(), $media->label(), 'Default name was set correctly.'); + $this->assertEquals('media:' . $media->bundle() . ':' . $media->uuid(), $media->label(), 'Default name was not set correctly.'); // Make sure that the user-supplied name is used. /** @var \Drupal\media\MediaInterface $media */ @@ -34,10 +35,11 @@ 'bundle' => $this->testMediaType->id(), 'name' => $name, ]); - $this->assertEquals('default_name', $media->getSource()->getPluginDefinition()['default_name_metadata_attribute'], 'Default metadata attribute is used for the default name.'); - $this->assertEquals('media:' . $media->bundle() . ':' . $media->uuid(), $media->getSource()->getMetadata($media, 'default_name'), 'Value of the default name metadata attribute looks correct.'); + $media_source = $media->getSource(); + $this->assertEquals('default_name', $media_source->getPluginDefinition()['default_name_metadata_attribute'], 'Default metadata attribute is not used for the default name.'); + $this->assertEquals('media:' . $media->bundle() . ':' . $media->uuid(), $media_source->getMetadata($media, 'default_name'), 'Value of the default name metadata attribute does not look correct.'); $media->save(); - $this->assertEquals($name, $media->label(), 'User-supplied name was set correctly.'); + $this->assertEquals($name, $media->label(), 'User-supplied name was not set correctly.'); // Change the default name attribute and see if it is used to set the name. $name = 'Old Major'; @@ -45,10 +47,11 @@ \Drupal::state()->set('media_source_test_definition', ['default_name_metadata_attribute' => 'alternative_name']); /** @var \Drupal\media\MediaInterface $media */ $media = Media::create(['bundle' => $this->testMediaType->id()]); - $this->assertEquals('alternative_name', $media->getSource()->getPluginDefinition()['default_name_metadata_attribute'], 'Correct metadata attribute is used for the default name.'); - $this->assertEquals($name, $media->getSource()->getMetadata($media, 'alternative_name'), 'Value of the default name metadata attribute looks correct.'); + $media_source = $media->getSource(); + $this->assertEquals('alternative_name', $media_source->getPluginDefinition()['default_name_metadata_attribute'], 'Correct metadata attribute is not used for the default name.'); + $this->assertEquals($name, $media_source->getMetadata($media, 'alternative_name'), 'Value of the default name metadata attribute does not look correct.'); $media->save(); - $this->assertEquals($name, $media->label(), 'Default name was set correctly.'); + $this->assertEquals($name, $media->label(), 'Default name was not set correctly.'); } /** @@ -86,9 +89,10 @@ 'bundle' => $this->testMediaType->id(), 'field_media_test' => 'some_value', ]); - $this->assertNull($media->getSource()->getMetadata($media, 'not_here_at_all'), 'NULL is returned if asking for a value of non-existing metadata.'); + $media_source = $media->getSource(); + $this->assertNull($media_source->getMetadata($media, 'not_here_at_all'), 'NULL is not returned if asking for a value of non-existing metadata.'); $media->save(); - $this->assertTrue($media->get($field_name)->isEmpty(), 'Non-existing metadata attribute was not mapped to the field.'); + $this->assertTrue($media->get($field_name)->isEmpty(), 'Non-existing metadata attribute was wrongly mapped to the field.'); // Define mapping and make sure that the value was stored in the field. \Drupal::state()->set('media_source_test_attributes', [ @@ -99,25 +103,26 @@ 'bundle' => $this->testMediaType->id(), 'field_media_test' => 'some_value', ]); - $this->assertEquals('Snowball', $media->getSource()->getMetadata($media, $attribute_name), 'Value of the metadata attribute is correct.'); + $media_source = $media->getSource(); + $this->assertEquals('Snowball', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.'); $media->save(); - $this->assertEquals('Snowball', $media->get($field_name)->value, 'Metadata attribute was correctly mapped to the field.'); + $this->assertEquals('Snowball', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.'); // Change the metadata attribute value and re-save the entity. Field value // should stay the same. \Drupal::state()->set('media_source_test_attributes', [ $attribute_name => ['title' => 'Attribute to map', 'value' => 'Pinkeye'], ]); - $this->assertEquals('Pinkeye', $media->getSource()->getMetadata($media, $attribute_name), 'Value of the metadata attribute is correct.'); + $this->assertEquals('Pinkeye', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.'); $media->save(); - $this->assertEquals('Snowball', $media->get($field_name)->value, 'Metadata attribute was correctly mapped to the field.'); + $this->assertEquals('Snowball', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.'); // Now change the value of the source field and make sure that the mapped // values update too. - $this->assertEquals('Pinkeye', $media->getSource()->getMetadata($media, $attribute_name), 'Value of the metadata attribute is correct.'); + $this->assertEquals('Pinkeye', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.'); $media->set('field_media_test', 'some_new_value'); $media->save(); - $this->assertEquals('Pinkeye', $media->get($field_name)->value, 'Metadata attribute was correctly mapped to the field.'); + $this->assertEquals('Pinkeye', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.'); // Remove the value of the mapped field and make sure that it is re-mapped // on save. @@ -125,9 +130,9 @@ $attribute_name => ['title' => 'Attribute to map', 'value' => 'Snowball'], ]); $media->{$field_name}->value = NULL; - $this->assertEquals('Snowball', $media->getSource()->getMetadata($media, $attribute_name), 'Value of the metadata attribute is correct.'); + $this->assertEquals('Snowball', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.'); $media->save(); - $this->assertEquals('Snowball', $media->get($field_name)->value, 'Metadata attribute was correctly mapped to the field.'); + $this->assertEquals('Snowball', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.'); } /** @@ -147,30 +152,31 @@ 'name' => 'Mr. Jones', 'field_media_test' => 'some_value', ]); - $this->assertEquals('public://thumbnail1.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is correct.'); + $media_source = $media->getSource(); + $this->assertEquals('public://thumbnail1.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.'); $media->save(); - $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was added to the media entity.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was not added to the media entity.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Now change the metadata attribute and make sure that the thumbnail stays // the same. \Drupal::state()->set('media_source_test_attributes', [ 'thumbnail_uri' => ['title' => 'Thumbnail', 'value' => 'public://thumbnail2.jpg'], ]); - $this->assertEquals('public://thumbnail2.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is correct.'); + $this->assertEquals('public://thumbnail2.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.'); $media->save(); - $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was preserved.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was not preserved.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Remove the thumbnail and make sure that it is auto-updated on save. $media->thumbnail->target_id = NULL; - $this->assertEquals('public://thumbnail2.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is correct.'); + $this->assertEquals('public://thumbnail2.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.'); $media->save(); - $this->assertEquals('public://thumbnail2.jpg', $media->thumbnail->entity->getFileUri(), 'New thumbnail was added to the media entity.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('public://thumbnail2.jpg', $media->thumbnail->entity->getFileUri(), 'New thumbnail was not added to the media entity.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Change the metadata attribute again, change the source field value too // and make sure that the thumbnail updates. @@ -178,11 +184,11 @@ 'thumbnail_uri' => ['title' => 'Thumbnail', 'value' => 'public://thumbnail1.jpg'], ]); $media->field_media_test->value = 'some_new_value'; - $this->assertEquals('public://thumbnail1.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is correct.'); + $this->assertEquals('public://thumbnail1.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.'); $media->save(); - $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'New thumbnail was added to the media entity.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'New thumbnail was not added to the media entity.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Change the thumbnail metadata attribute and make sure that the thumbnail // is set correctly. @@ -196,12 +202,13 @@ 'name' => 'Mr. Jones', 'field_media_test' => 'some_value', ]); - $this->assertEquals('public://thumbnail1.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the metadata attribute is correct.'); - $this->assertEquals('public://thumbnail2.jpg', $media->getSource()->getMetadata($media, 'alternative_thumbnail_uri'), 'Value of the thumbnail metadata attribute is correct.'); - $media->save(); - $this->assertEquals('public://thumbnail2.jpg', $media->thumbnail->entity->getFileUri(), 'Correct metadata attribute was used for the thumbnail.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $media_source = $media->getSource(); + $this->assertEquals('public://thumbnail1.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the metadata attribute is not correct.'); + $this->assertEquals('public://thumbnail2.jpg', $media_source->getMetadata($media, 'alternative_thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.'); + $media->save(); + $this->assertEquals('public://thumbnail2.jpg', $media->thumbnail->entity->getFileUri(), 'Correct metadata attribute was not used for the thumbnail.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Enable queued thumbnails and make sure that the entity gets the default // thumbnail initially. @@ -215,30 +222,30 @@ 'name' => 'Mr. Jones', 'field_media_test' => 'some_value', ]); - $this->assertEquals('public://thumbnail1.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the metadata attribute is correct.'); + $this->assertEquals('public://thumbnail1.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the metadata attribute is not correct.'); $media->save(); - $this->assertEquals('public://media-icons/generic/generic.png', $media->thumbnail->entity->getFileUri(), 'Default thumbnail was set initially.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('public://media-icons/generic/generic.png', $media->thumbnail->entity->getFileUri(), 'Default thumbnail was not set initially.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Process the queue item and make sure that the thumbnail was updated too. $queue_name = 'media_entity_thumbnail'; /** @var \Drupal\Core\Queue\QueueWorkerInterface $queue_worker */ $queue_worker = \Drupal::service('plugin.manager.queue_worker')->createInstance($queue_name); $queue = \Drupal::queue($queue_name); - $this->assertEquals(1, $queue->numberOfItems(), 'Item was added to the queue.'); + $this->assertEquals(1, $queue->numberOfItems(), 'Item was not added to the queue.'); $item = $queue->claimItem(); - $this->assertEquals($media->id(), $item->data['id'], 'Queue item that was created belongs to the correct entity.'); + $this->assertEquals($media->id(), $item->data['id'], 'Queue item that was created does not belong to the correct entity.'); $queue_worker->processItem($item->data); $queue->deleteItem($item); - $this->assertEquals(0, $queue->numberOfItems(), 'Item was removed from the queue.'); + $this->assertEquals(0, $queue->numberOfItems(), 'Item was not removed from the queue.'); $media = Media::load($media->id()); - $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was updated by the queue.'); - $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was not updated by the queue.'); + $this->assertEquals('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); // Set alt and title metadata attributes and make sure they are used for the // thumbnail. @@ -256,9 +263,9 @@ 'field_media_test' => 'some_value', ]); $media->save(); - $this->assertEquals('Boxer', $media->label(), 'Correct name was set on the media entity.'); - $this->assertEquals('This will be title.', $media->thumbnail->title, 'Title text was set on the thumbnail.'); - $this->assertEquals('This will be alt.', $media->thumbnail->alt, 'Alt text was set on the thumbnail.'); + $this->assertEquals('Boxer', $media->label(), 'Correct name was not set on the media entity.'); + $this->assertEquals('This will be title.', $media->thumbnail->title, 'Title text was not set on the thumbnail.'); + $this->assertEquals('This will be alt.', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.'); } /** @@ -283,24 +290,25 @@ $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 */ $violations = $media->validate(); - $this->assertEquals(1, $violations->count(), 'Expected number of validations found.'); - $this->assertEquals('Inappropriate text.', $violations->get(0)->getMessage(), 'Correct constraint validation message found.'); + $this->assertCount(1, $violations, 'Expected number of validations not found.'); + $this->assertEquals('Inappropriate text.', $violations->get(0)->getMessage(), 'Incorrect constraint validation message found.'); // Fix the violation and make sure it is not reported anymore. $media->set('name', 'I love Drupal!'); $violations = $media->validate(); - $this->assertEquals(0, $violations->count(), 'Expected number of validations found.'); + $this->assertCount(0, $violations, 'Expected number of validations not found.'); // Save and make sure it succeeded. - $this->assertEmpty($media->id(), 'Entity ID was not found.'); + $this->assertEmpty($media->id(), 'Entity ID was found.'); $media->save(); - $this->assertNotEmpty($media->id(), 'Entity ID was found.'); + $this->assertNotEmpty($media->id(), 'Entity ID was not found.'); // Test source field constraints. \Drupal::state()->set('media_source_test_field_constraints', [ @@ -321,24 +329,25 @@ $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 */ $violations = $media->validate(); - $this->assertEquals(1, $violations->count(), 'Expected number of validations found.'); - $this->assertEquals('Inappropriate text.', $violations->get(0)->getMessage(), 'Correct constraint validation message found.'); + $this->assertCount(1, $violations, 'Expected number of validations not found.'); + $this->assertEquals('Inappropriate text.', $violations->get(0)->getMessage(), 'Incorrect constraint validation message found.'); // Fix the violation and make sure it is not reported anymore. $media->set('field_media_test_constraints', 'I love Drupal!'); $violations = $media->validate(); - $this->assertEquals(0, $violations->count(), 'Expected number of validations found.'); + $this->assertCount(0, $violations, 'Expected number of validations not found.'); // Save and make sure it succeeded. - $this->assertEmpty($media->id(), 'Entity ID was not found.'); + $this->assertEmpty($media->id(), 'Entity ID was found.'); $media->save(); - $this->assertNotEmpty($media->id(), 'Entity ID was found.'); + $this->assertNotEmpty($media->id(), 'Entity ID was not found.'); } /** @@ -358,19 +367,19 @@ $field_storage = $field->getFieldStorageDefinition(); // Test field storage. - $this->assertTrue($field_storage->isNew(), 'Field storage is not saved automatically.'); - $this->assertTrue($field_storage->isLocked(), 'Field storage is locked.'); - $this->assertEquals('string', $field_storage->getType(), 'Field is of correct type.'); - $this->assertEquals('field_media_test_1', $field_storage->getName(), 'Correct field name is used.'); - $this->assertEquals('media', $field_storage->getTargetEntityTypeId(), 'Field is targeting media entities.'); + $this->assertTrue($field_storage->isNew(), 'Field storage is saved automatically.'); + $this->assertTrue($field_storage->isLocked(), 'Field storage is not locked.'); + $this->assertEquals('string', $field_storage->getType(), 'Field is not of correct type.'); + $this->assertEquals('field_media_test_1', $field_storage->getName(), 'Incorrect field name is used.'); + $this->assertEquals('media', $field_storage->getTargetEntityTypeId(), 'Field is not targeting media entities.'); // Test field. - $this->assertTrue($field->isNew(), 'Field is not saved automatically.'); - $this->assertEquals('field_media_test_1', $field->getName(), 'Correct field name is used.'); - $this->assertEquals('string', $field->getType(), 'Field is of correct type.'); - $this->assertTrue($field->isRequired(), 'Field is required.'); - $this->assertEquals('Test source', $field->label(), 'Correct label is used.'); - $this->assertEquals('test_type', $field->getTargetBundle(), 'Field is targeting correct bundle.'); + $this->assertTrue($field->isNew(), 'Field is saved automatically.'); + $this->assertEquals('field_media_test_1', $field->getName(), 'Incorrect field name is used.'); + $this->assertEquals('string', $field->getType(), 'Field is of inccorrect type.'); + $this->assertTrue($field->isRequired(), 'Field is not required.'); + $this->assertEquals('Test source', $field->label(), 'Incorrect label is used.'); + $this->assertEquals('test_type', $field->getTargetBundle(), 'Field is not targeting correct bundle.'); // Fields should be automatically saved only when creating the media type // using the media type creation form. Make sure that they are not saved @@ -393,19 +402,19 @@ $field_storage = $field->getFieldStorageDefinition(); // Test field storage. - $this->assertTrue($field_storage->isNew(), 'Field storage is not saved automatically.'); - $this->assertTrue($field_storage->isLocked(), 'Field storage is locked.'); - $this->assertEquals('string_long', $field_storage->getType(), 'Field is of correct type.'); - $this->assertEquals('field_media_test_constraints_1', $field_storage->getName(), 'Correct field name is used.'); - $this->assertEquals('media', $field_storage->getTargetEntityTypeId(), 'Field is targeting media entities.'); + $this->assertTrue($field_storage->isNew(), 'Field storage is saved automatically.'); + $this->assertTrue($field_storage->isLocked(), 'Field storage is not locked.'); + $this->assertEquals('string_long', $field_storage->getType(), 'Field is of incorrect type.'); + $this->assertEquals('field_media_test_constraints_1', $field_storage->getName(), 'Incorrect field name is used.'); + $this->assertEquals('media', $field_storage->getTargetEntityTypeId(), 'Field is not targeting media entities.'); // Test field. - $this->assertTrue($field->isNew(), 'Field is not saved automatically.'); - $this->assertEquals('field_media_test_constraints_1', $field->getName(), 'Correct field name is used.'); - $this->assertEquals('string_long', $field->getType(), 'Field is of correct type.'); - $this->assertTrue($field->isRequired(), 'Field is required.'); - $this->assertEquals('Test source with constraints', $field->label(), 'Correct label is used.'); - $this->assertEquals('test_constraints_type', $field->getTargetBundle(), 'Field is targeting correct bundle.'); + $this->assertTrue($field->isNew(), 'Field is saved automatically.'); + $this->assertEquals('field_media_test_constraints_1', $field->getName(), 'Incorrect field name is used.'); + $this->assertEquals('string_long', $field->getType(), 'Field is of incorrect type.'); + $this->assertTrue($field->isRequired(), 'Field is not required.'); + $this->assertEquals('Test source with constraints', $field->label(), 'Incorrect label is used.'); + $this->assertEquals('test_constraints_type', $field->getTargetBundle(), 'Field is not targeting correct bundle.'); } } diff -u b/core/themes/classy/templates/content/media.html.twig b/core/themes/classy/templates/content/media.html.twig --- b/core/themes/classy/templates/content/media.html.twig +++ b/core/themes/classy/templates/content/media.html.twig @@ -1,7 +1,7 @@ {# /** * @file - * Theme override to display a media. + * Theme override to display a media item. * * Available variables: * - name: Name of the media. diff -u b/core/themes/stable/templates/content/media.html.twig b/core/themes/stable/templates/content/media.html.twig --- b/core/themes/stable/templates/content/media.html.twig +++ b/core/themes/stable/templates/content/media.html.twig @@ -1,7 +1,7 @@ {# /** * @file - * Theme override to display a media. + * Theme override to display a media item. * * Available variables: * - name: Name of the media. only in patch2: unchanged: --- /dev/null +++ b/core/modules/media/tests/src/Functional/MediaFunctionalTestCreateMediaTypeTrait.php @@ -0,0 +1,67 @@ +randomMachineName()); + } + else { + $id = $values['bundle']; + } + $values += [ + 'id' => $id, + 'label' => $id, + 'source' => $source, + 'source_configuration' => [], + 'field_map' => [], + 'new_revision' => FALSE, + ]; + + $media_type = MediaType::create($values); + $status = $media_type->save(); + + // @todo Rename to assertSame() when #1945040 is done. + // @see https://www.drupal.org/node/1945040 + $this->assertIdentical(SAVED_NEW, $status, 'Media type was created successfully.'); + + // Ensure that the source field exists. + $source = $media_type->getSource(); + $source_field = $source->getSourceFieldDefinition($media_type); + if (!$source_field) { + $source_field = $source->createSourceField($media_type); + /** @var \Drupal\field\FieldStorageConfigInterface $storage */ + $storage = $source_field->getFieldStorageDefinition(); + $storage->setLocked(TRUE)->save(); + $source_field->save(); + + $media_type + ->set('source_configuration', [ + 'source_field' => $source_field->getName(), + ]) + ->save(); + } + + return $media_type; + } + +}