diff --git a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldFormatterSettingsTest.php b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldFormatterSettingsTest.php index aa47c90f0b554f67f0f342ff974e33e6fe177919..7bf3ad541830caae7b1ed865126e7828dc928fec 100644 --- a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldFormatterSettingsTest.php +++ b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldFormatterSettingsTest.php @@ -129,11 +129,14 @@ public function testEntityDisplaySettings() { // Test the file field formatter settings. $expected['weight'] = 8; $expected['type'] = 'file_default'; - $expected['settings'] = []; + $expected['settings'] = [ + 'use_description_as_link_text' => TRUE + ]; $component = $display->getComponent('field_test_filefield'); $this->assertIdentical($expected, $component); $display = EntityViewDisplay::load('node.story.default'); $expected['type'] = 'file_url_plain'; + $expected['settings'] = []; $component = $display->getComponent('field_test_filefield'); $this->assertIdentical($expected, $component); diff --git a/core/modules/file/config/schema/file.schema.yml b/core/modules/file/config/schema/file.schema.yml index 336550904b913ee4d327ce6dcaedf6f7847f18dc..5797ececddea618998ba80f208bce41ac293eab7 100644 --- a/core/modules/file/config/schema/file.schema.yml +++ b/core/modules/file/config/schema/file.schema.yml @@ -73,13 +73,17 @@ field.field_settings.file: field.formatter.settings.file_default: type: mapping label: 'Generic file format settings' + mapping: + use_description_as_link_text: + type: boolean + label: 'Replace the file name by its description when available' field.formatter.settings.file_rss_enclosure: type: mapping label: 'RSS enclosure format settings' field.formatter.settings.file_table: - type: mapping + type: field.formatter.settings.file_default label: 'Table of files format settings' field.formatter.settings.file_url_plain: diff --git a/core/modules/file/file.install b/core/modules/file/file.install index 48d2bb2d81fb649992abe8faa5cf190e2639384e..6274efc7c912f52ffe9697085ce4b45e3a8dc8f9 100644 --- a/core/modules/file/file.install +++ b/core/modules/file/file.install @@ -5,6 +5,8 @@ * Install, update and uninstall functions for File module. */ +use Drupal\Core\Entity\Entity\EntityViewDisplay; + /** * Implements hook_schema(). */ @@ -128,3 +130,37 @@ function file_update_8300() { return t('Files that have no remaining usages are no longer deleted by default.'); } + +/** + * Add 'use_description_as_link_text' setting to file field formatters. + */ +function file_update_8001() { + $displays = EntityViewDisplay::loadMultiple(); + foreach ($displays as $display) { + /** @var \Drupal\Core\Entity\Entity\EntityViewDisplay $display */ + $fields_settings = $display->get('content'); + $changed = FALSE; + foreach ($fields_settings as $field_name => $settings) { + if (!empty($settings['type'])) { + switch ($settings['type']) { + // The file_table formatter never displayed available descriptions + // before, so we disable this option to ensure backward compatibility. + case 'file_table': + $fields_settings[$field_name]['settings']['use_description_as_link_text'] = FALSE; + $changed = TRUE; + break; + + // The file_default formatter always displayed available descriptions + // before, so we enable this option to ensure backward compatibility. + case 'file_default': + $fields_settings[$field_name]['settings']['use_description_as_link_text'] = TRUE; + $changed = TRUE; + break; + } + } + } + if ($changed === TRUE) { + $display->set('content', $fields_settings)->save(); + } + } +} diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/DescriptionAwareFileFormatterBase.php b/core/modules/file/src/Plugin/Field/FieldFormatter/DescriptionAwareFileFormatterBase.php new file mode 100644 index 0000000000000000000000000000000000000000..a6a80c92919ef833601408a9bd6a50a7d101b2fe --- /dev/null +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/DescriptionAwareFileFormatterBase.php @@ -0,0 +1,52 @@ + $this->t('Use description as link text'), + '#description' => $this->t('Replace the file name by its description when available'), + '#type' => 'checkbox', + '#default_value' => $this->getSetting('use_description_as_link_text'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + $summary = parent::settingsSummary(); + + if ($this->getSetting('use_description_as_link_text')) { + $summary[] = $this->t('Use description as link text'); + } + + return $summary; + } + +} diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php index daeb9f42c22a1de1a2f07e12fa5ba174dcc36133..7f35f3bee541556f6243d8c3fae2237edf3b598e 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php @@ -15,7 +15,7 @@ * } * ) */ -class GenericFileFormatter extends FileFormatterBase { +class GenericFileFormatter extends DescriptionAwareFileFormatterBase { /** * {@inheritdoc} @@ -28,7 +28,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $elements[$delta] = [ '#theme' => 'file_link', '#file' => $file, - '#description' => $item->description, + '#description' => $this->getSetting('use_description_as_link_text') ? $item->description : NULL, '#cache' => [ 'tags' => $file->getCacheTags(), ], diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php index 4da9e84366f44cc44f31d1696478ebf0947ed1a2..5bb3d94883972a9e608d933a5fa4626fda25f46f 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php @@ -15,7 +15,7 @@ * } * ) */ -class TableFormatter extends FileFormatterBase { +class TableFormatter extends DescriptionAwareFileFormatterBase { /** * {@inheritdoc} @@ -27,11 +27,13 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $header = [t('Attachment'), t('Size')]; $rows = []; foreach ($files as $delta => $file) { + $item = $file->_referringItem; $rows[] = [ [ 'data' => [ '#theme' => 'file_link', '#file' => $file, + '#description' => $this->getSetting('use_description_as_link_text') ? $item->description : NULL, '#cache' => [ 'tags' => $file->getCacheTags(), ], diff --git a/core/modules/file/src/Tests/FileFieldDisplayTest.php b/core/modules/file/src/Tests/FileFieldDisplayTest.php index db9b7dc91ba561d5c1f1c140cd68b93cc1fb065b..9589db17856f2ebe916f23c955867cb04829c0ab 100644 --- a/core/modules/file/src/Tests/FileFieldDisplayTest.php +++ b/core/modules/file/src/Tests/FileFieldDisplayTest.php @@ -4,6 +4,7 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\file\Entity\File; +use Drupal\node\Entity\Node; /** * Tests the display of file fields in node and views. @@ -173,4 +174,49 @@ public function testDescToggle() { $this->assertText(t('The description may be used as the label of the link to the file.')); } + /** + * Tests description display of File Field. + */ + public function testDescriptionDefaultFileFieldDisplay() { + $field_name = strtolower($this->randomMachineName()); + $type_name = 'article'; + $field_storage_settings = [ + 'display_field' => '1', + 'display_default' => '1', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + ]; + $field_settings = [ + 'description_field' => '1', + ]; + $widget_settings = []; + $this->createFileField($field_name, 'node', $type_name, $field_storage_settings, $field_settings, $widget_settings); + + $test_file = $this->getTestFile('text'); + + // Create a new node with the uploaded file. + $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); + + // Add file description. + $description = 'This is the test file description'; + $this->drupalPostForm("node/$nid/edit", [$field_name . '[0][description]' => $description], t('Save')); + + // Load uncached node. + \Drupal::entityTypeManager()->getStorage('node')->resetCache([$nid]); + $node = Node::load($nid); + + // Test default formatter. + $this->drupalGet('node/' . $nid); + $this->assertFieldByXPath('//a[@href="' . $node->{$field_name}->entity->url() . '"]', $description); + + // Change formatter to "Table of files". + $display = \Drupal::entityTypeManager()->getStorage('entity_view_display')->load('node.' . $type_name . '.default'); + $display->setComponent($field_name, [ + 'label' => 'hidden', + 'type' => 'file_table', + ])->save(); + + $this->drupalGet('node/' . $nid); + $this->assertFieldByXPath('//a[@href="' . $node->{$field_name}->entity->url() . '"]', $description); + } + } diff --git a/core/modules/file/src/Tests/Update/FileUpdateTest.php b/core/modules/file/src/Tests/Update/FileUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bd724f41b02436660ddca917d7734d9f4557f49c --- /dev/null +++ b/core/modules/file/src/Tests/Update/FileUpdateTest.php @@ -0,0 +1,59 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz', + __DIR__ . '/../../../tests/fixtures/update/drupal-8.file_formatters_update_2677990.php', + ]; + } + + /** + * Tests file_update_8001(). + */ + public function testPostUpdate8001() { + $view = 'core.entity_view_display.node.article.default'; + + // Check that field_file_generic formatter has no + // use_description_as_link_text setting. + $formatter_settings = $this->config($view)->get('content.field_file_generic_2677990.settings'); + $this->assertTrue(!isset($formatter_settings['use_description_as_link_text'])); + + // Check that field_file_table formatter has no use_description_as_link_text + // setting. + $formatter_settings = $this->config($view)->get('content.field_file_table_2677990.settings'); + $this->assertTrue(!isset($formatter_settings['use_description_as_link_text'])); + + // Run updates. + $this->runUpdates(); + + // Check that field_file_generic formatter has a + // use_description_as_link_text setting which value is TRUE. + $formatter_settings = $this->config($view)->get('content.field_file_generic_2677990.settings'); + $this->assertEqual($formatter_settings, ['use_description_as_link_text' => TRUE]); + + // Check that field_file_table formatter has a use_description_as_link_text + // setting which value is FALSE. + $formatter_settings = $this->config($view)->get('content.field_file_table_2677990.settings'); + $this->assertEqual($formatter_settings, ['use_description_as_link_text' => FALSE]); + } + +} diff --git a/core/modules/file/tests/fixtures/update/core.entity_view_display.node.article.default_2677990.yml b/core/modules/file/tests/fixtures/update/core.entity_view_display.node.article.default_2677990.yml new file mode 100644 index 0000000000000000000000000000000000000000..fae6adecb6a7f608641de06c5a46ba49e1e2551c --- /dev/null +++ b/core/modules/file/tests/fixtures/update/core.entity_view_display.node.article.default_2677990.yml @@ -0,0 +1,71 @@ +uuid: 9ca49b35-b49d-4014-9337-965cdf15b61e +langcode: en +status: true +dependencies: + config: + - field.field.node.article.body + - field.field.node.article.comment + - field.field.node.article.field_file_generic_2677990 + - field.field.node.article.field_file_table_2677990 + - field.field.node.article.field_image + - field.field.node.article.field_tags + - image.style.large + - node.type.article + module: + - comment + - file + - image + - text + - user +_core: + default_config_hash: JtAg_-waIt1quMtdDtHIaXJMxvTuSmxW7bWyO6Zd68E +id: node.article.default +targetEntityType: node +bundle: article +mode: default +content: + body: + type: text_default + weight: 0 + settings: { } + third_party_settings: { } + label: hidden + comment: + label: above + type: comment_default + weight: 20 + settings: + pager_id: 0 + third_party_settings: { } + field_file_generic_2677990: + weight: 101 + label: above + settings: { } + third_party_settings: { } + type: file_default + field_file_table_2677990: + weight: 102 + label: above + settings: { } + third_party_settings: { } + type: file_table + field_image: + type: image + weight: -1 + settings: + image_style: large + image_link: '' + third_party_settings: { } + label: hidden + field_tags: + type: entity_reference_label + weight: 10 + label: above + settings: + link: true + third_party_settings: { } + links: + weight: 100 + settings: { } + third_party_settings: { } +hidden: { } diff --git a/core/modules/file/tests/fixtures/update/drupal-8.file_formatters_update_2677990.php b/core/modules/file/tests/fixtures/update/drupal-8.file_formatters_update_2677990.php new file mode 100644 index 0000000000000000000000000000000000000000..642314287741cac1fb38c65bca9d6408e0c1eeb5 --- /dev/null +++ b/core/modules/file/tests/fixtures/update/drupal-8.file_formatters_update_2677990.php @@ -0,0 +1,88 @@ +insert('config') + ->fields([ + 'collection', + 'name', + 'data', + ]) + ->values([ + 'collection' => '', + 'name' => 'field.storage.' . $field_file_generic_2677990['id'], + 'data' => serialize($field_file_generic_2677990), + ]) + ->values([ + 'collection' => '', + 'name' => 'field.storage.' . $field_file_table_2677990['id'], + 'data' => serialize($field_file_table_2677990), + ]) + ->execute(); +// We need to Update the registry of "last installed" field definitions. +$installed = $connection->select('key_value') + ->fields('key_value', ['value']) + ->condition('collection', 'entity.definitions.installed') + ->condition('name', 'node.field_storage_definitions') + ->execute() + ->fetchField(); +$installed = unserialize($installed); +$installed['field_file_generic_2677990'] = new FieldStorageConfig($field_file_generic_2677990); +$installed['field_file_table_2677990'] = new FieldStorageConfig($field_file_table_2677990); +$connection->update('key_value') + ->condition('collection', 'entity.definitions.installed') + ->condition('name', 'node.field_storage_definitions') + ->fields([ + 'value' => serialize($installed) + ]) + ->execute(); + +// Configuration for a file field storage for generic display. +$field_file_generic_2677990 = Yaml::decode(file_get_contents(__DIR__ . '/field.field.node.article.field_file_generic_2677990.yml')); + +// Configuration for a file field storage for table display. +$field_file_table_2677990 = Yaml::decode(file_get_contents(__DIR__ . '/field.field.node.article.field_file_table_2677990.yml')); + +$connection->insert('config') + ->fields([ + 'collection', + 'name', + 'data', + ]) + ->values([ + 'collection' => '', + 'name' => 'field.field.' . $field_file_generic_2677990['id'], + 'data' => serialize($field_file_generic_2677990), + ]) + ->values([ + 'collection' => '', + 'name' => 'field.field.' . $field_file_table_2677990['id'], + 'data' => serialize($field_file_table_2677990), + ]) + ->execute(); + +// Configuration of the view mode to set the proper formatters. +$view_mode_2677990 = Yaml::decode(file_get_contents(__DIR__ . '/core.entity_view_display.node.article.default_2677990.yml')); + +$connection->update('config') + ->fields([ + 'data' => serialize($view_mode_2677990), + ]) + ->condition('name', 'core.entity_view_display.' . $view_mode_2677990['id']) + ->execute(); diff --git a/core/modules/file/tests/fixtures/update/field.field.node.article.field_file_generic_2677990.yml b/core/modules/file/tests/fixtures/update/field.field.node.article.field_file_generic_2677990.yml new file mode 100644 index 0000000000000000000000000000000000000000..140a9f355c32b346b2a2899e01d9a9213333e9be --- /dev/null +++ b/core/modules/file/tests/fixtures/update/field.field.node.article.field_file_generic_2677990.yml @@ -0,0 +1,27 @@ +uuid: d352a831-c267-4ecc-9b4e-7ae1896b2241 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_file_generic_2677990 + - node.type.article + module: + - file +id: node.article.field_file_generic_2677990 +field_name: field_file_generic_2677990 +entity_type: node +bundle: article +label: 'File generic' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + file_directory: '[date:custom:Y]-[date:custom:m]' + file_extensions: txt + max_filesize: '' + description_field: true + handler: 'default:file' + handler_settings: { } +field_type: file diff --git a/core/modules/file/tests/fixtures/update/field.field.node.article.field_file_table_2677990.yml b/core/modules/file/tests/fixtures/update/field.field.node.article.field_file_table_2677990.yml new file mode 100644 index 0000000000000000000000000000000000000000..ba40a9fb5d31694370efa332d303d0c64811e24c --- /dev/null +++ b/core/modules/file/tests/fixtures/update/field.field.node.article.field_file_table_2677990.yml @@ -0,0 +1,27 @@ +uuid: 44c7a590-ffcc-4534-b01c-b17b8d57ed48 +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_file_table_2677990 + - node.type.article + module: + - file +id: node.article.field_file_table_2677990 +field_name: field_file_table_2677990 +entity_type: node +bundle: article +label: 'File table' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + file_directory: '[date:custom:Y]-[date:custom:m]' + file_extensions: txt + max_filesize: '' + description_field: true + handler: 'default:file' + handler_settings: { } +field_type: file diff --git a/core/modules/file/tests/fixtures/update/field.storage.node.field_file_generic_2677990.yml b/core/modules/file/tests/fixtures/update/field.storage.node.field_file_generic_2677990.yml new file mode 100644 index 0000000000000000000000000000000000000000..2c4a297dc05f6fd9c2a3b0c4e39cceac77ca1fee --- /dev/null +++ b/core/modules/file/tests/fixtures/update/field.storage.node.field_file_generic_2677990.yml @@ -0,0 +1,23 @@ +uuid: a7eb470d-e538-4221-a8ac-57f989d92d8e +langcode: en +status: true +dependencies: + module: + - file + - node +id: node.field_file_generic_2677990 +field_name: field_file_generic_2677990 +entity_type: node +type: file +settings: + display_field: false + display_default: false + uri_scheme: public + target_type: file +module: file +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/core/modules/file/tests/fixtures/update/field.storage.node.field_file_table_2677990.yml b/core/modules/file/tests/fixtures/update/field.storage.node.field_file_table_2677990.yml new file mode 100644 index 0000000000000000000000000000000000000000..bf93af8c261a616b9d612a1250bde1a6b3dd250c --- /dev/null +++ b/core/modules/file/tests/fixtures/update/field.storage.node.field_file_table_2677990.yml @@ -0,0 +1,23 @@ +uuid: 43113a5e-3e07-4234-b045-4aa4cd217dca +langcode: en +status: true +dependencies: + module: + - file + - node +id: node.field_file_table_2677990 +field_name: field_file_table_2677990 +entity_type: node +type: file +settings: + display_field: false + display_default: false + uri_scheme: public + target_type: file +module: file +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false