Loading core/modules/field_ui/js/field_ui.js +0 −41 Original line number Diff line number Diff line Loading @@ -31,47 +31,6 @@ '.js-form-item-existing-storage-label label', ) .addClass('js-form-required form-required'); const $newFieldType = $form.find('select[name="new_storage_type"]'); const $existingStorageName = $form.find( 'select[name="existing_storage_name"]', ); const $existingStorageLabel = $form.find( 'input[name="existing_storage_label"]', ); // When the user selects a new field type, clear the "existing field" // selection. $newFieldType.on('change', function () { if (this.value !== '') { // Reset the "existing storage name" selection. if ($existingStorageName.length) { $existingStorageName[0].value = ''; $existingStorageName.trigger('change'); } } }); // When the user selects an existing storage name, clear the "new field // type" selection and populate the 'existing_storage_label' element. $existingStorageName.on('change', function () { const { value } = this; if (value !== '') { if ($newFieldType.length) { // Reset the "new field type" selection. $newFieldType[0].value = ''; $newFieldType.trigger('change'); } // Pre-populate the "existing storage label" element. if ( typeof drupalSettings.existingFieldLabels[value] !== 'undefined' ) { $existingStorageLabel[0].value = drupalSettings.existingFieldLabels[value]; } } }); } }, }; Loading core/modules/field_ui/src/Form/FieldStorageAddForm.php +146 −154 Original line number Diff line number Diff line Loading @@ -97,13 +97,6 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Fie } } /** * {@inheritdoc} */ public function getFormId() { return 'field_ui_field_storage_add_form'; } /** * {@inheritdoc} */ Loading @@ -118,6 +111,13 @@ public static function create(ContainerInterface $container) { ); } /** * {@inheritdoc} */ public function getFormId() { return 'field_ui_field_storage_add_form'; } /** * {@inheritdoc} */ Loading Loading @@ -156,8 +156,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t 'field_ui/drupal.field_ui.manage_fields', 'core/drupal.ajax', ]; // The group info is stored in new_storage_type. if ($form_state->getValue('new_storage_type')) { if ($form_state->hasValue('new_storage_type')) { // A group is already selected. Show field types for that group. $this->addFieldOptionsForGroup($form, $form_state); } Loading @@ -170,108 +170,36 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } /** * Adds field types for the selected group to the form. * Save field type definitions and categories in the form state. * * Get all field type definitions and store each one twice: * - field_type_options: each field type is indexed by its category plugin ID * or its label. * - unique_definitions: each field type is indexed by its category and name. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function addFieldOptionsForGroup(array &$form, FormStateInterface $form_state): void { // Field label and field_name. $form['new_storage_wrapper'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['field-ui-new-storage-wrapper'], ], ]; $form['new_storage_wrapper']['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#size' => 30, ]; $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); $form['new_storage_wrapper']['field_name'] = [ '#type' => 'machine_name', '#field_prefix' => $field_prefix, '#size' => 15, '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'), // Calculate characters depending on the length of the field prefix // setting. Maximum length is 32. '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix), '#machine_name' => [ 'source' => ['new_storage_wrapper', 'label'], 'exists' => [$this, 'fieldNameExists'], ], '#required' => FALSE, ]; $form['actions']['submit']['#validate'][] = '::validateAddNew'; $form['actions']['back'] = [ '#type' => 'submit', '#value' => $this->t('Back'), '#submit' => ['::startOver'], ]; $field_type_options = $form_state->get('field_type_options'); $new_storage_type = $form_state->getValue('new_storage_type'); $form['new_storage_type'] = [ '#type' => 'value', '#value' => $new_storage_type, ]; if (!isset($new_storage_type) || !$field_type_options[$new_storage_type]['display_as_group']) { return; } // Create a wrapper for all the field options to be provided. $form['group_field_options_wrapper'] = [ '#prefix' => '<div id="group-field-options-wrapper" class="group-field-options-wrapper">', '#suffix' => '</div>', ]; $form['group_field_options_wrapper']['label'] = [ '#type' => 'label', '#title' => $this->t('Choose an option below'), '#required' => TRUE, ]; $form['group_field_options_wrapper']['fields'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['group-field-options'], ], ]; $unique_definitions = $form_state->get('unique_definitions'); $group_field_options = []; foreach ($unique_definitions[$new_storage_type] as $option_key => $option) { $radio_element = [ '#type' => 'radio', '#theme_wrappers' => ['form_element__new_storage_type'], '#title' => $option['label'], '#description' => [ '#theme' => 'item_list', '#items' => $unique_definitions[$new_storage_type][$option_key]['description'], ], '#id' => $option['unique_identifier'], '#weight' => $option['weight'], '#parents' => ['group_field_options_wrapper'], '#attributes' => [ 'class' => ['field-option-radio'], 'data-once' => 'field-click-to-select', ], '#wrapper_attributes' => [ 'class' => ['js-click-to-select', 'subfield-option'], ], '#variant' => 'field-suboption', ]; $radio_element['#return_value'] = $option['unique_identifier']; if ((string) $option['unique_identifier'] === 'entity_reference') { $radio_element['#title'] = 'Other'; $radio_element['#weight'] = 10; protected function processFieldDefinitions(FormStateInterface $form_state): void { $field_type_options = $unique_definitions = []; $grouped_definitions = $this->fieldTypePluginManager ->getGroupedDefinitions($this->fieldTypePluginManager->getEntityTypeUiDefinitions($this->entityTypeId), 'label', 'id'); foreach ($grouped_definitions as $category => $field_types) { foreach ($field_types as $name => $field_type) { $definition = ['unique_identifier' => $name] + $field_type; $category_info = $this->fieldTypeCategoryManager ->createInstance($field_type['category'], $definition); $definition['display_as_group'] = !($category_info instanceof FallbackFieldTypeCategory); $id = $this->fieldTypeCategoryManager->hasDefinition($category) ? $category_info->getPluginId() : (string) $field_type['label']; $field_type_options[$id] = $definition; $unique_definitions[$category][$name] = $definition; } $group_field_options[$option['unique_identifier']] = $radio_element; } uasort($group_field_options, [SortArray::class, 'sortByWeightProperty']); $form['group_field_options_wrapper']['fields'] += $group_field_options; $form_state->set('field_type_options', $field_type_options); $form_state->set('unique_definitions', $unique_definitions); } /** Loading @@ -286,18 +214,17 @@ protected function addFieldOptionsForGroup(array &$form, FormStateInterface $for * The current state of the form. */ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_state): void { $field_type_options = $form_state->get('field_type_options'); $field_type_options_radios = []; foreach ($field_type_options as $id => $field_type) { foreach ($form_state->get('field_type_options') as $id => $field_type) { /** @var \Drupal\Core\Field\FieldTypeCategoryInterface $category_info */ $category_info = $this->fieldTypeCategoryManager->createInstance($field_type['category'], $field_type); $category_info = $this->fieldTypeCategoryManager ->createInstance($field_type['category'], $field_type); $display_as_group = $field_type['display_as_group']; $cleaned_class_name = Html::getClass($field_type['unique_identifier']); $field_type_options_radios[$id] = [ '#type' => 'container', '#attributes' => [ 'class' => ['field-option', 'js-click-to-select'], 'checked' => $this->getRequest()->request->get('new_storage_type') !== NULL && $this->getRequest()->request->get('new_storage_type') == ($display_as_group ? $field_type['category'] : $field_type['unique_identifier']), ], '#weight' => $category_info->getWeight(), 'thumb' => [ Loading @@ -308,8 +235,9 @@ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_s 'icon' => [ '#type' => 'container', '#attributes' => [ 'class' => ['field-option__icon', $display_as_group ? "field-icon-$field_type[category]" : "field-icon-$cleaned_class_name", 'class' => [ 'field-option__icon', $display_as_group ? "field-icon-$field_type[category]" : "field-icon-$cleaned_class_name", ], ], ], Loading @@ -321,8 +249,8 @@ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_s '#title_display' => 'before', '#description_display' => 'before', '#theme_wrappers' => ['form_element__new_storage_type'], // If it is a category, set return value as the category label, // otherwise, set it as the field type id. // If it is a category, set return value as the category label. // Otherwise, set it as the field type id. '#return_value' => $display_as_group ? $field_type['category'] : $field_type['unique_identifier'], '#attributes' => [ 'class' => ['field-option-radio'], Loading Loading @@ -358,54 +286,116 @@ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_s ]; $form['add']['new_storage_type'] = $field_type_options_radios; $form['group_submit'] = [ '#type' => 'submit', '#value' => $this->t('Change field group'), '#limit_validation_errors' => [], '#attributes' => [ 'class' => ['js-hide'], ], '#submit' => [[static::class, 'rebuildWithOptions']], ]; $form['actions']['submit']['#validate'][] = '::validateGroupOrField'; $form['actions']['submit']['#submit'][] = '::rebuildWithOptions'; } /** * Save field type definitions and categories in the form state. * * Get all field type definitions and store each one twice: * - field_type_options: each field type is indexed by its category plugin ID * or its label. * - unique_definitions: each field type is indexed by its category and name. * Adds field types for the selected group to the form. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function processFieldDefinitions(FormStateInterface $form_state): void { $field_type_options = $unique_definitions = []; $grouped_definitions = $this->fieldTypePluginManager->getGroupedDefinitions($this->fieldTypePluginManager->getEntityTypeUiDefinitions($this->entityTypeId), 'label', 'id'); // Invoke a hook to get category properties. foreach ($grouped_definitions as $category => $field_types) { foreach ($field_types as $name => $field_type) { $definition = ['unique_identifier' => $name] + $field_type; $category_info = $this->fieldTypeCategoryManager ->createInstance($field_type['category'], $definition); $definition['display_as_group'] = !($category_info instanceof FallbackFieldTypeCategory); if ($this->fieldTypeCategoryManager->hasDefinition($category)) { $id = $category_info->getPluginId(); } else { $id = (string) $field_type['label']; protected function addFieldOptionsForGroup(array &$form, FormStateInterface $form_state): void { // Field label and field_name. $form['new_storage_wrapper'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['field-ui-new-storage-wrapper'], ], ]; $form['new_storage_wrapper']['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#size' => 30, ]; $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); $form['new_storage_wrapper']['field_name'] = [ '#type' => 'machine_name', '#field_prefix' => $field_prefix, '#size' => 15, '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'), // Calculate characters depending on the length of the field prefix // setting. Maximum length is 32. '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix), '#machine_name' => [ 'source' => ['new_storage_wrapper', 'label'], 'exists' => [$this, 'fieldNameExists'], ], '#required' => FALSE, ]; $form['actions']['submit']['#validate'][] = '::validateFieldType'; $form['actions']['back'] = [ '#type' => 'submit', '#value' => $this->t('Back'), '#submit' => ['::startOver'], ]; $field_type_options = $form_state->get('field_type_options'); $new_storage_type = $form_state->getValue('new_storage_type'); $form['new_storage_type'] = [ '#type' => 'value', '#value' => $new_storage_type, ]; if (!isset($new_storage_type) || !$field_type_options[$new_storage_type]['display_as_group']) { return; } $field_type_options[$id] = $definition; $unique_definitions[$category][$name] = $definition; // Create a wrapper for all the field options to be provided. $form['group_field_options_wrapper'] = [ '#prefix' => '<div id="group-field-options-wrapper" class="group-field-options-wrapper">', '#suffix' => '</div>', ]; $form['group_field_options_wrapper']['label'] = [ '#type' => 'label', '#title' => $this->t('Choose an option below'), '#required' => TRUE, ]; $form['group_field_options_wrapper']['fields'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['group-field-options'], ], ]; $unique_definitions = $form_state->get('unique_definitions')[$new_storage_type] ?? []; $group_field_options = []; foreach ($unique_definitions as $option) { $identifier = $option['unique_identifier']; $radio_element = [ '#type' => 'radio', '#theme_wrappers' => ['form_element__new_storage_type'], '#title' => $option['label'], '#description' => [ '#theme' => 'item_list', '#items' => $option['description'], ], '#id' => $identifier, '#weight' => $option['weight'], '#parents' => ['group_field_options_wrapper'], '#attributes' => [ 'class' => ['field-option-radio'], 'data-once' => 'field-click-to-select', ], '#wrapper_attributes' => [ 'class' => ['js-click-to-select', 'subfield-option'], ], '#variant' => 'field-suboption', '#return_value' => $identifier, ]; if ($identifier === 'entity_reference') { $radio_element['#title'] = 'Other'; $radio_element['#weight'] = 10; } $group_field_options[$identifier] = $radio_element; } $form_state->set('field_type_options', $field_type_options); $form_state->set('unique_definitions', $unique_definitions); uasort($group_field_options, [SortArray::class, 'sortByWeightProperty']); $form['group_field_options_wrapper']['fields'] += $group_field_options; } /** Loading @@ -430,7 +420,7 @@ public function validateGroupOrField(array &$form, FormStateInterface $form_stat * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ public function validateAddNew(array $form, FormStateInterface $form_state) { public function validateFieldType(array $form, FormStateInterface $form_state) { // Missing label. if (!$form_state->getValue('label')) { $form_state->setErrorByName('label', $this->t('Add new field: you need to provide a label.')); Loading Loading @@ -466,15 +456,15 @@ public function submitForm(array &$form, FormStateInterface $form_state) { '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) { if (str_starts_with($field_storage_type, 'field_ui:')) { [, $field_type, $preset_key] = explode(':', $field_storage_type, 3); $default_options = $this->getNewFieldDefaults($field_type, $preset_key); } else { $field_type = $field_storage_type; $default_options = []; } $field_values += [ ...$default_options['field_config'] ?? [], Loading @@ -493,7 +483,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ]; try { $field_storage_entity = $this->entityTypeManager->getStorage('field_storage_config')->create($field_storage_values); $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()])); Loading Loading
core/modules/field_ui/js/field_ui.js +0 −41 Original line number Diff line number Diff line Loading @@ -31,47 +31,6 @@ '.js-form-item-existing-storage-label label', ) .addClass('js-form-required form-required'); const $newFieldType = $form.find('select[name="new_storage_type"]'); const $existingStorageName = $form.find( 'select[name="existing_storage_name"]', ); const $existingStorageLabel = $form.find( 'input[name="existing_storage_label"]', ); // When the user selects a new field type, clear the "existing field" // selection. $newFieldType.on('change', function () { if (this.value !== '') { // Reset the "existing storage name" selection. if ($existingStorageName.length) { $existingStorageName[0].value = ''; $existingStorageName.trigger('change'); } } }); // When the user selects an existing storage name, clear the "new field // type" selection and populate the 'existing_storage_label' element. $existingStorageName.on('change', function () { const { value } = this; if (value !== '') { if ($newFieldType.length) { // Reset the "new field type" selection. $newFieldType[0].value = ''; $newFieldType.trigger('change'); } // Pre-populate the "existing storage label" element. if ( typeof drupalSettings.existingFieldLabels[value] !== 'undefined' ) { $existingStorageLabel[0].value = drupalSettings.existingFieldLabels[value]; } } }); } }, }; Loading
core/modules/field_ui/src/Form/FieldStorageAddForm.php +146 −154 Original line number Diff line number Diff line Loading @@ -97,13 +97,6 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Fie } } /** * {@inheritdoc} */ public function getFormId() { return 'field_ui_field_storage_add_form'; } /** * {@inheritdoc} */ Loading @@ -118,6 +111,13 @@ public static function create(ContainerInterface $container) { ); } /** * {@inheritdoc} */ public function getFormId() { return 'field_ui_field_storage_add_form'; } /** * {@inheritdoc} */ Loading Loading @@ -156,8 +156,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t 'field_ui/drupal.field_ui.manage_fields', 'core/drupal.ajax', ]; // The group info is stored in new_storage_type. if ($form_state->getValue('new_storage_type')) { if ($form_state->hasValue('new_storage_type')) { // A group is already selected. Show field types for that group. $this->addFieldOptionsForGroup($form, $form_state); } Loading @@ -170,108 +170,36 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } /** * Adds field types for the selected group to the form. * Save field type definitions and categories in the form state. * * Get all field type definitions and store each one twice: * - field_type_options: each field type is indexed by its category plugin ID * or its label. * - unique_definitions: each field type is indexed by its category and name. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function addFieldOptionsForGroup(array &$form, FormStateInterface $form_state): void { // Field label and field_name. $form['new_storage_wrapper'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['field-ui-new-storage-wrapper'], ], ]; $form['new_storage_wrapper']['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#size' => 30, ]; $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); $form['new_storage_wrapper']['field_name'] = [ '#type' => 'machine_name', '#field_prefix' => $field_prefix, '#size' => 15, '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'), // Calculate characters depending on the length of the field prefix // setting. Maximum length is 32. '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix), '#machine_name' => [ 'source' => ['new_storage_wrapper', 'label'], 'exists' => [$this, 'fieldNameExists'], ], '#required' => FALSE, ]; $form['actions']['submit']['#validate'][] = '::validateAddNew'; $form['actions']['back'] = [ '#type' => 'submit', '#value' => $this->t('Back'), '#submit' => ['::startOver'], ]; $field_type_options = $form_state->get('field_type_options'); $new_storage_type = $form_state->getValue('new_storage_type'); $form['new_storage_type'] = [ '#type' => 'value', '#value' => $new_storage_type, ]; if (!isset($new_storage_type) || !$field_type_options[$new_storage_type]['display_as_group']) { return; } // Create a wrapper for all the field options to be provided. $form['group_field_options_wrapper'] = [ '#prefix' => '<div id="group-field-options-wrapper" class="group-field-options-wrapper">', '#suffix' => '</div>', ]; $form['group_field_options_wrapper']['label'] = [ '#type' => 'label', '#title' => $this->t('Choose an option below'), '#required' => TRUE, ]; $form['group_field_options_wrapper']['fields'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['group-field-options'], ], ]; $unique_definitions = $form_state->get('unique_definitions'); $group_field_options = []; foreach ($unique_definitions[$new_storage_type] as $option_key => $option) { $radio_element = [ '#type' => 'radio', '#theme_wrappers' => ['form_element__new_storage_type'], '#title' => $option['label'], '#description' => [ '#theme' => 'item_list', '#items' => $unique_definitions[$new_storage_type][$option_key]['description'], ], '#id' => $option['unique_identifier'], '#weight' => $option['weight'], '#parents' => ['group_field_options_wrapper'], '#attributes' => [ 'class' => ['field-option-radio'], 'data-once' => 'field-click-to-select', ], '#wrapper_attributes' => [ 'class' => ['js-click-to-select', 'subfield-option'], ], '#variant' => 'field-suboption', ]; $radio_element['#return_value'] = $option['unique_identifier']; if ((string) $option['unique_identifier'] === 'entity_reference') { $radio_element['#title'] = 'Other'; $radio_element['#weight'] = 10; protected function processFieldDefinitions(FormStateInterface $form_state): void { $field_type_options = $unique_definitions = []; $grouped_definitions = $this->fieldTypePluginManager ->getGroupedDefinitions($this->fieldTypePluginManager->getEntityTypeUiDefinitions($this->entityTypeId), 'label', 'id'); foreach ($grouped_definitions as $category => $field_types) { foreach ($field_types as $name => $field_type) { $definition = ['unique_identifier' => $name] + $field_type; $category_info = $this->fieldTypeCategoryManager ->createInstance($field_type['category'], $definition); $definition['display_as_group'] = !($category_info instanceof FallbackFieldTypeCategory); $id = $this->fieldTypeCategoryManager->hasDefinition($category) ? $category_info->getPluginId() : (string) $field_type['label']; $field_type_options[$id] = $definition; $unique_definitions[$category][$name] = $definition; } $group_field_options[$option['unique_identifier']] = $radio_element; } uasort($group_field_options, [SortArray::class, 'sortByWeightProperty']); $form['group_field_options_wrapper']['fields'] += $group_field_options; $form_state->set('field_type_options', $field_type_options); $form_state->set('unique_definitions', $unique_definitions); } /** Loading @@ -286,18 +214,17 @@ protected function addFieldOptionsForGroup(array &$form, FormStateInterface $for * The current state of the form. */ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_state): void { $field_type_options = $form_state->get('field_type_options'); $field_type_options_radios = []; foreach ($field_type_options as $id => $field_type) { foreach ($form_state->get('field_type_options') as $id => $field_type) { /** @var \Drupal\Core\Field\FieldTypeCategoryInterface $category_info */ $category_info = $this->fieldTypeCategoryManager->createInstance($field_type['category'], $field_type); $category_info = $this->fieldTypeCategoryManager ->createInstance($field_type['category'], $field_type); $display_as_group = $field_type['display_as_group']; $cleaned_class_name = Html::getClass($field_type['unique_identifier']); $field_type_options_radios[$id] = [ '#type' => 'container', '#attributes' => [ 'class' => ['field-option', 'js-click-to-select'], 'checked' => $this->getRequest()->request->get('new_storage_type') !== NULL && $this->getRequest()->request->get('new_storage_type') == ($display_as_group ? $field_type['category'] : $field_type['unique_identifier']), ], '#weight' => $category_info->getWeight(), 'thumb' => [ Loading @@ -308,8 +235,9 @@ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_s 'icon' => [ '#type' => 'container', '#attributes' => [ 'class' => ['field-option__icon', $display_as_group ? "field-icon-$field_type[category]" : "field-icon-$cleaned_class_name", 'class' => [ 'field-option__icon', $display_as_group ? "field-icon-$field_type[category]" : "field-icon-$cleaned_class_name", ], ], ], Loading @@ -321,8 +249,8 @@ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_s '#title_display' => 'before', '#description_display' => 'before', '#theme_wrappers' => ['form_element__new_storage_type'], // If it is a category, set return value as the category label, // otherwise, set it as the field type id. // If it is a category, set return value as the category label. // Otherwise, set it as the field type id. '#return_value' => $display_as_group ? $field_type['category'] : $field_type['unique_identifier'], '#attributes' => [ 'class' => ['field-option-radio'], Loading Loading @@ -358,54 +286,116 @@ protected function addGroupFieldOptions(array &$form, FormStateInterface $form_s ]; $form['add']['new_storage_type'] = $field_type_options_radios; $form['group_submit'] = [ '#type' => 'submit', '#value' => $this->t('Change field group'), '#limit_validation_errors' => [], '#attributes' => [ 'class' => ['js-hide'], ], '#submit' => [[static::class, 'rebuildWithOptions']], ]; $form['actions']['submit']['#validate'][] = '::validateGroupOrField'; $form['actions']['submit']['#submit'][] = '::rebuildWithOptions'; } /** * Save field type definitions and categories in the form state. * * Get all field type definitions and store each one twice: * - field_type_options: each field type is indexed by its category plugin ID * or its label. * - unique_definitions: each field type is indexed by its category and name. * Adds field types for the selected group to the form. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function processFieldDefinitions(FormStateInterface $form_state): void { $field_type_options = $unique_definitions = []; $grouped_definitions = $this->fieldTypePluginManager->getGroupedDefinitions($this->fieldTypePluginManager->getEntityTypeUiDefinitions($this->entityTypeId), 'label', 'id'); // Invoke a hook to get category properties. foreach ($grouped_definitions as $category => $field_types) { foreach ($field_types as $name => $field_type) { $definition = ['unique_identifier' => $name] + $field_type; $category_info = $this->fieldTypeCategoryManager ->createInstance($field_type['category'], $definition); $definition['display_as_group'] = !($category_info instanceof FallbackFieldTypeCategory); if ($this->fieldTypeCategoryManager->hasDefinition($category)) { $id = $category_info->getPluginId(); } else { $id = (string) $field_type['label']; protected function addFieldOptionsForGroup(array &$form, FormStateInterface $form_state): void { // Field label and field_name. $form['new_storage_wrapper'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['field-ui-new-storage-wrapper'], ], ]; $form['new_storage_wrapper']['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#size' => 30, ]; $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); $form['new_storage_wrapper']['field_name'] = [ '#type' => 'machine_name', '#field_prefix' => $field_prefix, '#size' => 15, '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'), // Calculate characters depending on the length of the field prefix // setting. Maximum length is 32. '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix), '#machine_name' => [ 'source' => ['new_storage_wrapper', 'label'], 'exists' => [$this, 'fieldNameExists'], ], '#required' => FALSE, ]; $form['actions']['submit']['#validate'][] = '::validateFieldType'; $form['actions']['back'] = [ '#type' => 'submit', '#value' => $this->t('Back'), '#submit' => ['::startOver'], ]; $field_type_options = $form_state->get('field_type_options'); $new_storage_type = $form_state->getValue('new_storage_type'); $form['new_storage_type'] = [ '#type' => 'value', '#value' => $new_storage_type, ]; if (!isset($new_storage_type) || !$field_type_options[$new_storage_type]['display_as_group']) { return; } $field_type_options[$id] = $definition; $unique_definitions[$category][$name] = $definition; // Create a wrapper for all the field options to be provided. $form['group_field_options_wrapper'] = [ '#prefix' => '<div id="group-field-options-wrapper" class="group-field-options-wrapper">', '#suffix' => '</div>', ]; $form['group_field_options_wrapper']['label'] = [ '#type' => 'label', '#title' => $this->t('Choose an option below'), '#required' => TRUE, ]; $form['group_field_options_wrapper']['fields'] = [ '#type' => 'container', '#attributes' => [ 'class' => ['group-field-options'], ], ]; $unique_definitions = $form_state->get('unique_definitions')[$new_storage_type] ?? []; $group_field_options = []; foreach ($unique_definitions as $option) { $identifier = $option['unique_identifier']; $radio_element = [ '#type' => 'radio', '#theme_wrappers' => ['form_element__new_storage_type'], '#title' => $option['label'], '#description' => [ '#theme' => 'item_list', '#items' => $option['description'], ], '#id' => $identifier, '#weight' => $option['weight'], '#parents' => ['group_field_options_wrapper'], '#attributes' => [ 'class' => ['field-option-radio'], 'data-once' => 'field-click-to-select', ], '#wrapper_attributes' => [ 'class' => ['js-click-to-select', 'subfield-option'], ], '#variant' => 'field-suboption', '#return_value' => $identifier, ]; if ($identifier === 'entity_reference') { $radio_element['#title'] = 'Other'; $radio_element['#weight'] = 10; } $group_field_options[$identifier] = $radio_element; } $form_state->set('field_type_options', $field_type_options); $form_state->set('unique_definitions', $unique_definitions); uasort($group_field_options, [SortArray::class, 'sortByWeightProperty']); $form['group_field_options_wrapper']['fields'] += $group_field_options; } /** Loading @@ -430,7 +420,7 @@ public function validateGroupOrField(array &$form, FormStateInterface $form_stat * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ public function validateAddNew(array $form, FormStateInterface $form_state) { public function validateFieldType(array $form, FormStateInterface $form_state) { // Missing label. if (!$form_state->getValue('label')) { $form_state->setErrorByName('label', $this->t('Add new field: you need to provide a label.')); Loading Loading @@ -466,15 +456,15 @@ public function submitForm(array &$form, FormStateInterface $form_state) { '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) { if (str_starts_with($field_storage_type, 'field_ui:')) { [, $field_type, $preset_key] = explode(':', $field_storage_type, 3); $default_options = $this->getNewFieldDefaults($field_type, $preset_key); } else { $field_type = $field_storage_type; $default_options = []; } $field_values += [ ...$default_options['field_config'] ?? [], Loading @@ -493,7 +483,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ]; try { $field_storage_entity = $this->entityTypeManager->getStorage('field_storage_config')->create($field_storage_values); $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()])); Loading