diff --git a/core/lib/Drupal/Core/Render/Element/MachineName.php b/core/lib/Drupal/Core/Render/Element/MachineName.php index 66c85c7..58402d0 100644 --- a/core/lib/Drupal/Core/Render/Element/MachineName.php +++ b/core/lib/Drupal/Core/Render/Element/MachineName.php @@ -170,8 +170,24 @@ public static function processMachineName(&$element, FormStateInterface $form_st $key_exists = NULL; $source = NestedArray::getValue($form_state->getCompleteForm(), $element['#machine_name']['source'], $key_exists); if (!$key_exists) { + // Try to find the source element by looking up the parents of the machine + // name element. + $element_parents = $element['#array_parents']; + + // Remove the element itself from the array. + array_pop($element_parents); + $source_parents = array_merge($element_parents, $element['#machine_name']['source']); + $source = NestedArray::getValue($form_state->getCompleteForm(), $source_parents, $key_exists); + } + + if (!$key_exists) { return $element; } + elseif (isset($source_parents)) { + // The source element was found in the form in a different location than + // initially specified so we need to update it. + $element['#machine_name']['source'] = $source_parents; + } $suffix_id = $source['#id'] . '-machine-name-suffix'; $element['#machine_name']['suffix'] = '#' . $suffix_id; diff --git a/core/modules/field/config/schema/field.schema.yml b/core/modules/field/config/schema/field.schema.yml index 55760a7..26b156c 100644 --- a/core/modules/field/config/schema/field.schema.yml +++ b/core/modules/field/config/schema/field.schema.yml @@ -24,6 +24,9 @@ field.storage.*.*: type: type: string label: 'Type' + label: + type: label + label: 'Label' settings: type: field.storage_settings.[%parent.type] module: diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index 5fff1aa..b07ef69 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -28,13 +28,14 @@ * config_prefix = "storage", * entity_keys = { * "id" = "id", - * "label" = "id" + * "label" = "label" * }, * config_export = { * "id", * "field_name", * "entity_type", * "type", + * "label", * "settings", * "module", * "locked", @@ -95,6 +96,16 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI protected $type; /** + * The human-readable label for the field storage. + * + * This will be used as the default title for new fields using this field + * storage. + * + * @var string + */ + protected $label; + + /** * The name of the module that provides the field type. * * @var string @@ -237,12 +248,12 @@ 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['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."); } @@ -687,7 +698,7 @@ public function isQueryable() { * TRUE if the field has data for any entity; FALSE otherwise. */ public function hasData() { - return \Drupal::entityManager()->getStorage($this->entity_type)->countFieldData($this, TRUE); + return !$this->isNew() && \Drupal::entityManager()->getStorage($this->entity_type)->countFieldData($this, TRUE); } /** diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php index 5f087a6..9ef499a 100644 --- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php @@ -7,13 +7,14 @@ namespace Drupal\field_ui\Form; -use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Entity\EntityFormBuilderInterface; use Drupal\Core\Entity\Query\QueryFactory; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormStateInterface; -use Drupal\field\Entity\FieldStorageConfig; +use Drupal\Core\Render\Element; use Drupal\field\FieldStorageConfigInterface; use Drupal\field_ui\FieldUI; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -59,11 +60,11 @@ class FieldStorageAddForm extends FormBase { public $queryFactory; /** - * The configuration factory. + * The entity form builder. * - * @var \Drupal\Core\Config\ConfigFactoryInterface + * @var \Drupal\Core\Entity\EntityFormBuilderInterface */ - protected $configFactory; + protected $entityFormBuilder; /** * Constructs a new FieldStorageAddForm object. @@ -74,14 +75,14 @@ class FieldStorageAddForm extends FormBase { * The field type plugin manager. * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory * The entity query factory. - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The configuration factory. + * @param \Drupal\Core\Entity\EntityFormBuilderInterface $entity_form_builder + * The entity form builder. */ - public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, QueryFactory $query_factory, ConfigFactoryInterface $config_factory) { + public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, QueryFactory $query_factory, EntityFormBuilderInterface $entity_form_builder) { $this->entityManager = $entity_manager; $this->fieldTypePluginManager = $field_type_plugin_manager; $this->queryFactory = $query_factory; - $this->configFactory = $config_factory; + $this->entityFormBuilder = $entity_form_builder; } /** @@ -99,7 +100,7 @@ public static function create(ContainerInterface $container) { $container->get('entity.manager'), $container->get('plugin.manager.field.field_type'), $container->get('entity.query'), - $container->get('config.factory') + $container->get('entity.form_builder') ); } @@ -135,6 +136,10 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t '#title' => $this->t('Add a new field'), '#options' => $field_type_options, '#empty_option' => $this->t('- Select a field type -'), + '#ajax' => array( + 'callback' => '::buildAjaxFieldStorageConfig', + 'wrapper' => 'new-storage-wrapper', + ), ); // Re-use existing field. @@ -150,7 +155,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t '#empty_option' => $this->t('- Select an existing field -'), ); - $form['#attached']['drupalSettings']['existingFieldLabels'] = $this->getExistingFieldLabels(array_keys($existing_field_storage_options)); + $form['#attached']['drupalSettings']['existingFieldLabels'] = $this->getExistingFieldStorageLabels(array_keys($existing_field_storage_options)); } else { // Provide a placeholder form element to simplify the validation code. @@ -161,37 +166,36 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } // Field label and field_name. - $form['new_storage_wrapper'] = array( + $form['new_storage_wrapper'] = [ '#type' => 'container', - '#states' => array( - '!visible' => array( - ':input[name="new_storage_type"]' => array('value' => ''), - ), - ), - ); - $form['new_storage_wrapper']['label'] = array( - '#type' => 'textfield', - '#title' => $this->t('Label'), - '#size' => 15, - ); + '#attributes' => [ + 'id' => 'new-storage-wrapper', + ], + ]; - $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); - $form['new_storage_wrapper']['field_name'] = array( - '#type' => 'machine_name', - // This field should stay LTR even for RTL languages. - '#field_prefix' => '' . $field_prefix, - '#field_suffix' => '‎', - '#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' => array( - 'source' => array('new_storage_wrapper', 'label'), - 'exists' => array($this, 'fieldNameExists'), - ), - '#required' => FALSE, - ); + 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']; + + $form['new_storage_wrapper'] += $field_storage_form; + } // Provide a separate label element for the "Re-use existing field" case // and place it outside the $form['add'] wrapper because those elements @@ -231,6 +235,13 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } /** + * Handles changes to the selected field storage type. + */ + public function buildAjaxFieldStorageConfig(array $form, FormStateInterface $form_state) { + return $form['new_storage_wrapper']; + } + + /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { @@ -261,24 +272,9 @@ public function validateForm(array &$form, FormStateInterface $form_state) { */ protected function validateAddNew(array $form, FormStateInterface $form_state) { // Validate if any information was provided in the 'add new field' case. - if ($form_state->getValue('new_storage_type')) { - // Missing label. - if (!$form_state->getValue('label')) { - $form_state->setErrorByName('label', $this->t('Add new field: you need to provide a label.')); - } - - // Missing field name. - if (!$form_state->getValue('field_name')) { - $form_state->setErrorByName('field_name', $this->t('Add new field: you need to provide a machine name for the field.')); - } - // Field name validation. - else { - $field_name = $form_state->getValue('field_name'); - - // Add the field prefix. - $field_name = $this->configFactory->get('field_ui.settings')->get('field_prefix') . $field_name; - $form_state->setValueForElement($form['new_storage_wrapper']['field_name'], $field_name); - } + if ($form_state->isRebuilding() && $form_state->getValue('new_storage_type')) { + $form_object = $this->entityManager->getFormObject('field_storage_config', 'edit'); + $form_object->validateForm($form['new_storage_wrapper'], $form_state); } } @@ -312,12 +308,15 @@ 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_values = [ + 'type' => $preconfigured_values['type'], 'field_name' => $values['field_name'], 'entity_type' => $this->entityTypeId, - 'type' => $values['new_storage_type'], 'translatable' => $values['translatable'], - ]; + ] + $preconfigured_values['field_storage']; + $field_values = [ 'field_name' => $values['field_name'], 'entity_type' => $this->entityTypeId, @@ -325,41 +324,21 @@ public function submitForm(array &$form, FormStateInterface $form_state) { 'label' => $values['label'], // Field translatability should be explicitly enabled by the users. 'translatable' => FALSE, - ]; - $widget_id = $formatter_id = NULL; - - // Check if we're dealing with a preconfigured field. - if (strpos($field_storage_values['type'], 'field_ui:') !== FALSE) { - list(, $field_type, $option_key) = explode(':', $field_storage_values['type'], 3); - $field_storage_values['type'] = $field_type; - - $field_type_class = $this->fieldTypePluginManager->getDefinition($field_type)['class']; - $field_options = $field_type_class::getPreconfiguredOptions()[$option_key]; - - // Merge in preconfigured field storage options. - if (isset($field_options['field_storage_config'])) { - foreach (array('cardinality', 'settings') as $key) { - if (isset($field_options['field_storage_config'][$key])) { - $field_storage_values[$key] = $field_options['field_storage_config'][$key]; - } - } - } - - // Merge in preconfigured field options. - if (isset($field_options['field_config'])) { - foreach (array('required', 'settings') as $key) { - if (isset($field_options['field_config'][$key])) { - $field_values[$key] = $field_options['field_config'][$key]; - } - } - } + ] + $preconfigured_values['field']; - $widget_id = isset($field_options['entity_form_display']['type']) ? $field_options['entity_form_display']['type'] : NULL; - $formatter_id = isset($field_options['entity_view_display']['type']) ? $field_options['entity_view_display']['type'] : NULL; - } + $widget_id = $preconfigured_values['widget_id']; + $formatter_id = $preconfigured_values['formatter_id']; // 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); + + $form_object = $this->entityManager->getFormObject('field_storage_config', 'edit'); + $form_object->setEntity($field_storage); + $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(); @@ -372,7 +351,6 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $route_parameters = array( 'field_config' => $field->id(), ) + FieldUI::getRouteBundleParameter($entity_type, $this->bundle); - $destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_storage_edit_form", 'route_parameters' => $route_parameters); $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); @@ -427,6 +405,62 @@ 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. + * + * @return array + * An array with the following structure: + * - type: (string) The field type plugin ID. + * - field_storage: (array) The default properties of a field storage + * config. + * - field: (array) The default properties of a field config. + * - widget_id: (string) The default widget plugin ID. + * - formatter_id: (string) The default formatter plugin ID. + */ + protected function getInitialValues($field_type) { + $initial_values = [ + 'type' => $field_type, + 'field_storage' => [], + 'field' => [], + 'widget_id' => NULL, + 'formatter_id' => NULL, + ]; + + if (strpos($field_type, 'field_ui:') !== FALSE) { + list(, $field_type, $option_key) = explode(':', $field_type, 3); + $initial_values['type'] = $field_type; + + $field_type_class = $this->fieldTypePluginManager->getDefinition($field_type)['class']; + $field_options = $field_type_class::getPreconfiguredOptions()[$option_key]; + + // Add pre-configured field storage options. + 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]; + } + } + } + + // Add pre-configured field options. + 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]; + } + } + } + + $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; + } + + return $initial_values; + } + + /** * Configures the newly created field for the default view and form modes. * * @param string $field_name @@ -497,64 +531,25 @@ protected function getExistingFieldStorageOptions() { /** * Gets the human-readable labels for the given field storage names. * - * Since not all field storages are required to have a field, we can only - * provide the field labels on a best-effort basis (e.g. the label of a field - * storage without any field attached to a bundle will be the field name). - * * @param array $field_names * An array of field names. * * @return array * An array of field labels keyed by field name. */ - protected function getExistingFieldLabels(array $field_names) { - // Get all the fields corresponding to the given field storage names and - // this entity type. - $field_ids = $this->queryFactory->get('field_config') - ->condition('entity_type', $this->entityTypeId) - ->condition('field_name', $field_names) - ->execute(); - $fields = $this->entityManager->getStorage('field_config')->loadMultiple($field_ids); - - // Go through all the fields and use the label of the first encounter. - $labels = array(); - foreach ($fields as $field) { - if (!isset($labels[$field->getName()])) { - $labels[$field->getName()] = $field->label(); - } + protected function getExistingFieldStorageLabels(array $field_names) { + $field_ids = []; + foreach ($field_names as $field_name) { + $field_ids[] = $this->entityTypeId . '.' . $field_name; } + $field_storages = $this->entityManager->getStorage('field_storage_config')->loadMultiple($field_ids); - // For field storages without any fields attached to a bundle, the default - // label is the field name. - $labels += array_combine($field_names, $field_names); - - return $labels; - } - - /** - * Checks if a field machine name is taken. - * - * @param string $value - * The machine name, not prefixed. - * @param array $element - * An array containing the structure of the 'field_name' element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - * - * @return bool - * Whether or not the field machine name is taken. - */ - public function fieldNameExists($value, $element, FormStateInterface $form_state) { - // Don't validate the case when an existing field has been selected. - if ($form_state->getValue('existing_storage_name')) { - return FALSE; + $labels = array(); + foreach ($field_storages as $field_storage) { + $labels[$field_storage->getName()] = $field_storage->label(); } - // Add the field prefix. - $field_name = $this->configFactory->get('field_ui.settings')->get('field_prefix') . $value; - - $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->entityTypeId); - return isset($field_storage_definitions[$field_name]); + return $labels; } } diff --git a/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php b/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php index adafcc7..473bfab 100644 --- a/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php @@ -8,11 +8,16 @@ namespace Drupal\field_ui\Form; use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\field_ui\FieldUI; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Provides a form for the "field storage" edit page. @@ -27,6 +32,32 @@ class FieldStorageConfigEditForm extends EntityForm { protected $entity; /** + * The field type plugin manager. + * + * @var \Drupal\Core\Field\FieldTypePluginManagerInterface + */ + protected $fieldTypePluginManager; + + /** + * Constructs a new FieldStorageConfigEditForm. + * + * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager + * The field type manager. + */ + public function __construct(FieldTypePluginManagerInterface $field_type_manager) { + $this->fieldTypePluginManager = $field_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.field.field_type') + ); + } + + /** * {@inheritdoc} */ public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) { @@ -61,16 +92,50 @@ public function buildForm(array $form, FormStateInterface $form_state, $field_co public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); - $field_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. These settings impact the way that data is stored in the database and cannot be changed once data has been created.', array('%field' => $field_label)) . '

'; + // We cannot use an 'add' entity form operation because this form is also + // used as an AJAX subform of \Drupal\field_ui\Form\FieldStorageAddForm. + if (!$this->entity->isNew()) { + $field_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. These settings impact the way that data is stored in the database and cannot be changed once data has been created.', array('%field' => $field_label)) . '

'; - // See if data already exists for this field. - // If so, prevent changes to the field settings. - if ($this->entity->hasData()) { - $form['#prefix'] = '
' . $this->t('There is data for this field in the database. The field settings can no longer be changed.') . '
' . $form['#prefix']; + // See if data already exists for this field. + // If so, prevent changes to the field settings. + if ($this->entity->hasData()) { + $form['#prefix'] = '
' . $this->t('There is data for this field in the database. The field settings can no longer be changed.') . '
' . $form['#prefix']; + } } + $form['label'] = array( + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#default_value' => $this->entity->label(), + '#size' => 15, + '#required' => TRUE, + '#weight' => -15, + ); + + $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); + $form['field_name'] = array( + '#type' => 'machine_name', + '#default_value' => $this->entity->getName(), + // This field should stay LTR even for RTL languages. + '#field_prefix' => '' . $field_prefix, + '#field_suffix' => '‎', + '#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' => array( + 'source' => array('label'), + 'exists' => array($this, 'fieldNameExists'), + ), + '#required' => TRUE, + '#access' => $this->entity->isNew(), + '#weight' => -14, + ); + // Add settings provided by the field module. The field module is // responsible for not returning settings that cannot be changed if // the field already has data. @@ -86,7 +151,13 @@ public function form(array $form, FormStateInterface $form_state) { 'entity_id' => NULL ); $entity = _field_create_entity_from_ids($ids); - $items = $entity->get($this->entity->getName()); + + // @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()); $item = $items->first() ?: $items->appendItem(); $form['settings'] += $item->storageSettingsForm($form, $form_state, $this->entity->hasData()); @@ -153,6 +224,12 @@ public function validateForm(array &$form, FormStateInterface $form_state) { if ($form_state->getValue('cardinality') === 'number' && !$form_state->getValue('cardinality_number')) { $form_state->setErrorByName('cardinality_number', $this->t('Number of values is required.')); } + + // Add the field prefix. + if (isset($form['field_name'])) { + $field_name = $this->config('field_ui.settings')->get('field_prefix') . $form_state->getValue('field_name'); + $form_state->setValueForElement($form['field_name'], $field_name); + } } /** @@ -189,4 +266,25 @@ public function save(array $form, FormStateInterface $form_state) { } } + /** + * Checks if a field machine name is taken. + * + * @param string $value + * The machine name, not prefixed. + * @param array $element + * An array containing the structure of the 'field_name' element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return bool + * Whether or not the field machine name is taken. + */ + public function fieldNameExists($value, $element, FormStateInterface $form_state) { + // Add the field prefix. + $field_name = $this->config('field_ui.settings')->get('field_prefix') . $value; + + $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($form_state->get('entity_type_id')); + return isset($field_storage_definitions[$field_name]); + } + }