diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index db6505f..42ccdda 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -237,12 +237,6 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI */ public function __construct(array $values, $entity_type = 'field_storage_config') { // Check required properties. -// if (empty($values['field_name'])) { -// throw new FieldException('Attempt to create a field storage without a field name.'); -// } -// if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['field_name'])) { -// throw new FieldException("Attempt to create a field storage {$values['field_name']} with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character"); -// } if (empty($values['type'])) { throw new FieldException("Attempt to create a field storage {$values['field_name']} with no type."); } @@ -304,6 +298,13 @@ protected function preSaveNew(EntityStorageInterface $storage) { // Assign the ID. $this->id = $this->id(); + // Validate that we have a field name and that it is valid. + if (!$this->getName()) { + throw new FieldException('Attempt to create a field storage without a field name.'); + } + if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $this->getName())) { + throw new FieldException("Attempt to create a field storage {$this->getName()} with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character"); + } // Field name cannot be longer than FieldStorageConfig::NAME_MAX_LENGTH characters. // We use Unicode::strlen() because the DB layer assumes that column widths // are given in characters rather than bytes. @@ -352,6 +353,9 @@ protected function preSaveUpdated(EntityStorageInterface $storage) { $entity_manager = \Drupal::entityManager(); // Some updates are always disallowed. + if ($this->getName() != $this->original->getName()) { + throw new FieldException("Cannot change the field name for an existing field storage."); + } if ($this->getType() != $this->original->getType()) { throw new FieldException("Cannot change the field type for an existing field storage."); } diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php index 46ef63b..b587c67 100644 --- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php @@ -166,7 +166,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t ); } - // Field label and field_name. + // New field storage subform wrapper. $form['new_storage_wrapper'] = [ '#type' => 'container', '#attributes' => [ @@ -175,26 +175,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t ]; if ($form_state->isRebuilding() && ($new_storage_type = $form_state->getValue('new_storage_type'))) { - $initial_values = $this->getInitialValues($new_storage_type); - - $field_storage_values = [ - 'entity_type' => $form_state->get('entity_type_id'), - 'type' => $initial_values['type'], - ] + $initial_values['field_storage']; - $field_storage = $this->entityManager->getStorage('field_storage_config')->create($field_storage_values); - - $form_object = $this->entityManager->getFormObject('field_storage_config', 'edit'); - $form_object->setEntity($field_storage); - - $form_state = (new FormState())->setFormState([ - 'entity_type_id' => $form_state->get('entity_type_id'), - 'bundle' => $form_state->get('bundle'), - ]); - - $field_storage_form = $form_object->form([], $form_state); - unset($field_storage_form['#process'], $field_storage_form['#after_build']); - $field_storage_form['cardinality_container']['#parents'] = ['new_storage_wrapper']; - + // Field label and field_name. $form['new_storage_wrapper']['label'] = array( '#type' => 'textfield', '#title' => $this->t('Label'), @@ -221,6 +202,42 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t '#weight' => -14, ); + // Instantiate the field storage config and field config objects that we + // will work with throughout the life-cycle of this form. + $preconfigured_values = $this->getPreconfiguredValues($new_storage_type); + + $field_storage_values = [ + 'entity_type' => $this->entityTypeId, + 'type' => $preconfigured_values['type'], + ] + $preconfigured_values['field_storage']; + $field_storage_config = $this->entityManager->getStorage('field_storage_config')->create($field_storage_values); + $form_state->set('field_storage_config', $field_storage_config); + + $field_values = [ + 'entity_type' => $this->entityTypeId, + 'bundle' => $this->bundle, + 'field_storage' => $field_storage_config, + ] + $preconfigured_values['field']; + $field_config = $this->entityManager->getStorage('field_config')->create($field_values); + $form_state->set('field_config', $field_config); + + $form_state->set('preconfigured_widget_id', $preconfigured_values['widget_id']); + $form_state->set('preconfigured_formatter_id', $preconfigured_values['formatter_id']); + + // Instantiate the field storage config entity form. + $form_object = $this->entityManager->getFormObject('field_storage_config', 'edit'); + $form_object->setEntity($field_storage_config); + + $form_state = (new FormState())->setFormState([ + 'entity_type_id' => $form_state->get('entity_type_id'), + 'bundle' => $form_state->get('bundle'), + 'field_config' => $field_config, + ]); + + $field_storage_form = $form_object->form([], $form_state); + unset($field_storage_form['#process'], $field_storage_form['#after_build']); + $field_storage_form['cardinality_container']['#parents'] = ['new_storage_wrapper']; + $form['new_storage_wrapper'] += $field_storage_form; } @@ -262,6 +279,15 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } /** + * Form submission handler for the 'new field type' element. + */ + public function newStorageTypeSubmit($form, FormStateInterface $form_state) { + // @todo Set some property on $form_state to indicate that we need to + // display the field storage config subform. + $form_state->setRebuild(); + } + + /** * Handles changes to the selected field storage type. */ public function buildAjaxFieldStorageConfig(array $form, FormStateInterface $form_state) { @@ -320,6 +346,7 @@ protected function validateAddNew(array $form, FormStateInterface $form_state) { // Also run the field storage config form validation. $form_object = $this->entityManager->getFormObject('field_storage_config', 'edit'); + $form_object->setEntity($form_state->get('field_storage_config')); $form_object->validateForm($form['new_storage_wrapper'], $form_state); } } @@ -354,48 +381,36 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // Create new field. if ($values['new_storage_type']) { - $preconfigured_values = $this->getInitialValues($values['new_storage_type']); + $field_storage_config = $form_state->get('field_storage_config'); + $field_config = $form_state->get('field_config'); - $field_storage_values = [ - 'type' => $preconfigured_values['type'], - 'field_name' => $values['field_name'], - 'entity_type' => $this->entityTypeId, - 'translatable' => $values['translatable'], - ] + $preconfigured_values['field_storage']; + $field_storage_config + ->set('field_name', $values['field_name']) + ->set('translatable', $values['translatable']); - $field_values = [ - 'field_name' => $values['field_name'], - 'entity_type' => $this->entityTypeId, - 'bundle' => $this->bundle, - 'label' => $values['label'], + $field_config + ->set('field_name', $values['field_name']) + ->set('label', $values['label']) // Field translatability should be explicitly enabled by the users. - 'translatable' => FALSE, - ] + $preconfigured_values['field']; - - $widget_id = $preconfigured_values['widget_id']; - $formatter_id = $preconfigured_values['formatter_id']; + ->set('translatable', FALSE); // Create the field storage and field. try { - // Merge in the values from the field storage edit subform. - $field_storage = $this->entityManager->getStorage('field_storage_config')->create($field_storage_values); - + // Allow the field storage edit subform to also set its values. $form_object = $this->entityManager->getFormObject('field_storage_config', 'edit'); - $form_object->setEntity($field_storage); + $form_object->setEntity($field_storage_config); $form_object->submitForm($form['new_storage_wrapper'], $form_state); - $field_storage_values = $form_object->getEntity()->toArray() + $field_storage_values; - $this->entityManager->getStorage('field_storage_config')->create($field_storage_values)->save(); - $field = $this->entityManager->getStorage('field_config')->create($field_values); - $field->save(); + $field_storage_config = $form_object->getEntity(); + $field_storage_config->save(); + $field_config->save(); - $this->configureEntityFormDisplay($values['field_name'], $widget_id); - $this->configureEntityViewDisplay($values['field_name'], $formatter_id); + $this->configureEntityFormDisplay($values['field_name'], $form_state->get('preconfigured_widget_id')); + $this->configureEntityViewDisplay($values['field_name'], $form_state->get('preconfigured_formatter_id')); - // Always show the field settings step, as the cardinality needs to be - // configured for new fields. + // Always show the field settings step. $route_parameters = array( - 'field_config' => $field->id(), + 'field_config' => $field_config->id(), ) + FieldUI::getRouteBundleParameter($entity_type, $this->bundle); $destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_field_edit_form", 'route_parameters' => $route_parameters); $destinations[] = array('route_name' => "entity.{$this->entityTypeId}.field_ui_fields", 'route_parameters' => $route_parameters); @@ -454,7 +469,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { * Gets the default properties for the config entities created by this form. * * @param string $field_type - * The field type selection from the 'new storage type' form element. + * The value selected in the 'new storage type' form element. * * @return array * An array with the following structure: @@ -465,8 +480,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { * - widget_id: (string) The default widget plugin ID. * - formatter_id: (string) The default formatter plugin ID. */ - protected function getInitialValues($field_type) { - $initial_values = [ + protected function getPreconfiguredValues($field_type) { + $preconfigured_values = [ 'type' => $field_type, 'field_storage' => [], 'field' => [], @@ -476,7 +491,7 @@ protected function getInitialValues($field_type) { if (strpos($field_type, 'field_ui:') !== FALSE) { list(, $field_type, $option_key) = explode(':', $field_type, 3); - $initial_values['type'] = $field_type; + $preconfigured_values['type'] = $field_type; $field_type_class = $this->fieldTypePluginManager->getDefinition($field_type)['class']; $field_options = $field_type_class::getPreconfiguredOptions()[$option_key]; @@ -485,7 +500,7 @@ protected function getInitialValues($field_type) { if (isset($field_options['field_storage_config'])) { foreach (array('cardinality', 'settings') as $key) { if (isset($field_options['field_storage_config'][$key])) { - $initial_values['field_storage'][$key] = $field_options['field_storage_config'][$key]; + $preconfigured_values['field_storage'][$key] = $field_options['field_storage_config'][$key]; } } } @@ -494,16 +509,16 @@ protected function getInitialValues($field_type) { if (isset($field_options['field_config'])) { foreach (array('required', 'settings') as $key) { if (isset($field_options['field_config'][$key])) { - $initial_values['field'][$key] = $field_options['field_config'][$key]; + $preconfigured_values['field'][$key] = $field_options['field_config'][$key]; } } } - $initial_values['widget_id'] = isset($field_options['entity_form_display']['type']) ? $field_options['entity_form_display']['type'] : NULL; - $initial_values['formatter_id'] = isset($field_options['entity_view_display']['type']) ? $field_options['entity_view_display']['type'] : NULL; + $preconfigured_values['widget_id'] = isset($field_options['entity_form_display']['type']) ? $field_options['entity_form_display']['type'] : NULL; + $preconfigured_values['formatter_id'] = isset($field_options['entity_view_display']['type']) ? $field_options['entity_view_display']['type'] : NULL; } - return $initial_values; + return $preconfigured_values; } /** diff --git a/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php b/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php index c651b0a..00d1b5d 100644 --- a/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php @@ -92,13 +92,7 @@ public function form(array $form, FormStateInterface $form_state) { 'entity_id' => NULL ); $entity = _field_create_entity_from_ids($ids); - - // @todo Use a proper FieldStorageDefinition class when it becomes available - // in https://www.drupal.org/node/2280639. - $field_storage_definition = BaseFieldDefinition::create($this->entity->getType()); - $field_storage_definition->getItemDefinition()->setSettings($this->entity->getSettings()); - - $items = FieldItemList::createInstance($field_storage_definition, NULL, $entity->getTypedData()); + $items = FieldItemList::createInstance($form_state->get('field_config'), NULL, $entity->getTypedData()); $item = $items->first() ?: $items->appendItem(); $form['settings'] += $item->storageSettingsForm($form, $form_state, $this->entity->hasData());