From d2cdfb1940de2297b269a3aaee3a8bd5d7c11afd Mon Sep 17 00:00:00 2001 From: effulgentsia Date: Thu, 31 Aug 2023 14:52:48 -0700 Subject: [PATCH] Issue #3358049 by narendraR, lauriii, srishtiiee, Utkarsh_33, Wim Leers, tim.plunkett, tedbow, bnjmnm, smustgrave, Berdir, amateescu, larowlan: Save FieldStorageConfig at the same time as FieldConfig --- .../lib/Drupal/Core/Field/FieldConfigBase.php | 12 +- core/lib/Drupal/Core/Field/FieldItemList.php | 12 +- .../src/Functional/CommentFieldsTest.php | 12 +- .../field/src/Entity/FieldStorageConfig.php | 18 +- .../EntityReferenceAdminTest.php | 11 +- .../EntityReferenceAdminTest.php | 10 +- core/modules/field_ui/field_ui.module | 2 + .../Controller/FieldConfigAddController.php | 77 +++++++ .../Controller/FieldStorageAddController.php | 64 ++++++ .../field_ui/src/Form/FieldConfigEditForm.php | 68 +++++- .../field_ui/src/Form/FieldStorageAddForm.php | 64 +++--- .../src/Form/FieldStorageConfigEditForm.php | 65 +++++- .../field_ui/src/Routing/RouteSubscriber.php | 25 +++ .../Functional/ManageFieldsFunctionalTest.php | 46 +++-- .../tests/src/Functional/ManageFieldsTest.php | 195 +++++++++++++++++- .../FunctionalJavascript/ManageFieldsTest.php | 21 +- .../tests/src/Traits/FieldUiJSTestTrait.php | 10 +- .../tests/src/Traits/FieldUiTestTrait.php | 73 +++++-- .../src/Unit/FieldConfigEditFormTest.php | 6 +- .../src/Functional/FileFieldWidgetTest.php | 2 +- .../src/Functional/ImageFieldDisplayTest.php | 8 +- .../src/Functional/MediaUiFunctionalTest.php | 11 +- .../FieldUiIntegrationTest.php | 6 +- .../src/Functional/NodeTranslationUITest.php | 2 +- .../Functional/NodeTypeTranslationTest.php | 4 +- .../src/Functional/OptionsFieldUITest.php | 7 +- .../OptionsFloatFieldImportTest.php | 2 +- .../OptionsFieldUITest.php | 6 +- .../Functional/SearchPageCacheTagsTest.php | 2 +- 29 files changed, 698 insertions(+), 143 deletions(-) create mode 100644 core/modules/field_ui/src/Controller/FieldConfigAddController.php create mode 100644 core/modules/field_ui/src/Controller/FieldStorageAddController.php diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php index af50573a7dc..e9032e8cc9f 100644 --- a/core/lib/Drupal/Core/Field/FieldConfigBase.php +++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php @@ -6,6 +6,7 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\TypedData\FieldItemDataDefinition; +use Drupal\field\Entity\FieldStorageConfig; /** * Base class for configurable field definitions. @@ -468,10 +469,17 @@ abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigIn * @todo Investigate in https://www.drupal.org/node/1977206. */ public function __sleep() { + $properties = get_object_vars($this); + // Only serialize necessary properties, excluding those that can be // recalculated. - $properties = get_object_vars($this); - unset($properties['fieldStorage'], $properties['itemDefinition'], $properties['original']); + unset($properties['itemDefinition'], $properties['original']); + + // Field storage can be recalculated if it's not new. + if (array_key_exists('fieldStorage', $properties) && $properties['fieldStorage'] instanceof FieldStorageConfig && !$properties['fieldStorage']->isNew()) { + unset($properties['fieldStorage']); + } + return array_keys($properties); } diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php index 33b3a37ef02..c1d3b70edb9 100644 --- a/core/lib/Drupal/Core/Field/FieldItemList.php +++ b/core/lib/Drupal/Core/Field/FieldItemList.php @@ -370,7 +370,17 @@ class FieldItemList extends ItemList implements FieldItemListInterface { ]); } else { - $widget = $field_widget_plugin_manager->getInstance(['field_definition' => $definition]); + $options = [ + 'field_definition' => $this->getFieldDefinition(), + ]; + // If the field does not have a widget configured in the 'default' form + // mode, check if there are default entity form display options defined + // for the 'default' form mode in the form state. + // @see \Drupal\field_ui\Controller\FieldConfigAddController::fieldConfigAddConfigureForm + if (($default_options = $form_state->get('default_options')) && isset($default_options['entity_form_display']['default'])) { + $options['configuration'] = $default_options['entity_form_display']['default']; + } + $widget = $field_widget_plugin_manager->getInstance($options); } $form_state->set('default_value_widget', $widget); diff --git a/core/modules/comment/tests/src/Functional/CommentFieldsTest.php b/core/modules/comment/tests/src/Functional/CommentFieldsTest.php index 4d07112856a..f67ebea79c7 100644 --- a/core/modules/comment/tests/src/Functional/CommentFieldsTest.php +++ b/core/modules/comment/tests/src/Functional/CommentFieldsTest.php @@ -158,12 +158,12 @@ class CommentFieldsTest extends CommentTestBase { 'field_name' => 'user_comment', ]; $this->drupalGet('admin/config/people/accounts/fields/add-field'); - $this->submitForm($edit, 'Save and continue'); + $this->submitForm($edit, 'Continue'); // Try to save the comment field without selecting a comment type. $edit = []; - $this->drupalGet('admin/config/people/accounts/fields/user.user.field_user_comment/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->drupalGet('admin/config/people/accounts/add-storage/user/field_user_comment'); + $this->submitForm($edit, 'Continue'); // We should get an error message. $this->assertSession()->pageTextContains('The submitted value in the Comment type element is not allowed.'); @@ -180,8 +180,8 @@ class CommentFieldsTest extends CommentTestBase { $edit = [ 'settings[comment_type]' => 'user_comment_type', ]; - $this->drupalGet('admin/config/people/accounts/fields/user.user.field_user_comment/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->drupalGet('admin/config/people/accounts/add-storage/user/field_user_comment'); + $this->submitForm($edit, 'Continue'); // We shouldn't get an error message. $this->assertSession()->pageTextNotContains('The submitted value in the Comment type element is not allowed.'); @@ -190,7 +190,7 @@ class CommentFieldsTest extends CommentTestBase { $edit = [ 'settings[per_page]' => 0, ]; - $this->drupalGet('admin/config/people/accounts/fields/user.user.field_user_comment'); + $this->drupalGet('admin/config/people/accounts/add-field/user/field_user_comment'); $this->submitForm($edit, 'Save settings'); $this->assertSession()->statusMessageContains('Saved User comment configuration.', 'status'); } diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index a492996cfff..5334c155b20 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -6,6 +6,8 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Entity\FieldableEntityStorageInterface; +use Drupal\Core\Entity\Plugin\DataType\EntityAdapter; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\FieldException; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\TypedData\OptionsProviderInterface; @@ -680,7 +682,19 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI // runtime item object, so that it can be used as the options provider // without modifying the entity being worked on. if (is_subclass_of($this->getFieldItemClass(), OptionsProviderInterface::class)) { - $items = $entity->get($this->getName()); + try { + $items = $entity->get($this->getName()); + } + catch (\InvalidArgumentException $e) { + // When a field doesn't exist, create a new field item list using a + // temporary base field definition. This step is necessary since there + // may not be a field configuration for the storage when creating a new + // field. + // @todo Simplify in https://www.drupal.org/project/drupal/issues/3347291. + $field_storage = BaseFieldDefinition::createFromFieldStorageDefinition($this); + $entity_adapter = EntityAdapter::createFromEntity($entity); + $items = \Drupal::typedDataManager()->create($field_storage, name: $field_storage->getName(), parent: $entity_adapter); + } return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0); } // @todo: Allow setting custom options provider, see @@ -724,7 +738,7 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI * TRUE if the field has data for any entity; FALSE otherwise. */ public function hasData() { - return \Drupal::entityTypeManager()->getStorage($this->entity_type)->countFieldData($this, TRUE); + return !$this->isNew() && \Drupal::entityTypeManager()->getStorage($this->entity_type)->countFieldData($this, TRUE); } /** diff --git a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php index 3be9c473a41..12362a73ffb 100644 --- a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php +++ b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\field\Functional\EntityReference; use Behat\Mink\Element\NodeElement; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\field\Entity\FieldConfig; use Drupal\node\Entity\Node; use Drupal\taxonomy\Entity\Vocabulary; @@ -119,7 +120,7 @@ class EntityReferenceAdminTest extends BrowserTestBase { $edit = [ 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, ]; - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Continue'); // Add the view to the test field. $edit = [ @@ -131,6 +132,8 @@ class EntityReferenceAdminTest extends BrowserTestBase { 'settings[handler_settings][view][view_and_display]' => 'node_test_view:entity_reference_1', ]; $this->submitForm($edit, 'Save settings'); + $this->assertSession()->statusMessageContains("Saved Test Entity Reference Field configuration.", MessengerInterface::TYPE_STATUS); + $this->assertFieldExistsOnOverview('Test Entity Reference Field'); // Create nodes. $node1 = Node::create([ @@ -205,7 +208,7 @@ class EntityReferenceAdminTest extends BrowserTestBase { $edit = [ 'cardinality' => -1, ]; - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->drupalGet($bundle_path . '/fields/' . $field_path); $term_name = $this->randomString(); $result = \Drupal::entityQuery('taxonomy_term') @@ -219,6 +222,7 @@ class EntityReferenceAdminTest extends BrowserTestBase { 'settings[handler_settings][auto_create]' => 1, ]; $this->submitForm($edit, 'Save settings'); + $this->assertFieldExistsOnOverview($taxonomy_term_field_name); $this->drupalGet($bundle_path . '/fields/' . $field_path); $edit = [ 'set_default_value' => '1', @@ -226,6 +230,7 @@ class EntityReferenceAdminTest extends BrowserTestBase { 'default_value_input[field_' . $taxonomy_term_field_name . '][0][target_id]' => $term_name, ]; $this->submitForm($edit, 'Save settings'); + $this->assertFieldExistsOnOverview($taxonomy_term_field_name); // The term should now exist. $result = \Drupal::entityQuery('taxonomy_term') ->condition('name', $term_name) @@ -382,7 +387,7 @@ class EntityReferenceAdminTest extends BrowserTestBase { $field_edit['settings[handler_settings][target_bundles][' . $bundle . ']'] = TRUE; } - $this->fieldUIAddNewField($bundle_path, $field_name, NULL, 'entity_reference', $storage_edit, $field_edit); + $this->fieldUIAddNewField($bundle_path, $field_name, $field_name, 'entity_reference', $storage_edit, $field_edit); // Returns the generated field name. return $field_name; diff --git a/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php b/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php index e4792ddcdf8..84f20b3501b 100644 --- a/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php +++ b/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php @@ -136,7 +136,7 @@ class EntityReferenceAdminTest extends WebDriverTestBase { $this->assertFieldSelectOptions('settings[target_type]', array_keys(\Drupal::entityTypeManager()->getDefinitions())); // Second step: 'Field settings' form. - $this->submitForm([], 'Save field settings'); + $this->submitForm([], 'Continue'); // The base handler should be selected by default. $this->assertSession()->fieldValueEquals('settings[handler]', 'default:node'); @@ -268,7 +268,7 @@ class EntityReferenceAdminTest extends WebDriverTestBase { 'settings[target_type]' => 'taxonomy_term', ]; $this->drupalGet($bundle_path . '/fields/' . $field_name . '/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->drupalGet($bundle_path . '/fields/' . $field_name); $this->assertSession()->fieldExists('settings[handler_settings][auto_create]'); @@ -279,7 +279,7 @@ class EntityReferenceAdminTest extends WebDriverTestBase { 'settings[target_type]' => 'user', ]; $this->drupalGet($bundle_path . '/fields/' . $field_name . '/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->drupalGet($bundle_path . '/fields/' . $field_name); $this->assertSession()->fieldValueEquals('settings[handler_settings][filter][type]', '_none'); $this->assertSession()->fieldValueEquals('settings[handler_settings][sort][field]', '_none'); @@ -299,7 +299,7 @@ class EntityReferenceAdminTest extends WebDriverTestBase { 'settings[target_type]' => 'node', ]; $this->drupalGet($bundle_path . '/fields/' . $field_name . '/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); // Try to select the views handler. $this->drupalGet($bundle_path . '/fields/' . $field_name); @@ -332,7 +332,7 @@ class EntityReferenceAdminTest extends WebDriverTestBase { 'settings[target_type]' => 'entity_test', ]; $this->drupalGet($bundle_path . '/fields/' . $field_name . '/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->drupalGet($bundle_path . '/fields/' . $field_name); $page->findField('settings[handler]')->setValue('views'); $assert_session diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index 7792ee85421..46c983503a5 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityViewModeInterface; use Drupal\Core\Entity\EntityFormModeInterface; use Drupal\Core\Url; use Drupal\field_ui\FieldUI; +use Drupal\field_ui\Form\FieldConfigEditForm; use Drupal\field_ui\Plugin\Derivative\FieldUiLocalTask; /** @@ -79,6 +80,7 @@ function field_ui_theme() { function field_ui_entity_type_build(array &$entity_types) { /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */ $entity_types['field_config']->setFormClass('edit', 'Drupal\field_ui\Form\FieldConfigEditForm'); + $entity_types['field_config']->setFormClass('default', FieldConfigEditForm::class); $entity_types['field_config']->setFormClass('delete', 'Drupal\field_ui\Form\FieldConfigDeleteForm'); $entity_types['field_config']->setListBuilderClass('Drupal\field_ui\FieldConfigListBuilder'); diff --git a/core/modules/field_ui/src/Controller/FieldConfigAddController.php b/core/modules/field_ui/src/Controller/FieldConfigAddController.php new file mode 100644 index 00000000000..2a5a8b81de4 --- /dev/null +++ b/core/modules/field_ui/src/Controller/FieldConfigAddController.php @@ -0,0 +1,77 @@ +get('tempstore.private')->get('field_ui'), + $container->get('plugin.manager.field.field_type'), + $container->get('plugin.manager.entity_reference_selection') + ); + } + + /** + * Builds the field config instance form. + * + * @param string $entity_type + * The entity type. + * @param string $field_name + * The name of the field to create. + * + * @return array + * The field instance edit form. + */ + public function fieldConfigAddConfigureForm(string $entity_type, string $field_name): array { + // @see \Drupal\field_ui\Form\FieldStorageAddForm::submitForm + $temp_storage = $this->tempStore->get($entity_type . ':' . $field_name); + if (!$temp_storage) { + throw new NotFoundHttpException(); + } + + /** @var \Drupal\Core\Field\FieldConfigInterface $entity */ + $entity = $this->entityTypeManager()->getStorage('field_config')->create([ + ...$temp_storage['field_config_values'], + 'field_storage' => $temp_storage['field_storage'], + ]); + + return $this->entityFormBuilder()->getForm($entity, 'default', [ + 'default_options' => $temp_storage['default_options'], + ]); + } + +} diff --git a/core/modules/field_ui/src/Controller/FieldStorageAddController.php b/core/modules/field_ui/src/Controller/FieldStorageAddController.php new file mode 100644 index 00000000000..c22ca0d94dd --- /dev/null +++ b/core/modules/field_ui/src/Controller/FieldStorageAddController.php @@ -0,0 +1,64 @@ +get('tempstore.private')->get('field_ui') + ); + } + + /** + * Builds the field storage form. + * + * @param string $entity_type + * The entity type. + * @param string $field_name + * The name of the field to create. + * @param string $bundle + * The bundle where the field is being created. + * + * @return array + * The field storage form. + */ + public function storageAddConfigureForm(string $entity_type, string $field_name, string $bundle): array { + // @see \Drupal\field_ui\Form\FieldStorageAddForm::submitForm + $temp_storage = $this->tempStore->get($entity_type . ':' . $field_name); + if (!$temp_storage) { + throw new NotFoundHttpException(); + } + + return $this->entityFormBuilder()->getForm($temp_storage['field_storage'], 'edit', [ + 'entity_type_id' => $entity_type, + 'bundle' => $bundle, + ]); + } + +} diff --git a/core/modules/field_ui/src/Form/FieldConfigEditForm.php b/core/modules/field_ui/src/Form/FieldConfigEditForm.php index acd27872636..f18f550c670 100644 --- a/core/modules/field_ui/src/Form/FieldConfigEditForm.php +++ b/core/modules/field_ui/src/Form/FieldConfigEditForm.php @@ -2,13 +2,16 @@ namespace Drupal\field_ui\Form; +use Drupal\Core\Entity\EntityDisplayRepositoryInterface; use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Entity\Plugin\DataType\EntityAdapter; use Drupal\Core\Field\FieldFilteredMarkup; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; +use Drupal\Core\TempStore\PrivateTempStore; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedDataManagerInterface; use Drupal\Core\Url; @@ -23,6 +26,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class FieldConfigEditForm extends EntityForm { + use FieldStorageCreationTrait; + /** * The entity being used by this form. * @@ -37,6 +42,20 @@ class FieldConfigEditForm extends EntityForm { */ protected $entityTypeBundleInfo; + /** + * The name of the entity type. + * + * @var string + */ + protected string $entityTypeId; + + /** + * The entity bundle. + * + * @var string + */ + protected string $bundle; + /** * Constructs a new FieldConfigDeleteForm object. * @@ -44,9 +63,25 @@ class FieldConfigEditForm extends EntityForm { * The entity type bundle info service. * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typedDataManager * The type data manger. + * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface|null $entityDisplayRepository + * The entity display repository. + * @param \Drupal\Core\TempStore\PrivateTempStore|null $tempStore + * The private tempstore. */ - public function __construct(EntityTypeBundleInfoInterface $entity_type_bundle_info, protected TypedDataManagerInterface $typedDataManager) { + public function __construct( + EntityTypeBundleInfoInterface $entity_type_bundle_info, + protected TypedDataManagerInterface $typedDataManager, + protected ?EntityDisplayRepositoryInterface $entityDisplayRepository = NULL, + protected ?PrivateTempStore $tempStore = NULL) { $this->entityTypeBundleInfo = $entity_type_bundle_info; + if ($this->entityDisplayRepository === NULL) { + @trigger_error('Calling FieldConfigEditForm::__construct() without the $entityDisplayRepository argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3383771', E_USER_DEPRECATED); + $this->entityDisplayRepository = \Drupal::service('entity_display.repository'); + } + if ($this->tempStore === NULL) { + @trigger_error('Calling FieldConfigEditForm::__construct() without the $tempStore argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3383771', E_USER_DEPRECATED); + $this->tempStore = \Drupal::service('tempstore.private')->get('field_ui'); + } } /** @@ -55,7 +90,9 @@ class FieldConfigEditForm extends EntityForm { public static function create(ContainerInterface $container) { return new static( $container->get('entity_type.bundle.info'), - $container->get('typed_data_manager') + $container->get('typed_data_manager'), + $container->get('entity_display.repository'), + $container->get('tempstore.private')->get('field_ui') ); } @@ -261,7 +298,34 @@ class FieldConfigEditForm extends EntityForm { * {@inheritdoc} */ public function save(array $form, FormStateInterface $form_state) { + $temp_storage = $this->tempStore->get($this->entity->getTargetEntityTypeId() . ':' . $this->entity->getName()); + if ($this->entity->isNew()) { + // @todo remove in https://www.drupal.org/project/drupal/issues/3347291. + if ($temp_storage && $temp_storage['field_storage']->isNew()) { + // Save field storage. + try { + $temp_storage['field_storage']->save(); + } + catch (EntityStorageException $e) { + $this->tempStore->delete($this->entity->getTargetEntityTypeId() . ':' . $this->entity->getName()); + $form_state->setRedirectUrl(FieldUI::getOverviewRouteInfo($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle())); + $this->messenger()->addError($this->t('An error occurred while saving the field: @error', ['@error' => $e->getMessage()])); + return; + } + } + } + // Save field config. $this->entity->save(); + if (isset($form_state->getStorage()['default_options'])) { + $default_options = $form_state->getStorage()['default_options']; + // Configure the default display modes. + $this->entityTypeId = $temp_storage['field_config_values']['entity_type']; + $this->bundle = $temp_storage['field_config_values']['bundle']; + $this->configureEntityFormDisplay($temp_storage['field_config_values']['field_name'], $default_options['entity_form_display'] ?? []); + $this->configureEntityViewDisplay($temp_storage['field_config_values']['field_name'], $default_options['entity_view_display'] ?? []); + // Delete the temp store entry. + $this->tempStore->delete($this->entity->getTargetEntityTypeId() . ':' . $this->entity->getName()); + } $this->messenger()->addStatus($this->t('Saved %label configuration.', ['%label' => $this->entity->getLabel()])); diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php index 097af8b1111..ea1f2f94436 100644 --- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php @@ -5,7 +5,6 @@ namespace Drupal\field_ui\Form; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\SortArray; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Entity\EntityDisplayRepositoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FallbackFieldTypeCategory; @@ -13,6 +12,7 @@ use Drupal\Core\Field\FieldTypeCategoryManagerInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\TempStore\PrivateTempStore; use Drupal\field\Entity\FieldStorageConfig; use Drupal\field_ui\FieldUI; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -24,8 +24,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class FieldStorageAddForm extends FormBase { - use FieldStorageCreationTrait; - /** * The name of the entity type. * @@ -54,13 +52,6 @@ class FieldStorageAddForm extends FormBase { */ protected $entityFieldManager; - /** - * The entity display repository. - * - * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface - */ - protected $entityDisplayRepository; - /** * The field type plugin manager. * @@ -86,17 +77,20 @@ class FieldStorageAddForm extends FormBase { * The configuration factory. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * (optional) The entity field manager. - * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository - * (optional) The entity display repository. + * @param \Drupal\Core\TempStore\PrivateTempStore|null $tempStore + * The private tempstore. * @param \Drupal\Core\Field\FieldTypeCategoryManagerInterface|null $fieldTypeCategoryManager * The field type category plugin manager. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, ConfigFactoryInterface $config_factory, EntityFieldManagerInterface $entity_field_manager, EntityDisplayRepositoryInterface $entity_display_repository, protected ?FieldTypeCategoryManagerInterface $fieldTypeCategoryManager = NULL) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, ConfigFactoryInterface $config_factory, EntityFieldManagerInterface $entity_field_manager, protected ?PrivateTempStore $tempStore = NULL, protected ?FieldTypeCategoryManagerInterface $fieldTypeCategoryManager = NULL) { $this->entityTypeManager = $entity_type_manager; $this->fieldTypePluginManager = $field_type_plugin_manager; $this->configFactory = $config_factory; $this->entityFieldManager = $entity_field_manager; - $this->entityDisplayRepository = $entity_display_repository; + if ($this->tempStore === NULL) { + @trigger_error('Calling FieldStorageAddForm::__construct() without the $tempStore argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3383719', E_USER_DEPRECATED); + $this->tempStore = \Drupal::service('tempstore.private')->get('field_ui'); + } if ($this->fieldTypeCategoryManager === NULL) { @trigger_error('Calling FieldStorageAddForm::__construct() without the $fieldTypeCategoryManager argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3375740', E_USER_DEPRECATED); $this->fieldTypeCategoryManager = \Drupal::service('plugin.manager.field.field_type_category'); @@ -119,7 +113,7 @@ class FieldStorageAddForm extends FormBase { $container->get('plugin.manager.field.field_type'), $container->get('config.factory'), $container->get('entity_field.manager'), - $container->get('entity_display.repository'), + $container->get('tempstore.private')->get('field_ui'), $container->get('plugin.manager.field.field_type_category'), ); } @@ -349,7 +343,7 @@ class FieldStorageAddForm extends FormBase { $form['actions'] = ['#type' => 'actions']; $form['actions']['submit'] = [ '#type' => 'submit', - '#value' => $this->t('Save and continue'), + '#value' => $this->t('Continue'), '#button_type' => 'primary', ]; @@ -421,6 +415,8 @@ class FieldStorageAddForm extends FormBase { 'entity_type' => $this->entityTypeId, 'bundle' => $this->bundle, ]; + $default_options = []; + // Check if we're dealing with a preconfigured field. if (strpos($field_storage_type, 'field_ui:') === 0) { [, $field_type, $preset_key] = explode(':', $field_storage_type, 3); @@ -446,40 +442,32 @@ class FieldStorageAddForm extends FormBase { ]; try { - // Create the field storage. - $this->entityTypeManager->getStorage('field_storage_config') - ->create($field_storage_values)->save(); - - // Create the field. - $field = $this->entityTypeManager->getStorage('field_config') - ->create($field_values); - $field->save(); - - // Configure the display modes. - $this->configureEntityFormDisplay($field_name, $default_options['entity_form_display'] ?? []); - $this->configureEntityViewDisplay($field_name, $default_options['entity_view_display'] ?? []); + $field_storage_entity = $this->entityTypeManager->getStorage('field_storage_config')->create($field_storage_values); } catch (\Exception $e) { - $this->messenger()->addError($this->t( - 'There was a problem creating field %label: @message', - ['%label' => $values['label'], '@message' => $e->getMessage()])); + $this->messenger()->addError($this->t('There was a problem creating field %label: @message', ['%label' => $values['label'], '@message' => $e->getMessage()])); return; } + // Save field and field storage values in tempstore. + $this->tempStore->set($this->entityTypeId . ':' . $field_name, [ + 'field_storage' => $field_storage_entity, + 'field_config_values' => $field_values, + 'default_options' => $default_options, + ]); + // Configure next steps in the multi-part form. $destinations = []; $route_parameters = [ - 'field_config' => $field->id(), + 'entity_type' => $this->entityTypeId, + 'field_name' => $field_name, ] + FieldUI::getRouteBundleParameter($entity_type, $this->bundle); - // Always show the field settings step, as the cardinality needs to be - // configured for new fields. $destinations[] = [ - 'route_name' => "entity.field_config.{$this->entityTypeId}_storage_edit_form", + 'route_name' => "field_ui.field_storage_add_{$this->entityTypeId}", 'route_parameters' => $route_parameters, ]; - $destinations[] = [ - 'route_name' => "entity.field_config.{$this->entityTypeId}_field_edit_form", + 'route_name' => "field_ui.field_add_{$this->entityTypeId}", 'route_parameters' => $route_parameters, ]; $destinations[] = [ @@ -494,8 +482,6 @@ class FieldStorageAddForm extends FormBase { // Store new field information for any additional submit handlers. $form_state->set(['fields_added', '_add_new_field'], $field_name); - - $this->messenger()->addMessage($this->t('Your settings have been saved.')); } /** diff --git a/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php b/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php index eeb85e2259f..f83c7d3e9e7 100644 --- a/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php @@ -3,11 +3,15 @@ namespace Drupal\field_ui\Form; use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Entity\Plugin\DataType\EntityAdapter; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\TempStore\PrivateTempStore; +use Drupal\Core\TypedData\TypedDataManagerInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field_ui\FieldUI; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -24,6 +28,34 @@ class FieldStorageConfigEditForm extends EntityForm { */ protected $entity; + /** + * FieldStorageConfigEditForm constructor. + * + * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typedDataManager + * The typed data manager. + * @param \Drupal\Core\TempStore\PrivateTempStore|null $tempStore + * The private tempstore. + */ + public function __construct( + protected TypedDataManagerInterface $typedDataManager, + protected ?PrivateTempStore $tempStore = NULL, + ) { + if ($this->tempStore === NULL) { + @trigger_error('Calling FieldStorageConfigEditForm::__construct() without the $tempStore argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3383720', E_USER_DEPRECATED); + $this->tempStore = \Drupal::service('tempstore.private')->get('field_ui'); + } + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('typed_data_manager'), + $container->get('tempstore.private')->get('field_ui') + ); + } + /** * {@inheritdoc} */ @@ -64,9 +96,10 @@ class FieldStorageConfigEditForm extends EntityForm { * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { + $temp_storage = $this->tempStore->get($this->entity->getTargetEntityTypeId() . ':' . $this->entity->getName()); $form = parent::form($form, $form_state); - $field_label = $form_state->get('field_config')->label(); + $field_label = $this->entity->isNew() ? $temp_storage['field_config_values']['label'] : $form_state->get('field_config')->label(); $form['#title'] = $field_label; $form['#prefix'] = '

' . $this->t('These settings apply to the %field field everywhere it is used. Some also impact the way that data is stored and cannot be changed once data has been created.', ['%field' => $field_label]) . '

'; @@ -85,7 +118,18 @@ class FieldStorageConfigEditForm extends EntityForm { 'entity_id' => NULL, ]; $entity = _field_create_entity_from_ids($ids); - $items = $entity->get($this->entity->getName()); + if (!$this->entity->isNew()) { + $items = $entity->get($this->entity->getName()); + } + else { + // Create a temporary field config so that we can access the field + // definition. + $field_config = $this->entityTypeManager->getStorage('field_config')->create([ + ...$temp_storage['field_config_values'], + 'field_storage' => $temp_storage['field_storage'], + ]); + $items = $this->typedDataManager->create($field_config, name: $this->entity->getName(), parent: EntityAdapter::createFromEntity($entity)); + } $item = $items->first() ?: $items->appendItem(); $form['settings'] += $item->storageSettingsForm($form, $form_state, $this->entity->hasData()); @@ -164,7 +208,7 @@ class FieldStorageConfigEditForm extends EntityForm { */ protected function actions(array $form, FormStateInterface $form_state) { $elements = parent::actions($form, $form_state); - $elements['submit']['#value'] = $this->t('Save field settings'); + $elements['submit']['#value'] = $this->entity->isNew() ? $this->t('Continue') : $this->t('Save'); return $elements; } @@ -218,10 +262,19 @@ class FieldStorageConfigEditForm extends EntityForm { * {@inheritdoc} */ public function save(array $form, FormStateInterface $form_state) { - $field_label = $form_state->get('field_config')->label(); + // Save field storage entity values in tempstore. + if ($this->entity->isNew()) { + $temp_storage = $this->tempStore->get($this->entity->getTargetEntityTypeId() . ':' . $this->entity->getName()); + $field_label = $temp_storage['field_config_values']['label']; + $temp_storage['field_storage'] = $this->entity; + $this->tempStore->set($this->entity->getTargetEntityTypeId() . ':' . $this->entity->getName(), $temp_storage); + } try { - $this->entity->save(); - $this->messenger()->addStatus($this->t('Updated field %label field settings.', ['%label' => $field_label])); + if (!$this->entity->isNew()) { + $field_label = $form_state->get('field_config')->label(); + $this->entity->save(); + $this->messenger()->addMessage($this->t('Your settings have been saved.')); + } $request = $this->getRequest(); if (($destinations = $request->query->all('destinations')) && $next_destination = FieldUI::getNextDestination($destinations)) { $request->query->remove('destinations'); diff --git a/core/modules/field_ui/src/Routing/RouteSubscriber.php b/core/modules/field_ui/src/Routing/RouteSubscriber.php index a84dde31817..affe1ea2c73 100644 --- a/core/modules/field_ui/src/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php @@ -5,6 +5,8 @@ namespace Drupal\field_ui\Routing; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Routing\RouteSubscriberBase; use Drupal\Core\Routing\RoutingEvents; +use Drupal\field_ui\Controller\FieldConfigAddController; +use Drupal\field_ui\Controller\FieldStorageAddController; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -109,6 +111,29 @@ class RouteSubscriber extends RouteSubscriberBase { ); $collection->add("field_ui.field_storage_config_add_$entity_type_id", $route); + $route = new Route( + "$path/add-field/{entity_type}/{field_name}", + [ + '_controller' => FieldConfigAddController::class . '::fieldConfigAddConfigureForm', + '_title' => 'Add field', + ] + $defaults, + ['_permission' => 'administer ' . $entity_type_id . ' fields'], + $options + ); + $collection->add("field_ui.field_add_$entity_type_id", $route); + + // @todo remove in https://www.drupal.org/project/drupal/issues/3347291. + $route = new Route( + "$path/add-storage/{entity_type}/{field_name}", + [ + '_controller' => FieldStorageAddController::class . '::storageAddConfigureForm', + '_title' => 'Add storage', + ] + $defaults, + ['_permission' => 'administer ' . $entity_type_id . ' fields'], + $options + ); + $collection->add("field_ui.field_storage_add_$entity_type_id", $route); + $route = new Route( "$path/fields/reuse", [ diff --git a/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php b/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php index 349aa8a6918..f6813227137 100644 --- a/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php +++ b/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php @@ -240,7 +240,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { $edit = [ 'settings[test_field_storage_setting]' => $string, ]; - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); // Go to the field edit page. $this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field_id); @@ -291,7 +291,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => '', ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->assertSession()->pageTextContains('Number of values is required.'); // Submit a custom number. @@ -300,8 +300,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => 6, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); - $this->assertSession()->pageTextContains('Updated field Body field settings.'); + $this->submitForm($edit, 'Save'); $this->drupalGet($field_edit_path); $this->assertSession()->fieldValueEquals('cardinality', 'number'); $this->assertSession()->fieldValueEquals('cardinality_number', 6); @@ -324,7 +323,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => 1, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->assertSession()->pageTextContains("There is 1 entity with 2 or more values in this field"); // Create a second entity with three values. @@ -337,8 +336,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); - $this->assertSession()->pageTextContains('Updated field Body field settings.'); + $this->submitForm($edit, 'Save'); $this->drupalGet($field_edit_path); $this->assertSession()->fieldValueEquals('cardinality', FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); $this->assertSession()->fieldValueEquals('cardinality_number', 1); @@ -350,7 +348,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => 1, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->assertSession()->pageTextContains("There are 2 entities with 2 or more values in this field"); $edit = [ @@ -358,7 +356,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => 2, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->assertSession()->pageTextContains("There is 1 entity with 3 or more values in this field"); $edit = [ @@ -366,7 +364,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => 3, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); // Test the cardinality validation is not access sensitive. @@ -375,7 +373,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality' => (string) FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $node = $this->drupalCreateNode([ 'private' => TRUE, 'uid' => 0, @@ -396,21 +394,21 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'cardinality_number' => 2, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->assertSession()->pageTextContains("There are 2 entities with 3 or more values in this field"); $edit = [ 'cardinality' => 'number', 'cardinality_number' => 3, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $this->assertSession()->pageTextContains("There is 1 entity with 4 or more values in this field"); $edit = [ 'cardinality' => 'number', 'cardinality_number' => 4, ]; $this->drupalGet($field_edit_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); } /** @@ -490,7 +488,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'field_name' => $field_exceed_max_length_input, ]; $this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/add-field'); - $this->submitForm($edit, 'Save and continue'); + $this->submitForm($edit, 'Continue'); $this->assertSession()->pageTextContains('Machine-readable name cannot be longer than 22 characters but is currently 23 characters long.'); // Create a valid field. @@ -642,14 +640,14 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { $edit['field_name'] = 'title'; $bundle_path = 'admin/structure/types/manage/' . $this->contentType; $this->drupalGet("{$bundle_path}/fields/add-field"); - $this->submitForm($edit, 'Save and continue'); + $this->submitForm($edit, 'Continue'); $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.'); // Try with a base field. $edit['field_name'] = 'sticky'; $bundle_path = 'admin/structure/types/manage/' . $this->contentType; $this->drupalGet("{$bundle_path}/fields/add-field"); - $this->submitForm($edit, 'Save and continue'); + $this->submitForm($edit, 'Continue'); $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.'); } @@ -755,11 +753,17 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { public function testDuplicateFieldName() { // field_tags already exists, so we're expecting an error when trying to // create a new field with the same name. - $url = 'admin/structure/types/manage/' . $this->contentType; - $this->fieldUIAddNewField($url, 'tags', $this->randomMachineName(), 'entity_reference', [], [], FALSE); + $url = 'admin/structure/types/manage/' . $this->contentType . '/fields/add-field'; + $this->drupalGet($url); + $edit = [ + 'label' => $this->randomMachineName(), + 'field_name' => 'tags', + 'new_storage_type' => 'boolean', + ]; + $this->submitForm($edit, 'Continue'); $this->assertSession()->pageTextContains('The machine-readable name is already in use. It must be unique.'); - $this->assertSession()->addressEquals($url . '/fields/add-field'); + $this->assertSession()->addressEquals($url); } /** @@ -770,7 +774,7 @@ class ManageFieldsFunctionalTest extends BrowserTestBase { 'query' => ['destinations' => ['http://example.com']], ]; $this->drupalGet('admin/structure/types/manage/article/fields/node.article.body/storage', $options); - $this->submitForm([], 'Save field settings'); + $this->submitForm([], 'Save'); // The external redirect should not fire. $this->assertSession()->addressEquals('admin/structure/types/manage/article/fields/node.article.body/storage?destinations%5B0%5D=http%3A//example.com'); $this->assertSession()->statusCodeEquals(200); diff --git a/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php b/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php index 7a97872b0ff..3092e9644eb 100644 --- a/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php +++ b/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php @@ -2,7 +2,11 @@ namespace Drupal\Tests\field_ui\Functional; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; +use Drupal\user\Entity\User; // cSpell:ignore downlander @@ -13,10 +17,12 @@ use Drupal\Tests\BrowserTestBase; */ class ManageFieldsTest extends BrowserTestBase { + use FieldUiTestTrait; /** * {@inheritdoc} */ protected static $modules = [ + 'field_test', 'field_ui', 'field_ui_test', 'node', @@ -28,13 +34,20 @@ class ManageFieldsTest extends BrowserTestBase { */ protected $defaultTheme = 'stark'; + /** + * A user with permission to administer node fields, etc. + * + * @var \Drupal\user\UserInterface + */ + protected $adminUser; + /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); - $account = $this->drupalCreateUser(['administer node fields']); - $this->drupalLogin($account); + $this->adminUser = $this->drupalCreateUser(['administer node fields']); + $this->drupalLogin($this->adminUser); $this->config('system.logging') ->set('error_level', ERROR_REPORTING_DISPLAY_ALL) ->save(); @@ -112,4 +125,182 @@ class ManageFieldsTest extends BrowserTestBase { $this->assertStringContainsString($allowed_bundles_text, $element->getText()); } + /** + * Tests adding a field. + */ + public function testAddField() { + $page = $this->getSession()->getPage(); + $type = $this->drupalCreateContentType([ + 'name' => 'Article', + 'type' => 'article', + ]); + + // Create a new field without actually saving it. + $this->fieldUIAddNewField('admin/structure/types/manage/' . $type->id(), 'test_field', 'Test field', 'test_field', [], [], FALSE); + // Assert that the field was not created. + $this->assertNull(FieldStorageConfig::loadByName('node', "field_test_field")); + + $this->drupalGet('/admin/structure/types/manage/' . $type->id() . '/fields/add-field'); + $edit = [ + 'label' => 'Test field', + 'field_name' => 'test_field', + 'new_storage_type' => 'test_field', + ]; + $this->submitForm($edit, 'Continue'); + $this->assertSession()->statusMessageNotContains('Saved'); + + // Change the storage form values. + $edit = ['cardinality_number' => 5]; + $this->submitForm($edit, 'Continue'); + $this->assertSession()->statusMessageNotContains('Saved'); + + // Go back to the field storage form. + $this->drupalGet('/admin/structure/types/manage/' . $type->id() . '/add-storage/node/field_test_field'); + // Assert that the form values persist. + $this->assertEquals(5, $page->findField('cardinality_number')->getValue()); + + // Try creating a field with the same machine name. + $this->drupalGet('/admin/structure/types/manage/' . $type->id() . '/fields/add-field'); + $edit = [ + 'label' => 'Test field', + 'field_name' => 'test_field', + 'new_storage_type' => 'test_field', + ]; + $this->submitForm($edit, 'Continue'); + // Assert that the values in the field storage form are reset. + $this->assertEquals(1, $page->findField('cardinality_number')->getValue()); + + // Assert that the field is created with the new settings. + $this->submitForm([], 'Continue'); + $this->assertSession()->statusMessageNotContains('Saved'); + $this->submitForm([], 'Save settings'); + $this->assertSession()->statusMessageContains('Saved'); + + $this->assertEquals(1, FieldStorageConfig::loadByName('node', 'field_test_field')->getCardinality()); + } + + /** + * Tests multiple users adding a field with the same name. + */ + public function testAddFieldWithMultipleUsers() { + $page = $this->getSession()->getPage(); + // Create two users. + $user1 = $this->drupalCreateUser(['administer node fields']); + $user2 = $this->drupalCreateUser(['administer node fields']); + + $node_type = $this->drupalCreateContentType(); + $bundle_path = '/admin/structure/types/manage/' . $node_type->id(); + + // Start adding a field as user 1, stop prior to saving, but keep the URL. + $this->drupalLogin($user1); + $this->drupalGet($bundle_path . '/fields/add-field'); + $edit = [ + 'label' => 'Test field', + 'field_name' => 'test_field', + 'new_storage_type' => 'test_field', + ]; + $this->submitForm($edit, 'Continue'); + // Make changes to the storage form. + $edit = ['cardinality_number' => 5]; + $storage_form_url = $this->getUrl(); + $this->submitForm($edit, 'Continue'); + $this->drupalLogout(); + + // Actually add a field as user 2. + $this->drupalLogin($user2); + $this->drupalGet($bundle_path . '/fields/add-field'); + $edit = [ + 'label' => 'Test field', + 'field_name' => 'test_field', + 'new_storage_type' => 'test_field', + ]; + $this->submitForm($edit, 'Continue'); + $allowed_no_of_values = $page->findField('cardinality_number')->getValue(); + // Assert that the changes made by any user do not affect other users until + // the field is saved. + $this->assertEquals(1, $allowed_no_of_values); + $this->submitForm(['cardinality_number' => 2], 'Continue'); + $this->submitForm([], 'Save settings'); + $this->assertSession()->pageTextContains("Saved Test field configuration."); + $this->drupalLogout(); + + // Continue adding a field as user 1, using the URL saved previously. + $this->drupalLogin($user1); + $this->drupalGet($storage_form_url); + $this->submitForm([], 'Continue'); + // Assert that the user can go on with configuring a field with a machine + // that is already taken. + $this->assertSession()->pageTextNotContains('error'); + $this->submitForm([], 'Save settings'); + // An error is thrown only after the final 'Save'. + $this->assertSession()->statusMessageContains("An error occurred while saving the field: 'field_storage_config' entity with ID 'node.field_test_field' already exists."); + } + + /** + * Tests editing field when the field exists in temp store. + */ + public function testEditFieldWithLeftOverFieldInTempStore() { + $user = $this->drupalCreateUser(['administer node fields']); + + $node_type = $this->drupalCreateContentType(); + $bundle_path = '/admin/structure/types/manage/' . $node_type->id(); + + // Start adding a field but stop prior to saving. + $this->drupalLogin($user); + $this->drupalGet($bundle_path . '/fields/add-field'); + $edit = [ + 'label' => 'Test field', + 'field_name' => 'test_field', + 'new_storage_type' => 'test_field', + ]; + $this->submitForm($edit, 'Continue'); + + /** @var \Drupal\field\FieldStorageConfigInterface $storage */ + $storage = $this->container->get('entity_type.manager') + ->getStorage('field_storage_config') + ->create([ + 'type' => 'test_field', + 'field_name' => 'test_field', + 'entity_type' => 'node', + ]); + $storage->save(); + + $this->container->get('entity_type.manager') + ->getStorage('field_config') + ->create([ + 'field_storage' => $storage, + 'bundle' => $node_type->id(), + 'entity_type' => 'node', + ]) + ->save(); + + $this->drupalGet("$bundle_path/fields/node.{$node_type->id()}.test_field/storage"); + $this->submitForm([], 'Save'); + $this->assertSession()->statusMessageContains('Your settings have been saved.', 'status'); + + $this->drupalGet("$bundle_path/fields/node.{$node_type->id()}.test_field"); + $this->submitForm([], 'Save settings'); + $this->assertSession()->statusMessageContains('Saved test_field configuration.', 'status'); + } + + /** + * Tests creating entity reference field to non-bundleable entity type. + */ + public function testEntityReferenceToNonBundleableEntity() { + $type = $this->drupalCreateContentType([ + 'name' => 'kittens', + 'type' => 'kittens', + ]); + $bundle_path = 'admin/structure/types/manage/' . $type->id(); + $field_name = 'field_user_reference'; + + $field_edit = [ + 'set_default_value' => '1', + "default_value_input[$field_name][0][target_id]" => $this->adminUser->label() . ' (' . $this->adminUser->id() . ')', + ]; + $this->fieldUIAddNewField($bundle_path, 'user_reference', NULL, 'field_ui:entity_reference:user', [], $field_edit); + $field = FieldConfig::loadByName('node', 'kittens', $field_name); + $this->assertEquals([['target_id' => $this->adminUser->id()]], $field->getDefaultValue(User::create(['name' => '1337']))); + } + } diff --git a/core/modules/field_ui/tests/src/FunctionalJavascript/ManageFieldsTest.php b/core/modules/field_ui/tests/src/FunctionalJavascript/ManageFieldsTest.php index adcc89f0247..3db32a07236 100644 --- a/core/modules/field_ui/tests/src/FunctionalJavascript/ManageFieldsTest.php +++ b/core/modules/field_ui/tests/src/FunctionalJavascript/ManageFieldsTest.php @@ -180,7 +180,7 @@ class ManageFieldsTest extends WebDriverTestBase { $page->fillField('label', $field_name); // Test validation. - $page->pressButton('Save and continue'); + $page->pressButton('Continue'); $assert_session->pageTextContains('You need to select a field type.'); $assert_session->elementExists('css', '[name="new_storage_type"].error'); $assert_session->pageTextNotContains('Choose an option below'); @@ -190,7 +190,7 @@ class ManageFieldsTest extends WebDriverTestBase { $assert_session->assertWaitOnAjaxRequest(); $this->assertTrue($assert_session->elementExists('css', '[name="new_storage_type"][value="number"]')->isSelected()); $assert_session->pageTextContains('Choose an option below'); - $page->pressButton('Save and continue'); + $page->pressButton('Continue'); $assert_session->pageTextContains('You need to select a field type.'); $assert_session->elementNotExists('css', '[name="new_storage_type"].error'); $assert_session->elementExists('css', '[name="group_field_options_wrapper"].error'); @@ -211,9 +211,12 @@ class ManageFieldsTest extends WebDriverTestBase { $this->assertNotEmpty($text_plain = $page->find('xpath', '//*[text() = "Text (plain)"]')->getParent()); $text_plain->click(); $this->assertTrue($assert_session->elementExists('css', '[name="group_field_options_wrapper"][value="string"]')->isSelected()); - - $page->pressButton('Save and continue'); - $assert_session->pageTextContains('Your settings have been saved.'); + $page->pressButton('Continue'); + $this->assertMatchesRegularExpression('/.*article\/add-storage\/node\/field_test_field_1.*/', $this->getUrl()); + $page->pressButton('Continue'); + $this->assertMatchesRegularExpression('/.*article\/add-field\/node\/field_test_field_1.*/', $this->getUrl()); + $page->pressButton('Save settings'); + $assert_session->pageTextContains('Saved ' . $field_name . ' configuration.'); $this->assertNotNull($field_storage = FieldStorageConfig::loadByName('node', "field_$field_name")); $this->assertEquals('string', $field_storage->getType()); @@ -237,8 +240,12 @@ class ManageFieldsTest extends WebDriverTestBase { $this->assertTrue($assert_session->elementExists('css', '[name="new_storage_type"][value="test_field"]')->isSelected()); $assert_session->pageTextNotContains('Choose an option below'); - $page->pressButton('Save and continue'); - $assert_session->pageTextContains('Your settings have been saved.'); + $page->pressButton('Continue'); + $this->assertMatchesRegularExpression('/.*article\/add-storage\/node\/field_test_field_2.*/', $this->getUrl()); + $page->pressButton('Continue'); + $this->assertMatchesRegularExpression('/.*article\/add-field\/node\/field_test_field_2.*/', $this->getUrl()); + $page->pressButton('Save settings'); + $assert_session->pageTextContains('Saved ' . $field_name . ' configuration.'); $this->assertNotNull($field_storage = FieldStorageConfig::loadByName('node', "field_$field_name")); $this->assertEquals('test_field', $field_storage->getType()); } diff --git a/core/modules/field_ui/tests/src/Traits/FieldUiJSTestTrait.php b/core/modules/field_ui/tests/src/Traits/FieldUiJSTestTrait.php index c156684e3f1..1a4625095d6 100644 --- a/core/modules/field_ui/tests/src/Traits/FieldUiJSTestTrait.php +++ b/core/modules/field_ui/tests/src/Traits/FieldUiJSTestTrait.php @@ -61,17 +61,11 @@ trait FieldUiJSTestTrait { $this->assertTrue($field_field_name->isVisible()); $field_field_name->setValue($field_name); - $page->findButton('Save and continue')->click(); + $page->findButton('Continue')->click(); $assert_session->waitForText("These settings apply to the $label field everywhere it is used."); if ($save_settings) { - $breadcrumb_link = $page->findLink($label); - - // Test breadcrumb. - $this->assertTrue($breadcrumb_link->isVisible()); - // Second step: 'Storage settings' form. - $page->findButton('Save field settings')->click(); - $assert_session->pageTextContains("Updated field $label field settings."); + $page->findButton('Continue')->click(); // Third step: 'Field settings' form. $page->findButton('Save settings')->click(); diff --git a/core/modules/field_ui/tests/src/Traits/FieldUiTestTrait.php b/core/modules/field_ui/tests/src/Traits/FieldUiTestTrait.php index 3fca460a0ce..9a01349a307 100644 --- a/core/modules/field_ui/tests/src/Traits/FieldUiTestTrait.php +++ b/core/modules/field_ui/tests/src/Traits/FieldUiTestTrait.php @@ -42,12 +42,12 @@ trait FieldUiTestTrait { // page before calling this method. if ($bundle_path !== NULL) { $bundle_path = "$bundle_path/fields/add-field"; - } - - // First step: 'Add field' page. - if ($bundle_path !== NULL) { + // First step: 'Add field' page. $this->drupalGet($bundle_path); } + else { + $bundle_path = $this->getUrl(); + } try { // First check if the passed in field type is not part of a group. @@ -76,27 +76,25 @@ trait FieldUiTestTrait { ]; } } - $this->submitForm($initial_edit, 'Save and continue'); + $this->submitForm($initial_edit, 'Continue'); + // Assert that the field is not created. + $this->assertFieldDoesNotExist($bundle_path, $label); if ($save_settings) { $this->assertSession()->pageTextContains("These settings apply to the $label field everywhere it is used."); // Test Breadcrumbs. $this->getSession()->getPage()->findLink($label); // Second step: 'Storage settings' form. - $this->submitForm($storage_edit, 'Save field settings'); - $this->assertSession() - ->pageTextContains("Updated field $label field settings."); + $this->submitForm($storage_edit, 'Continue'); + // Assert that the field is not created. + $this->assertFieldDoesNotExist($bundle_path, $label); // Third step: 'Field settings' form. $this->submitForm($field_edit, 'Save settings'); $this->assertSession()->pageTextContains("Saved $label configuration."); // Check that the field appears in the overview form. - $xpath = $this->assertSession() - ->buildXPathQuery("//table[@id=\"field-overview\"]//tr/td[1 and text() = :label]", [ - ':label' => $label, - ]); - $this->assertSession()->elementExists('xpath', $xpath); + $this->assertFieldExistsOnOverview($label); } } @@ -205,4 +203,53 @@ trait FieldUiTestTrait { return NULL; } + /** + * Asserts that the field doesn't exist in the overview form. + * + * @param string $bundle_path + * The bundle path. + * @param string $label + * The field label. + */ + protected function assertFieldDoesNotExist(string $bundle_path, string $label) { + $original_url = $this->getUrl(); + $this->drupalGet(explode('/fields', $bundle_path)[0] . '/fields'); + $this->assertFieldDoesNotExistOnOverview($label); + $this->drupalGet($original_url); + } + + /** + * Asserts that the field appears on the overview form. + * + * @param string $label + * The field label. + * + * @throws \Behat\Mink\Exception\ElementNotFoundException + */ + protected function assertFieldExistsOnOverview(string $label) { + $xpath = $this->assertSession() + ->buildXPathQuery("//table[@id=\"field-overview\"]//tr/td[1 and text() = :label]", [ + ':label' => $label, + ]); + $element = $this->getSession()->getPage()->find('xpath', $xpath); + if ($element === NULL) { + throw new ElementNotFoundException($this->getSession()->getDriver(), 'form field', 'label', $label); + } + } + + /** + * Asserts that the field does not appear on the overview form. + * + * @param string $label + * The field label. + */ + protected function assertFieldDoesNotExistOnOverview(string $label) { + $xpath = $this->assertSession() + ->buildXPathQuery("//table[@id=\"field-overview\"]//tr/td[1 and text() = :label]", [ + ':label' => $label, + ]); + $element = $this->getSession()->getPage()->find('xpath', $xpath); + $this->assertSession()->assert($element === NULL, sprintf('A field "%s" appears on this page, but it should not.', $label)); + } + } diff --git a/core/modules/field_ui/tests/src/Unit/FieldConfigEditFormTest.php b/core/modules/field_ui/tests/src/Unit/FieldConfigEditFormTest.php index 00267079bcb..650baff4c69 100644 --- a/core/modules/field_ui/tests/src/Unit/FieldConfigEditFormTest.php +++ b/core/modules/field_ui/tests/src/Unit/FieldConfigEditFormTest.php @@ -2,6 +2,8 @@ namespace Drupal\Tests\field_ui\Unit; +use Drupal\Core\Entity\EntityDisplayRepositoryInterface; +use Drupal\Core\TempStore\PrivateTempStore; use Drupal\field_ui\Form\FieldConfigEditForm; use Drupal\Tests\UnitTestCase; @@ -27,7 +29,9 @@ class FieldConfigEditFormTest extends UnitTestCase { $entity_type_bundle_info = $this->createMock('\Drupal\Core\Entity\EntityTypeBundleInfoInterface'); $typed_data = $this->createMock('\Drupal\Core\TypedData\TypedDataManagerInterface'); - $this->fieldConfigEditForm = new FieldConfigEditForm($entity_type_bundle_info, $typed_data); + $temp_store = $this->createMock(PrivateTempStore::class); + $entity_display_repository = $this->createMock(EntityDisplayRepositoryInterface::class); + $this->fieldConfigEditForm = new FieldConfigEditForm($entity_type_bundle_info, $typed_data, $entity_display_repository, $temp_store); } /** diff --git a/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php b/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php index 83e12945fd6..2da0a4c14b9 100644 --- a/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php +++ b/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php @@ -260,7 +260,7 @@ class FileFieldWidgetTest extends FileFieldTestBase { // Change the field setting to make its files private, and upload a file. $edit = ['settings[uri_scheme]' => 'private']; $this->drupalGet("admin/structure/types/manage/{$type_name}/fields/{$field_id}/storage"); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); $node = $node_storage->loadUnchanged($nid); $node_file = File::load($node->{$field_name}->target_id); diff --git a/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php b/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php index 4874e98f499..bb270feda8f 100644 --- a/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php +++ b/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php @@ -337,7 +337,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase { $this->drupalGet('admin/structure/types/manage/article/fields/node.article.' . $field_name . '/storage'); $this->submitForm([ 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, - ], 'Save field settings'); + ], 'Save'); $edit = [ 'files[' . $field_name . '_1][]' => \Drupal::service('file_system')->realpath($test_image->uri), ]; @@ -504,7 +504,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase { 'settings[default_image][title]' => $title, ]; $this->drupalGet("admin/structure/types/manage/article/fields/node.article.{$field_name}/storage"); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); // Clear field definition cache so the new default image is detected. \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); $field_storage = FieldStorageConfig::loadByName('node', $field_name); @@ -560,7 +560,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase { // Can't use fillField cause Mink can't fill hidden fields. $this->drupalGet("admin/structure/types/manage/article/fields/node.article.$field_name/storage"); $this->getSession()->getPage()->find('css', 'input[name="settings[default_image][uuid][fids]"]')->setValue(0); - $this->getSession()->getPage()->pressButton('Save field settings'); + $this->getSession()->getPage()->pressButton('Save'); // Clear field definition cache so the new default image is detected. \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); @@ -579,7 +579,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase { 'settings[default_image][title]' => $title, ]; $this->drupalGet('admin/structure/types/manage/article/fields/node.article.' . $private_field_name . '/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); // Clear field definition cache so the new default image is detected. \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); diff --git a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php index f8cd65faeb2..063b0db77cc 100644 --- a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php +++ b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php @@ -196,7 +196,8 @@ class MediaUiFunctionalTest extends MediaFunctionalTestBase { $assert_session = $this->assertSession(); $this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']); - $this->fieldUIAddNewField('/admin/structure/types/manage/page', 'foo_field', 'Foo field', 'field_ui:entity_reference:media', [], [], FALSE); + $this->createMediaType('image', ['id' => 'image', 'new_revision' => TRUE]); + $this->fieldUIAddNewField('/admin/structure/types/manage/page', 'foo_field', 'Foo field', 'field_ui:entity_reference:media', [], ['settings[handler_settings][target_bundles][image]' => TRUE]); $this->drupalGet('/admin/structure/types/manage/page/display'); $assert_session->fieldValueEquals('fields[field_foo_field][type]', 'entity_reference_entity_view'); } @@ -340,13 +341,11 @@ class MediaUiFunctionalTest extends MediaFunctionalTestBase { // settings form. // Using submitForm() to avoid dealing with JavaScript on the previous // page in the field creation. - $this->fieldUIAddNewField("admin/structure/types/manage/{$content_type->id()}", 'media_reference', "Media (cardinality $cardinality)", 'field_ui:entity_reference:media', [], [], FALSE); - $edit = []; + $field_edit = []; foreach ($media_types as $type) { - $edit["settings[handler_settings][target_bundles][$type]"] = TRUE; + $field_edit["settings[handler_settings][target_bundles][$type]"] = TRUE; } - $this->drupalGet("admin/structure/types/manage/{$content_type->id()}/fields/node.{$content_type->id()}.field_media_reference"); - $this->submitForm($edit, "Save settings"); + $this->fieldUIAddNewField("admin/structure/types/manage/{$content_type->id()}", 'media_reference', "Media (cardinality $cardinality)", 'field_ui:entity_reference:media', [], $field_edit); \Drupal::entityTypeManager() ->getStorage('entity_form_display') ->load('node.' . $content_type->id() . '.default') diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/FieldUiIntegrationTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/FieldUiIntegrationTest.php index 9dd2fa9315b..c87def8210b 100644 --- a/core/modules/media_library/tests/src/FunctionalJavascript/FieldUiIntegrationTest.php +++ b/core/modules/media_library/tests/src/FunctionalJavascript/FieldUiIntegrationTest.php @@ -70,8 +70,10 @@ class FieldUiIntegrationTest extends MediaLibraryTestBase { $this->assertNotNull($assert_session->waitForField('label')); $page->fillField('label', 'Shatner'); $this->waitForText('field_shatner'); - $page->pressButton('Save and continue'); - $page->pressButton('Save field settings'); + $page->pressButton('Continue'); + $this->assertMatchesRegularExpression('/.*article\/add-storage\/node\/field_shatner.*/', $this->getUrl()); + $page->pressButton('Continue'); + $this->assertMatchesRegularExpression('/.*article\/add-field\/node\/field_shatner.*/', $this->getUrl()); $assert_session->pageTextNotContains('Undefined index: target_bundles'); $this->waitForFieldExists('Type One')->check(); $this->assertElementExistsAfterWait('css', '[name="settings[handler_settings][target_bundles][type_one]"][checked="checked"]'); diff --git a/core/modules/node/tests/src/Functional/NodeTranslationUITest.php b/core/modules/node/tests/src/Functional/NodeTranslationUITest.php index e808975efdb..c4262ffa531 100644 --- a/core/modules/node/tests/src/Functional/NodeTranslationUITest.php +++ b/core/modules/node/tests/src/Functional/NodeTranslationUITest.php @@ -560,7 +560,7 @@ class NodeTranslationUITest extends ContentTranslationUITestBase { // details form element. $edit = ['cardinality_number' => 2]; $this->drupalGet('admin/structure/types/manage/article/fields/node.article.field_image/storage'); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); // Make the image field non-translatable. $edit = ['settings[node][article][fields][field_image]' => FALSE]; diff --git a/core/modules/node/tests/src/Functional/NodeTypeTranslationTest.php b/core/modules/node/tests/src/Functional/NodeTypeTranslationTest.php index bbab173121b..4bfbbe48de5 100644 --- a/core/modules/node/tests/src/Functional/NodeTypeTranslationTest.php +++ b/core/modules/node/tests/src/Functional/NodeTypeTranslationTest.php @@ -172,8 +172,8 @@ class NodeTypeTranslationTest extends BrowserTestBase { 'new_storage_type' => 'email', 'label' => 'Email', 'field_name' => 'email', - ], 'Save and continue'); - $this->submitForm([], 'Save field settings'); + ], 'Continue'); + $this->submitForm([], 'Continue'); $this->submitForm([], 'Save settings'); $type = $this->randomMachineName(16); diff --git a/core/modules/options/tests/src/Functional/OptionsFieldUITest.php b/core/modules/options/tests/src/Functional/OptionsFieldUITest.php index f7d56397aa5..c89e3e8ea31 100644 --- a/core/modules/options/tests/src/Functional/OptionsFieldUITest.php +++ b/core/modules/options/tests/src/Functional/OptionsFieldUITest.php @@ -373,7 +373,7 @@ class OptionsFieldUITest extends FieldTestBase { $add_button->click(); $add_button->click(); - $this->submitForm($input, 'Save field settings'); + $this->submitForm($input, 'Save'); // Verify that the page does not have double escaped HTML tags. $this->assertSession()->responseNotContains('<'); @@ -406,8 +406,7 @@ class OptionsFieldUITest extends FieldTestBase { $this->drupalGet($this->adminPath); $page = $this->getSession()->getPage(); $page->findButton('Add another item')->click(); - $this->submitForm($edit, 'Save field settings'); - $this->assertSession()->pageTextContains('Updated field ' . $this->fieldName . ' field settings.'); + $this->submitForm($edit, 'Save'); // Select a default value. $edit = [ @@ -469,7 +468,7 @@ class OptionsFieldUITest extends FieldTestBase { // Assert that the button is disabled again. $this->assertTrue($delete_button_0->hasAttribute('disabled'), 'Button is disabled'); // Try to proceed without entering any value. - $page->findButton('Save field settings')->click(); + $page->findButton('Save')->click(); if ($field_type == 'list_string') { // Asserting only name field as there is no value field for list_string. diff --git a/core/modules/options/tests/src/Functional/OptionsFloatFieldImportTest.php b/core/modules/options/tests/src/Functional/OptionsFloatFieldImportTest.php index dfd5ad0645e..2610530d2a4 100644 --- a/core/modules/options/tests/src/Functional/OptionsFloatFieldImportTest.php +++ b/core/modules/options/tests/src/Functional/OptionsFloatFieldImportTest.php @@ -78,7 +78,7 @@ class OptionsFloatFieldImportTest extends FieldTestBase { 'settings[allowed_values][table][1][item][label]' => 'One', ]; $this->drupalGet($admin_path); - $this->submitForm($edit, 'Save field settings'); + $this->submitForm($edit, 'Save'); $field_storage = FieldStorageConfig::loadByName('node', $field_name); $this->assertSame($array = ['0' => 'Zero', '1' => 'One'], $field_storage->getSetting('allowed_values')); diff --git a/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php b/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php index 56d39c0b4dd..593fd85ef04 100644 --- a/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php +++ b/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php @@ -162,7 +162,7 @@ class OptionsFieldUITest extends WebDriverTestBase { $this->assertHasFocusByAttribute('name', $key_element_name); $this->assertAllowValuesRowCount($expected_rows); } - $page->pressButton('Save field settings'); + $page->pressButton('Save'); // Test the order of the option list on node form. $this->drupalGet($this->nodeFormPath); @@ -177,7 +177,7 @@ class OptionsFieldUITest extends WebDriverTestBase { // Change the order the items appear. $drag_handle->dragTo($target); $this->assertOrder(['Second', 'Third', 'First', ''], $is_string_option); - $page->pressButton('Save field settings'); + $page->pressButton('Save'); $this->drupalGet($this->nodeFormPath); $this->assertNodeFormOrder(['- None -', 'Second', 'Third', 'First']); @@ -191,7 +191,7 @@ class OptionsFieldUITest extends WebDriverTestBase { $page->pressButton('remove_row_button__1'); $this->assertSession()->assertWaitOnAjaxRequest(); $this->assertOrder(['Second', 'First', ''], $is_string_option); - $page->pressButton('Save field settings'); + $page->pressButton('Save'); $this->drupalGet($this->nodeFormPath); $this->assertNodeFormOrder(['- None -', 'Second', 'First']); diff --git a/core/modules/search/tests/src/Functional/SearchPageCacheTagsTest.php b/core/modules/search/tests/src/Functional/SearchPageCacheTagsTest.php index 23a7de2d787..1d8c15306f3 100644 --- a/core/modules/search/tests/src/Functional/SearchPageCacheTagsTest.php +++ b/core/modules/search/tests/src/Functional/SearchPageCacheTagsTest.php @@ -157,7 +157,7 @@ class SearchPageCacheTagsTest extends BrowserTestBase { ]); $this->drupalLogin($admin_user); - $this->fieldUIAddNewField($bundle_path, 'test__ref', 'Test label', 'entity_reference', [], [], FALSE); + $this->fieldUIAddNewField($bundle_path, 'test__ref', 'Test label', 'entity_reference', [], ['settings[handler_settings][target_bundles][page]' => TRUE]); // Create a new node of our newly created node type and fill in the entity // reference field. $edit = [