diff --git a/core/modules/media/media.module b/core/modules/media/media.module index 420e81e4fd..d3575457cc 100644 --- a/core/modules/media/media.module +++ b/core/modules/media/media.module @@ -210,9 +210,21 @@ function media_preprocess_media_reference_help(&$variables) { // Use the user-defined label for the field to indicate that the form allows // reusing existing media. $variables['label'] = $element['#original_label']; + if (!empty($element[0]['target_id']['#selection_settings']['target_bundles'])) { - $variables['types'] = implode(", ", $element[0]['target_id']['#selection_settings']['target_bundles']); - $variables['media_add_page'] = Url::fromRoute('entity.media.add_page')->toString(); - $variables['media_list'] = Url::fromRoute('entity.media.collection')->toString(); + $create_access = FALSE; + $bundles = $element[0]['target_id']['#selection_settings']['target_bundles']; + $variables['types'] = implode(", ", $bundles); + foreach ($bundles as $bundle) { + if (\Drupal::entityTypeManager()->getAccessControlHandler('media')->createAccess($bundle, \Drupal::currentUser())) { + $create_access = TRUE; + } + } + if ($create_access === TRUE) { + $variables['media_add_page'] = Url::fromRoute('entity.media.add_page')->toString(); + } + if (\Drupal::currentUser()->hasPermission('access media overview')) { + $variables['media_list'] = Url::fromRoute('entity.media.collection')->toString(); + } } } diff --git a/core/modules/media/templates/media-reference-help.html.twig b/core/modules/media/templates/media-reference-help.html.twig index d99ca4032c..1b23f5f234 100644 --- a/core/modules/media/templates/media-reference-help.html.twig +++ b/core/modules/media/templates/media-reference-help.html.twig @@ -10,14 +10,17 @@ #}
{{ label }} -

+ + {% if media_add_page %} +

+ {% trans %} + Create new {{ label|placeholder }} + {% endtrans %} +

{% trans %} - Create new {{ label|placeholder }} + Create your media on the media add page (opens a new window), then add it by name to the field below. {% endtrans %} - - {% trans %} - Create your media on the media add page (opens a new window), then add it by name to the field below. - {% endtrans %} + {% endif %} {% if multiple %}
@@ -30,9 +33,16 @@ {% trans %} - Type part of the media name. See the media list (opens a new window) to help locate media. Allowed media types: {{ types|placeholder }} + Type part of the media name. + {% endtrans %} + {% if media_list %} + {% trans %} + See the media list (opens a new window) to help locate media. + {% endtrans %} + {% endif %} + {% trans %} + Allowed media types: {{ types|placeholder }} {% endtrans %} - {% if multiple %} {% if description.content %} {{ description.content }} diff --git a/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php index 224bb426e3..379ba74717 100644 --- a/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php +++ b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php @@ -14,6 +14,7 @@ */ protected static $adminUserPermissions = [ // Media module permissions. + 'access media overview', 'administer media', 'administer media fields', 'administer media form display', diff --git a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php index 8d876b7b0d..3497f41c73 100644 --- a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php +++ b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php @@ -3,6 +3,10 @@ namespace Drupal\Tests\media\Functional; use Drupal\media\Entity\Media; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Url; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; /** * Ensures that media UI works correctly. @@ -192,6 +196,184 @@ public function testRenderedEntityReferencedMedia() { $assert_session->fieldValueEquals('fields[field_foo_field][type]', 'entity_reference_entity_view'); } + public function providerTestMediaReferenceWidget() { + return [ + // Single-value fields with a single media type: + // - The user can create and list the media. + [1, [TRUE], TRUE], + + // - The user can list but not create the media. + [1, [FALSE], TRUE], + // - The user can create but not list the media. + [1, [TRUE], FALSE], + // - The user can neither create nor list the media. + [1, [FALSE], FALSE], + + // Single-value fields with two media types: + // - The user can create both types. + [1, [TRUE, TRUE], TRUE], + // - The user can create only one type. + [1, [TRUE, FALSE], TRUE], + // - The user cannot create either type. + [1, [FALSE, FALSE], TRUE], + + // Multiple-value field with a cardinality of 3, with media the user can + // create and list. + [3, [TRUE], TRUE], + + // Unlimited value field. + [FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, [TRUE], TRUE], + + ]; + } + + /** + * Test the default autocomplete widgets for media reference fields. + * + * @dataProvider providerTestMediaReferenceWidget + * + * @see media_field_widget_entity_reference_autocomplete_form_alter() + * @see media_field_widget_multiple_entity_reference_autocomplete_form_alter() + */ + public function testMediaReferenceWidget($cardinality, array $media_type_create_access, $list_access) { + $assert_session = $this->assertSession(); + + // Create a non-media entity reference and make sure our help text is not + // showing up. + $non_media_content_type = $this->createContentType(); + $non_media_storage = FieldStorageConfig::create([ + 'field_name' => 'field_not_a_media_field', + 'entity_type' => 'node', + 'type' => 'entity_reference', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + 'settings' => [ + 'target_type' => 'node', + ], + ]); + $non_media_storage->save(); + $non_media_field = FieldConfig::create([ + 'label' => 'No media here!', + 'field_storage' => $non_media_storage, + 'entity_type' => 'node', + 'bundle' => $non_media_content_type->id(), + 'settings' => [ + 'handler' => 'default', + 'handler_settings' => [ + 'target_bundles' => [ + $non_media_content_type->id() => $non_media_content_type->id(), + ], + ], + ], + ]); + $non_media_field->save(); + entity_get_form_display('node', $non_media_content_type->id(), 'default') + ->setComponent('field_not_a_media_field', [ + 'type' => 'entity_reference_autocomplete', + ]) + ->save(); + $this->drupalGet("/node/add/{$non_media_content_type->id()}"); + $assert_session->pageTextNotContains('Create your media on the media add page (opens a new window), then add it by name to the field below.'); + $assert_session->pageTextNotContains('Type part of the media name. See the media list (opens a new window) to help locate media.'); + + // Now create a separate content type with the media field. + $content_type = $this->createContentType(); + + // Create media types to use in the field. + $media_types = []; + $permissions = []; + $any_create_access = FALSE; + foreach ($media_type_create_access as $id => $access) { + if ($access) { + $any_create_access = TRUE; + $permissions[] = "create media_type_$id media"; + } + $media_type = $this->createMediaType(['bundle' => "media_type_$id"]); + $media_types["media_type_$id"] = "media_type_$id"; + } + $type_list = implode(", ", array_keys($media_types)); + + // Create a user that can create content of the type, with other + // permissions as given by the data provider. + $permissions[] = "create {$content_type->id()} content"; + if ($list_access) { + $permissions[] = "access media overview"; + } + $test_user = $this->drupalCreateUser($permissions); + + // Create the field. + $storage = FieldStorageConfig::create([ + 'field_name' => "field_media_reference", + 'entity_type' => 'node', + 'type' => 'entity_reference', + 'cardinality' => $cardinality, + 'settings' => [ + 'target_type' => 'media', + ], + ]); + $storage->save(); + $field = FieldConfig::create([ + 'label' => "Media (cardinality $cardinality)", + 'field_storage' => $storage, + 'entity_type' => 'node', + 'bundle' => $content_type->id(), + 'settings' => [ + 'handler' => 'default', + 'handler_settings' => [ + 'target_bundles' => $media_types, + ], + ], + ]); + $field->save(); + entity_get_form_display('node', $content_type->id(), 'default') + ->setComponent('field_media_reference', [ + 'type' => 'entity_reference_autocomplete', + ]) + ->save(); + + // Now, xheck that the widget displays the expected help text under the + // given conditions for the test user. + $this->drupalLogin($test_user); + $this->drupalGet("/node/add/{$content_type->id()}"); + $fieldset_selector = '#edit-field-media-reference-wrapper fieldset'; + $fieldset = $assert_session->elementExists('css', $fieldset_selector); + + $this->assertEquals($field->getLabel(), $fieldset->find('css', 'legend')->getText()); + + // Find all the links inside the fieldset. + $find_all_links = $fieldset->findAll('css', 'a'); + $links = []; + foreach ($find_all_links as $link) { + $links[$link->getText()] = $link; + } + + // Within the fieldset, only once for each. + if ($any_create_access) { + $assert_session->elementsCount('css', $fieldset_selector . ":contains('Create new {$field->getLabel()}')", 1); + $assert_session->elementsCount('css', $fieldset_selector . ":contains('Create your media on the media add page (opens a new window), then add it by name to the field below.')", 1); + $this->assertTrue(in_array('media add page', array_keys($links))); + $this->assertEquals(Url::fromRoute('entity.media.add_page')->toString(), $links['media add page']->getAttribute('href')); + $this->assertEquals('_blank', $links['media add page']->getAttribute('target')); + } + else { + $assert_session->pageTextNotContains("Create new {$field->getLabel()}"); + $assert_session->pageTextNotContains("Create your media on the media add page (opens a new window), then add it by name to the field below."); + $this->assertFalse(in_array('media add page', array_keys($links))); + } + $assert_session->elementTextContains('css', $fieldset_selector, "Use existing {$field->getLabel()}"); + $assert_session->elementTextContains('css', $fieldset_selector, "Type part of the media name."); + if ($list_access) { + $assert_session->elementTextContains('css', $fieldset_selector, "See the media list (opens a new window) to help locate media."); + $this->assertTrue(in_array('media list', array_keys($links))); + $this->assertEquals(Url::fromRoute('entity.media.collection')->toString(), $links['media list']->getAttribute('href')); + $this->assertEquals('_blank', $links['media list']->getAttribute('target')); + } + else { + $assert_session->pageTextNotContains("See the media list (opens a new window) to help locate media."); + $this->assertFalse(in_array('media list', array_keys($links))); + } + $assert_session->elementTextContains('css', $fieldset_selector, "Allowed media types: $type_list"); + } + /** * Test the media collection route. */ diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaReferenceFieldHelpTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaReferenceFieldHelpTest.php index 19013cb0b3..46f7858df6 100644 --- a/core/modules/media/tests/src/FunctionalJavascript/MediaReferenceFieldHelpTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaReferenceFieldHelpTest.php @@ -57,158 +57,4 @@ public function testFieldCreationHelpText() { } } - /** - * Test our custom help texts when creating a field. - * - * @see media_field_widget_entity_reference_autocomplete_form_alter() - * @see media_field_widget_multiple_entity_reference_autocomplete_form_alter() - */ - public function testMediaAutocompleteWidgetTest() { - $assert_session = $this->assertSession(); - - $media_type1 = $this->createMediaType(); - $media_type2 = $this->createMediaType(); - $content_type = $this->createContentType(); - // The first field will have cardinality 1. - $storage1 = FieldStorageConfig::create([ - 'field_name' => 'field_card_1', - 'entity_type' => 'node', - 'type' => 'entity_reference', - 'cardinality' => 1, - 'settings' => [ - 'target_type' => 'media', - ], - ]); - $storage1->save(); - $field1 = FieldConfig::create([ - 'label' => 'Media (card 1)', - 'field_storage' => $storage1, - 'entity_type' => 'node', - 'bundle' => $content_type->id(), - 'settings' => [ - 'handler' => 'default', - 'handler_settings' => [ - 'target_bundles' => [ - $media_type1->id() => $media_type1->id(), - $media_type2->id() => $media_type2->id(), - ], - ], - ], - ]); - $field1->save(); - entity_get_form_display('node', $content_type->id(), 'default') - ->setComponent('field_card_1', [ - 'type' => 'entity_reference_autocomplete', - ]) - ->save(); - - // Do the same with a field with unlimited cardinality. - $storage2 = FieldStorageConfig::create([ - 'field_name' => 'field_card_unlimited', - 'entity_type' => 'node', - 'type' => 'entity_reference', - 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, - 'settings' => [ - 'target_type' => 'media', - ], - ]); - $storage2->save(); - $field2 = FieldConfig::create([ - 'label' => 'Media (card unlimited)', - 'field_storage' => $storage2, - 'entity_type' => 'node', - 'bundle' => $content_type->id(), - 'settings' => [ - 'handler' => 'default', - 'handler_settings' => [ - 'target_bundles' => [ - $media_type1->id() => $media_type1->id(), - $media_type2->id() => $media_type2->id(), - ], - ], - ], - ]); - $field2->save(); - entity_get_form_display('node', $content_type->id(), 'default') - ->setComponent('field_card_unlimited', [ - 'type' => 'entity_reference_autocomplete', - ]) - ->save(); - - // Check that both widgets display the expected help text on the form. - $this->drupalGet("/node/add/{$content_type->id()}"); - // Chedk the wrapper fieldsets are present. - $fieldset1 = $assert_session->elementExists('css', '#edit-field-card-1-wrapper fieldset'); - $fieldset2 = $assert_session->elementExists('css', '#edit-field-card-unlimited-wrapper fieldset'); - // Check some help texts are the ones we expect. - $this->assertEquals($field1->getLabel(), $fieldset1->find('css', 'legend')->getText()); - $this->assertEquals($field2->getLabel(), $fieldset2->find('css', 'legend')->getText()); - $h4s = $fieldset1->findAll('css', 'h4'); - $this->assertEquals("Create new {$field1->getLabel()}", $h4s[0]->getText()); - $this->assertEquals("Use existing {$field1->getLabel()}", $h4s[1]->getText()); - $h4s = $fieldset2->findAll('css', 'h4'); - $this->assertEquals("Create new {$field2->getLabel()}", $h4s[0]->getText()); - // The multiple-widget has an empty h4 in our way, that's why we use the - // next one instead. - $this->assertEquals("Use existing {$field2->getLabel()}", $h4s[2]->getText()); - $span1 = $assert_session->elementExists('css', 'span.reuse-media-help', $fieldset1); - $this->assertEquals("Create your media on the media add page (opens a new window), then add it by name to the field below.", $span1->getText()); - $link1 = $assert_session->elementExists('css', 'a', $span1); - $this->assertEquals("media add page", $link1->getText()); - $this->assertEquals(Url::fromRoute('entity.media.add_page')->toString(), $link1->getAttribute('href')); - $span2 = $assert_session->elementExists('css', 'span.reuse-media-help', $fieldset2); - $this->assertEquals("Create your media on the media add page (opens a new window), then add it by name to the field below.", $span2->getText()); - $link2 = $assert_session->elementExists('css', 'a', $span2); - $this->assertEquals("media add page", $link2->getText()); - $this->assertEquals(Url::fromRoute('entity.media.add_page')->toString(), $link2->getAttribute('href')); - $description1 = $assert_session->elementExists('css', '#edit-field-card-1-0-target-id--description', $fieldset1); - $this->assertEquals("Type part of the media name. See the media list (opens a new window) to help locate media. Allowed media types: {$media_type1->id()}, {$media_type2->id()}.", $description1->getText()); - $link3 = $assert_session->elementExists('css', 'a', $description1); - $this->assertEquals("media list", $link3->getText()); - $this->assertEquals(Url::fromRoute('entity.media.collection')->toString(), $link3->getAttribute('href')); - $description2 = $assert_session->elementExists('css', '#edit-field-card-unlimited-0-target-id--description', $fieldset2); - $this->assertEquals("Type part of the media name. See the media list (opens a new window) to help locate media. Allowed media types: {$media_type1->id()}, {$media_type2->id()}.", $description2->getText()); - $link4 = $assert_session->elementExists('css', 'a', $description2); - $this->assertEquals("media list", $link4->getText()); - $this->assertEquals(Url::fromRoute('entity.media.collection')->toString(), $link4->getAttribute('href')); - - // Create a non-media entity reference and make sure our help text is not - // showing up. - $storage3 = FieldStorageConfig::create([ - 'field_name' => 'field_not_a_media_field', - 'entity_type' => 'node', - 'type' => 'entity_reference', - 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, - 'settings' => [ - 'target_type' => 'node', - ], - ]); - $storage3->save(); - $field3 = FieldConfig::create([ - 'label' => 'No media here!', - 'field_storage' => $storage3, - 'entity_type' => 'node', - 'bundle' => $content_type->id(), - 'settings' => [ - 'handler' => 'default', - 'handler_settings' => [ - 'target_bundles' => [ - $content_type->id() => $content_type->id(), - ], - ], - ], - ]); - $field3->save(); - entity_get_form_display('node', $content_type->id(), 'default') - ->removeComponent('field_card_1') - ->removeComponent('field_card_unlimited') - ->setComponent('field_not_a_media_field', [ - 'type' => 'entity_reference_autocomplete', - ]) - ->save(); - $this->drupalGet("/node/add/{$content_type->id()}"); - $assert_session->pageTextNotContains('Create your media on the media add page (opens a new window), then add it by name to the field below.'); - $assert_session->pageTextNotContains('Type part of the media name. See the media list (opens a new window) to help locate media.'); - } - }