diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php index 905cdb4f1bb1281065a66343d55d187fd5960878..565fa4e6f74963ba98a7859025d02969e1f01f9b 100644 --- a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php +++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php @@ -135,7 +135,7 @@ public function getUiDefinitions() { // Add preconfigured definitions. foreach ($definitions as $id => $definition) { if (is_subclass_of($definition['class'], '\Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface')) { - foreach ($definition['class']::getPreconfiguredOptions() as $key => $option) { + foreach ($this->getPreconfiguredOptions($definition['id']) as $key => $option) { $definitions['field_ui:' . $id . ':' . $key] = [ 'label' => $option['label'], ] + $definition; @@ -150,6 +150,19 @@ public function getUiDefinitions() { return $definitions; } + /** + * {@inheritdoc} + */ + public function getPreconfiguredOptions($field_type) { + $options = []; + $class = $this->getPluginClass($field_type); + if (is_subclass_of($class, '\Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface')) { + $options = $class::getPreconfiguredOptions(); + $this->moduleHandler->alter('field_ui_preconfigured_options', $options, $field_type); + } + return $options; + } + /** * {@inheritdoc} */ diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php b/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php index 3a5c7b546cdb65335bab13472153b9b05eeee3ca..d937aabd446d507acd09d1f9526d17c0b4723dd7 100644 --- a/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php +++ b/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php @@ -84,6 +84,26 @@ public function getDefaultStorageSettings($type); */ public function getUiDefinitions(); + /** + * Returns preconfigured field options for a field type. + * + * This is a wrapper around + * \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions() + * allowing modules to alter the result of this method by implementing + * hook_field_ui_preconfigured_options_alter(). + * + * @param string $field_type + * The field type plugin ID. + * + * @return array + * A multi-dimensional array as returned from + * \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions(). + * + * @see \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions() + * @see hook_field_ui_preconfigured_options_alter() + */ + public function getPreconfiguredOptions($field_type); + /** * Returns the PHP class that implements the field type plugin. * diff --git a/core/lib/Drupal/Core/Field/PreconfiguredFieldUiOptionsInterface.php b/core/lib/Drupal/Core/Field/PreconfiguredFieldUiOptionsInterface.php index 9130e8c017cce86dd39faed7f8a1baf25a2c3f6d..684168aacb8aa64e087fc69268ea4372c5429719 100644 --- a/core/lib/Drupal/Core/Field/PreconfiguredFieldUiOptionsInterface.php +++ b/core/lib/Drupal/Core/Field/PreconfiguredFieldUiOptionsInterface.php @@ -16,6 +16,11 @@ interface PreconfiguredFieldUiOptionsInterface { /** * Returns preconfigured field options for a field type. * + * Note that if you want to give modules an opportunity to alter the result + * of this method, you should call + * \Drupal\Core\Field\FieldTypePluginManagerInterface::getPreconfiguredOptions() + * instead. + * * @return mixed[][] * A multi-dimensional array with string keys and the following structure: * - label: The label to show in the field type selection list. @@ -35,6 +40,7 @@ interface PreconfiguredFieldUiOptionsInterface { * @see \Drupal\field\Entity\FieldStorageConfig * @see \Drupal\field\Entity\FieldConfig * @see \Drupal\Core\Entity\Display\EntityDisplayInterface::setComponent() + * @see \Drupal\Core\Field\FieldTypePluginManagerInterface::getPreconfiguredOptions() */ public static function getPreconfiguredOptions(); diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php index 42bdd1e7125b46875b1a0ef3872aafb4c1817488..130f923180368d071fec92e171b7a23149914c0e 100644 --- a/core/modules/field/field.api.php +++ b/core/modules/field/field.api.php @@ -58,6 +58,33 @@ function hook_field_info_alter(&$info) { } } +/** + * Perform alterations on preconfigured field options. + * + * @param array $options + * Array of options as returned from + * \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions(). + * @param string $field_type + * The field type plugin ID. + * + * @see \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions() + */ +function hook_field_ui_preconfigured_options_alter(array &$options, $field_type) { + // If the field is not an "entity_reference"-based field, bail out. + /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */ + $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + $class = $field_type_manager->getPluginClass($field_type); + if (!is_a($class, 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem', TRUE)) { + return; + } + + // Set the default formatter for media in entity reference fields to be the + // "Rendered entity" formatter. + if (!empty($options['media'])) { + $options['media']['entity_view_display']['type'] = 'entity_reference_entity_view'; + } +} + /** * Forbid a field storage update from occurring. * diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module index cc1f9fa9054a31a79ec2e73e7fc8c0e3ddf25ebd..9121e942eae631d6d811e7e22c053705c8b0512e 100644 --- a/core/modules/field/tests/modules/field_test/field_test.module +++ b/core/modules/field/tests/modules/field_test/field_test.module @@ -171,3 +171,14 @@ function field_test_entity_bundle_field_info_alter(&$fields, EntityTypeInterface ]); } } + +/** + * Implements hook_field_ui_preconfigured_options_alter(). + */ +function field_test_field_ui_preconfigured_options_alter(array &$options, $field_type) { + if ($field_type === 'test_field_with_preconfigured_options') { + $options['custom_options']['entity_view_display']['settings'] = [ + 'test_formatter_setting_multiple' => 'altered dummy test string', + ]; + } +} diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php index 97e3ce7d102ee8924694b9c8f3cc92e3fb7c74c3..584cc96846746129429b01e25d95ab675b7b81e3 100644 --- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php @@ -312,14 +312,16 @@ public function submitForm(array &$form, FormStateInterface $form_state) { 'translatable' => FALSE, ]; $widget_id = $formatter_id = NULL; + $widget_settings = $formatter_settings = []; // Check if we're dealing with a preconfigured field. if (strpos($field_storage_values['type'], 'field_ui:') !== FALSE) { list(, $field_type, $option_key) = explode(':', $field_storage_values['type'], 3); $field_storage_values['type'] = $field_type; - $field_type_class = $this->fieldTypePluginManager->getDefinition($field_type)['class']; - $field_options = $field_type_class::getPreconfiguredOptions()[$option_key]; + $field_definition = $this->fieldTypePluginManager->getDefinition($field_type); + $options = $this->fieldTypePluginManager->getPreconfiguredOptions($field_definition['id']); + $field_options = $options[$option_key]; // Merge in preconfigured field storage options. if (isset($field_options['field_storage_config'])) { @@ -340,7 +342,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } $widget_id = isset($field_options['entity_form_display']['type']) ? $field_options['entity_form_display']['type'] : NULL; + $widget_settings = isset($field_options['entity_form_display']['settings']) ? $field_options['entity_form_display']['settings'] : []; $formatter_id = isset($field_options['entity_view_display']['type']) ? $field_options['entity_view_display']['type'] : NULL; + $formatter_settings = isset($field_options['entity_view_display']['settings']) ? $field_options['entity_view_display']['settings'] : []; } // Create the field storage and field. @@ -349,8 +353,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $field = $this->entityManager->getStorage('field_config')->create($field_values); $field->save(); - $this->configureEntityFormDisplay($values['field_name'], $widget_id); - $this->configureEntityViewDisplay($values['field_name'], $formatter_id); + $this->configureEntityFormDisplay($values['field_name'], $widget_id, $widget_settings); + $this->configureEntityViewDisplay($values['field_name'], $formatter_id, $formatter_settings); // Always show the field settings step, as the cardinality needs to be // configured for new fields. @@ -418,12 +422,20 @@ public function submitForm(array &$form, FormStateInterface $form_state) { * The field name. * @param string|null $widget_id * (optional) The plugin ID of the widget. Defaults to NULL. + * @param array $widget_settings + * (optional) An array of widget settings. Defaults to an empty array. */ - protected function configureEntityFormDisplay($field_name, $widget_id = NULL) { + protected function configureEntityFormDisplay($field_name, $widget_id = NULL, array $widget_settings = []) { + $options = []; + if ($widget_id) { + $options['type'] = $widget_id; + if (!empty($widget_settings)) { + $options['settings'] = $widget_settings; + } + } // Make sure the field is displayed in the 'default' form mode (using // default widget and settings). It stays hidden for other form modes // until it is explicitly configured. - $options = $widget_id ? ['type' => $widget_id] : []; entity_get_form_display($this->entityTypeId, $this->bundle, 'default') ->setComponent($field_name, $options) ->save(); @@ -436,12 +448,20 @@ protected function configureEntityFormDisplay($field_name, $widget_id = NULL) { * The field name. * @param string|null $formatter_id * (optional) The plugin ID of the formatter. Defaults to NULL. + * @param array $formatter_settings + * (optional) An array of formatter settings. Defaults to an empty array. */ - protected function configureEntityViewDisplay($field_name, $formatter_id = NULL) { + protected function configureEntityViewDisplay($field_name, $formatter_id = NULL, array $formatter_settings = []) { + $options = []; + if ($formatter_id) { + $options['type'] = $formatter_id; + if (!empty($formatter_settings)) { + $options['settings'] = $formatter_settings; + } + } // Make sure the field is displayed in the 'default' view mode (using // default formatter and settings). It stays hidden for other view // modes until it is explicitly configured. - $options = $formatter_id ? ['type' => $formatter_id] : []; entity_get_display($this->entityTypeId, $this->bundle, 'default') ->setComponent($field_name, $options) ->save(); diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php index d08ab03ba4cde7d175c79da5e7942c221a962d55..112e3923c497fe1399201f5eeedc8705c26c9ee5 100644 --- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php @@ -750,6 +750,7 @@ public function testPreconfiguredFields() { $this->assertEqual($form_display->getComponent('field_test_custom_options')['type'], 'test_field_widget_multiple'); $view_display = entity_get_display('node', 'article', 'default'); $this->assertEqual($view_display->getComponent('field_test_custom_options')['type'], 'field_test_multiple'); + $this->assertEqual($view_display->getComponent('field_test_custom_options')['settings']['test_formatter_setting_multiple'], 'altered dummy test string'); } /** diff --git a/core/modules/media/media.module b/core/modules/media/media.module index dc2d898e3c8eff530415fb0a1d7063978dd27d1a..5df059c284b89cd65cd88d4aad43c6b02178b08d 100644 --- a/core/modules/media/media.module +++ b/core/modules/media/media.module @@ -96,3 +96,22 @@ function template_preprocess_media(array &$variables) { $variables['content'][$key] = $variables['elements'][$key]; } } + +/** + * Implements hook_field_ui_preconfigured_options_alter(). + */ +function media_field_ui_preconfigured_options_alter(array &$options, $field_type) { + // If the field is not an "entity_reference"-based field, bail out. + /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */ + $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + $class = $field_type_manager->getPluginClass($field_type); + if (!is_a($class, 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem', TRUE)) { + return; + } + + // Set the default formatter for media in entity reference fields to be the + // "Rendered entity" formatter. + if (!empty($options['media'])) { + $options['media']['entity_view_display']['type'] = 'entity_reference_entity_view'; + } +} diff --git a/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php index d56e1565f7589fca30a7b5da8538a611b6f6975c..4fa7b54280f795bc35c91f3476ab19c0d7715ae7 100644 --- a/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php +++ b/core/modules/media/tests/src/Functional/MediaFunctionalTestTrait.php @@ -32,6 +32,7 @@ trait MediaFunctionalTestTrait { 'administer content types', 'administer node fields', 'administer node form display', + 'administer node display', 'bypass node access', ]; diff --git a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php index 4aa3f001f6d442e842b467b08a2a05afce6d9e6d..8a0a82fffb0f0ad14dab010b04c5a019a4686091 100644 --- a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php +++ b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php @@ -175,4 +175,21 @@ public function testMediaWithMultipleMediaTypes() { $assert_session->pageTextContains($second_media_item->getName()); } + /** + * Test that media in ER fields use the Rendered Entity formatter by default. + */ + public function testRenderedEntityReferencedMedia() { + $page = $this->getSession()->getPage(); + $assert_session = $this->assertSession(); + + $this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']); + $this->drupalGet('/admin/structure/types/manage/page/fields/add-field'); + $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference:media'); + $page->fillField('label', 'Foo field'); + $page->fillField('field_name', 'foo_field'); + $page->pressButton('Save and continue'); + $this->drupalGet('/admin/structure/types/manage/page/display'); + $assert_session->fieldValueEquals('fields[field_foo_field][type]', 'entity_reference_entity_view'); + } + }