diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js index 3000cd1..9153b19 100644 --- a/core/modules/field_ui/field_ui.js +++ b/core/modules/field_ui/field_ui.js @@ -9,7 +9,7 @@ Drupal.behaviors.fieldUIFieldOverview = { attach: function (context, settings) { - $(context).find('table#field-overview').once('field-overview', function () { + $(context).find('#field-overview').once('field-overview', function () { Drupal.fieldUIFieldOverview.attachUpdateSelects(this, settings); }); } @@ -32,7 +32,7 @@ // 'Field type' select updates its 'Widget' select. $table.find('.field-type-select').each(function () { var $this = $(this); - this.targetSelect = $this.closest('tr').find('.widget-type-select'); + this.targetSelect = $('.new-field-settings .widget-type-select'); $this.bind('change keyup', function () { var selectedFieldType = this.options[this.selectedIndex].value; @@ -48,7 +48,7 @@ // 'Existing field' select updates its 'Widget' select and 'Label' textfield. $table.find('.field-select').each(function () { var $this = $(this); - var $tr = $this.closest('tr'); + var $tr = $('.existing-field-settings'); this.targetSelect = $tr.find('.widget-type-select'); this.targetTextfield = $tr.find('.label-textfield'); this.targetTextfield diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php index ec602ff..4c1c3a1 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php @@ -11,7 +11,6 @@ use Drupal\Core\Entity\EntityManager; use Drupal\field\Plugin\Type\Widget\WidgetPluginManager; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\field\Plugin\Core\Entity\Field; /** * Field UI field overview form. @@ -59,11 +58,6 @@ public function getRegions() { 'invisible' => TRUE, 'message' => t('No fields are present yet.'), ), - 'hidden' => array( - 'title' => t('Hidden'), - 'invisible' => TRUE, - 'message' => t('No fields.'), - ), ); } @@ -93,9 +87,6 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $extra_fields = field_info_extra_fields($this->entity_type, $this->bundle, 'form'); $entity_form_display = entity_get_form_display($this->entity_type, $this->bundle, $this->mode); - // Field prefix. - $field_prefix = config('field_ui.settings')->get('field_prefix'); - $form += array( '#entity_type' => $this->entity_type, '#bundle' => $this->bundle, @@ -124,6 +115,18 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, ), ); + $form['inline_actions'] = array( + '#prefix' => '', + ); + $form['inline_actions']['add'] = array( + '#theme' => 'menu_local_action', + '#link' => array( + 'href' => 'admin/structure/types/manage/' . $this->bundle . '/add-field', + 'title' => t('Add field'), + ), + ); + // Fields. foreach ($instances as $name => $instance) { $field = field_info_field($instance['field_name']); @@ -245,204 +248,8 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, ); } - // Additional row: add new field. - $max_weight = $entity_form_display->getHighestWeight(); - - // Prepare the widget types to be display as options. - $widget_options = $this->widgetManager->getOptions(); - $widget_type_options = array(); - foreach ($widget_options as $field_type => $widgets) { - $widget_type_options[$field_types[$field_type]['label']] = $widgets; - } - - // Gather valid field types. - $field_type_options = array(); - foreach ($field_types as $name => $field_type) { - // Skip field types which have no widget types, or should not be added via - // user interface. - if (isset($widget_options[$name]) && empty($field_type['no_ui'])) { - $field_type_options[$name] = $field_type['label']; - } - } - asort($field_type_options); - - if ($field_type_options && $widget_type_options) { - $name = '_add_new_field'; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), - '#row_type' => 'add_new_field', - '#region_callback' => array($this, 'getRowRegion'), - 'label' => array( - '#type' => 'textfield', - '#title' => t('New field label'), - '#title_display' => 'invisible', - '#size' => 15, - '#description' => t('Label'), - '#prefix' => '
' . t('Add new field') .'
', - '#suffix' => '
', - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $max_weight + 1, - '#size' => 3, - '#title_display' => 'invisible', - '#title' => t('Weight for new field'), - '#attributes' => array('class' => array('field-weight')), - '#prefix' => '
 
', - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for new field'), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#prefix' => '
 
', - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#type' => 'machine_name', - '#title' => t('New field name'), - '#title_display' => 'invisible', - // This field should stay LTR even for RTL languages. - '#field_prefix' => '' . $field_prefix, - '#field_suffix' => '‎', - '#size' => 15, - '#description' => 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' => Field::ID_MAX_LENGTH - strlen($field_prefix), - '#prefix' => '
 
', - '#machine_name' => array( - 'source' => array('fields', $name, 'label'), - 'exists' => array($this, 'fieldNameExists'), - 'standalone' => TRUE, - 'label' => '', - ), - '#required' => FALSE, - ), - 'type' => array( - '#type' => 'select', - '#title' => t('Type of new field'), - '#title_display' => 'invisible', - '#options' => $field_type_options, - '#empty_option' => t('- Select a field type -'), - '#description' => t('Type of data to store.'), - '#attributes' => array('class' => array('field-type-select')), - '#prefix' => '
 
', - ), - 'widget_type' => array( - '#type' => 'select', - '#title' => t('Widget for new field'), - '#title_display' => 'invisible', - '#options' => $widget_type_options, - '#empty_option' => t('- Select a widget -'), - '#description' => t('Form element to edit the data.'), - '#attributes' => array('class' => array('widget-type-select')), - '#cell_attributes' => array('colspan' => 3), - '#prefix' => '
 
', - ), - // Place the 'translatable' property as an explicit value so that - // contrib modules can form_alter() the value for newly created fields. - 'translatable' => array( - '#type' => 'value', - '#value' => FALSE, - ), - ); - } - - // Additional row: re-use existing field. - $existing_fields = $this->getExistingFieldOptions(); - if ($existing_fields && $widget_type_options) { - // Build list of options. - $existing_field_options = array(); - foreach ($existing_fields as $field_name => $info) { - $text = t('@type: @field (@label)', array( - '@type' => $info['type_label'], - '@label' => $info['label'], - '@field' => $info['field'], - )); - $existing_field_options[$field_name] = truncate_utf8($text, 80, FALSE, TRUE); - } - asort($existing_field_options); - $name = '_add_existing_field'; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), - '#row_type' => 'add_new_field', - '#region_callback' => array($this, 'getRowRegion'), - 'label' => array( - '#type' => 'textfield', - '#title' => t('Existing field label'), - '#title_display' => 'invisible', - '#size' => 15, - '#description' => t('Label'), - '#attributes' => array('class' => array('label-textfield')), - '#prefix' => '
' . t('Re-use existing field') .'
', - '#suffix' => '
', - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $max_weight + 2, - '#size' => 3, - '#title_display' => 'invisible', - '#title' => t('Weight for added field'), - '#attributes' => array('class' => array('field-weight')), - '#prefix' => '
 
', - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for existing field'), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#prefix' => '
 
', - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#type' => 'select', - '#title' => t('Existing field to share'), - '#title_display' => 'invisible', - '#options' => $existing_field_options, - '#empty_option' => t('- Select an existing field -'), - '#description' => t('Field to share'), - '#attributes' => array('class' => array('field-select')), - '#cell_attributes' => array('colspan' => 2), - '#prefix' => '
 
', - ), - 'widget_type' => array( - '#type' => 'select', - '#title' => t('Widget for existing field'), - '#title_display' => 'invisible', - '#options' => $widget_type_options, - '#empty_option' => t('- Select a widget -'), - '#description' => t('Form element to edit the data.'), - '#attributes' => array('class' => array('widget-type-select')), - '#cell_attributes' => array('colspan' => 3), - '#prefix' => '
 
', - ), - ); - } $form['fields'] = $table; - // Add AJAX wrapper. - $form['fields']['#prefix'] = '
'; - $form['fields']['#suffix'] = '
'; - // This key is used to store the current updated field. $form_state += array( 'formatter_settings_edit' => NULL, @@ -453,17 +260,6 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui'); - // Add settings for the update selects behavior. - $js_fields = array(); - foreach ($existing_fields as $field_name => $info) { - $js_fields[$field_name] = array('label' => $info['label'], 'type' => $info['type'], 'widget' => $info['widget_type']); - } - - $form['#attached']['js'][] = array( - 'type' => 'setting', - 'data' => array('fields' => $js_fields, 'fieldWidgetTypes' => $widget_options), - ); - // Add tabledrag behavior. $form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'order', 'sibling', 'field-weight'); $form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name'); @@ -472,110 +268,6 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, } /** - * Implements \Drupal\Core\Form\FormInterface::validateForm(). - */ - public function validateForm(array &$form, array &$form_state) { - $this->validateAddNew($form, $form_state); - $this->validateAddExisting($form, $form_state); - } - - /** - * Validates the 'add new field' row. - * - * @param array $form - * An associative array containing the structure of the form. - * @param array $form_state - * A reference to a keyed array containing the current state of the form. - * - * @see Drupal\field_ui\FieldOverview::validateForm() - */ - protected function validateAddNew(array $form, array &$form_state) { - $field = $form_state['values']['fields']['_add_new_field']; - - // Validate if any information was provided in the 'add new field' row. - if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) { - // Missing label. - if (!$field['label']) { - form_set_error('fields][_add_new_field][label', t('Add new field: you need to provide a label.')); - } - - // Missing field name. - if (!$field['field_name']) { - form_set_error('fields][_add_new_field][field_name', t('Add new field: you need to provide a field name.')); - } - // Field name validation. - else { - $field_name = $field['field_name']; - - // Add the field prefix. - $field_name = config('field_ui.settings')->get('field_prefix') . $field_name; - form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state); - } - - // Missing field type. - if (!$field['type']) { - form_set_error('fields][_add_new_field][type', t('Add new field: you need to select a field type.')); - } - - // Missing widget type. - if (!$field['widget_type']) { - form_set_error('fields][_add_new_field][widget_type', t('Add new field: you need to select a widget.')); - } - // Wrong widget type. - elseif ($field['type']) { - $widget_types = $this->widgetManager->getOptions($field['type']); - if (!isset($widget_types[$field['widget_type']])) { - form_set_error('fields][_add_new_field][widget_type', t('Add new field: invalid widget.')); - } - } - } - } - - /** - * Validates the 're-use existing field' row. - * - * @param array $form - * An associative array containing the structure of the form. - * @param array $form_state - * A reference to a keyed array containing the current state of the form. - * - * @see Drupal\field_ui\FieldOverview::validate() - */ - protected function validateAddExisting(array $form, array &$form_state) { - // The form element might be absent if no existing fields can be added to - // this bundle. - if (isset($form_state['values']['fields']['_add_existing_field'])) { - $field = $form_state['values']['fields']['_add_existing_field']; - - // Validate if any information was provided in the - // 're-use existing field' row. - if (array_filter(array($field['label'], $field['field_name'], $field['widget_type']))) { - // Missing label. - if (!$field['label']) { - form_set_error('fields][_add_existing_field][label', t('Re-use existing field: you need to provide a label.')); - } - - // Missing existing field name. - if (!$field['field_name']) { - form_set_error('fields][_add_existing_field][field_name', t('Re-use existing field: you need to select a field.')); - } - - // Missing widget type. - if (!$field['widget_type']) { - form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: you need to select a widget.')); - } - // Wrong widget type. - elseif ($field['field_name'] && ($existing_field = field_info_field($field['field_name']))) { - $widget_types = $this->widgetManager->getOptions($existing_field['type']); - if (!isset($widget_types[$field['widget_type']])) { - form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: invalid widget.')); - } - } - } - } - } - - /** * Overrides \Drupal\field_ui\OverviewBase::submitForm(). */ public function submitForm(array &$form, array &$form_state) { @@ -599,117 +291,6 @@ public function submitForm(array &$form, array &$form_state) { // Save the form display. $entity_form_display->save(); - - $destinations = array(); - - // Create new field. - if (!empty($form_values['_add_new_field']['field_name'])) { - $values = $form_values['_add_new_field']; - - $field = array( - 'field_name' => $values['field_name'], - 'type' => $values['type'], - 'translatable' => $values['translatable'], - ); - $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => $this->entity_type, - 'bundle' => $this->bundle, - 'label' => $values['label'], - ); - - // Create the field and instance. - try { - $this->entityManager->getStorageController('field_entity')->create($field)->save(); - $new_instance = $this->entityManager->getStorageController('field_instance')->create($instance); - $new_instance->save(); - - // Make sure the field is displayed in the 'default' form mode (using - // the configured widget and default settings). - entity_get_form_display($this->entity_type, $this->bundle, 'default') - ->setComponent($field['field_name'], array( - 'type' => $values['widget_type'], - 'weight' => $values['weight'], - )) - ->save(); - - // Make sure the field is displayed in the 'default' view mode (using - // default formatter and settings). It stays hidden for other view - // modes until it is explicitly configured. - entity_get_display($this->entity_type, $this->bundle, 'default') - ->setComponent($field['field_name']) - ->save(); - - // Always show the field settings step, as the cardinality needs to be - // configured for new fields. - $destinations[] = $this->adminPath. '/fields/' . $new_instance->id() . '/field'; - $destinations[] = $this->adminPath . '/fields/' . $new_instance->id(); - - // Store new field information for any additional submit handlers. - $form_state['fields_added']['_add_new_field'] = $field['field_name']; - } - catch (\Exception $e) { - drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error'); - } - } - - // Re-use existing field. - if (!empty($form_values['_add_existing_field']['field_name'])) { - $values = $form_values['_add_existing_field']; - $field = field_info_field($values['field_name']); - if (!empty($field['locked'])) { - drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error'); - } - else { - $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => $this->entity_type, - 'bundle' => $this->bundle, - 'label' => $values['label'], - ); - - try { - $new_instance = $this->entityManager->getStorageController('field_instance')->create($instance); - $new_instance->save(); - - // Make sure the field is displayed in the 'default' form mode (using - // the configured widget and default settings). - entity_get_form_display($this->entity_type, $this->bundle, 'default') - ->setComponent($field['field_name'], array( - 'type' => $values['widget_type'], - 'weight' => $values['weight'], - )) - ->save(); - - // Make sure the field is displayed in the 'default' view mode (using - // default formatter and settings). It stays hidden for other view - // modes until it is explicitly configured. - entity_get_display($this->entity_type, $this->bundle, 'default') - ->setComponent($field['field_name']) - ->save(); - - $destinations[] = $this->adminPath . '/fields/' . $new_instance->id(); - // Store new field information for any additional submit handlers. - $form_state['fields_added']['_add_existing_field'] = $instance['field_name']; - } - catch (\Exception $e) { - drupal_set_message(t('There was a problem creating field instance %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())), 'error'); - } - } - } - - if ($destinations) { - $destination = drupal_get_destination(); - $destinations[] = $destination['destination']; - unset($_GET['destination']); - $path = array_shift($destinations); - $options = drupal_parse_url($path); - $options['query']['destinations'] = $destinations; - $form_state['redirect'] = array($options['path'], $options); - } - else { - drupal_set_message(t('Your settings have been saved.')); - } } /** @@ -733,64 +314,4 @@ public function getRowRegion($row) { } } - /** - * Returns an array of existing fields to be added to a bundle. - * - * @return array - * An array of existing fields keyed by field name. - */ - protected function getExistingFieldOptions() { - $info = array(); - $field_types = field_info_field_types(); - - foreach (field_info_instances() as $existing_entity_type => $bundles) { - foreach ($bundles as $existing_bundle => $instances) { - // No need to look in the current bundle. - if (!($existing_bundle == $this->bundle && $existing_entity_type == $this->entity_type)) { - foreach ($instances as $instance) { - $field = field_info_field($instance['field_name']); - // Don't show - // - locked fields, - // - fields already in the current bundle, - // - fields that cannot be added to the entity type, - // - fields that should not be added via user interface. - - if (empty($field['locked']) - && !field_info_instance($this->entity_type, $field['field_name'], $this->bundle) - && (empty($field['entity_types']) || in_array($this->entity_type, $field['entity_types'])) - && empty($field_types[$field['type']]['no_ui'])) { - $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']); - $info[$instance['field_name']] = array( - 'type' => $field['type'], - 'type_label' => $field_types[$field['type']]['label'], - 'field' => $field['field_name'], - 'label' => $instance['label'], - 'widget_type' => $widget['type'], - ); - } - } - } - } - } - return $info; - } - - /** - * Checks if a field machine name is taken. - * - * @param string $value - * The machine name, not prefixed with 'field_'. - * - * @return bool - * Whether or not the field machine name is taken. - */ - public function fieldNameExists($value) { - // Prefix with 'field_'. - $field_name = 'field_' . $value; - - // We need to check inactive fields as well, so we can't use - // field_info_fields(). - return (bool) field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); - } - } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php index 6e4a6a2..b97c19a 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php @@ -33,4 +33,70 @@ public static function getNextDestination() { return $next_destination; } + /** + * Returns an array of existing fields to be added to a bundle. + * + * @param string $entity_type + * The entity to search. + * + * @param string $bundle + * The bundle to search for existing fields. + * + * @return array + * An array of existing fields keyed by field name. + */ + public static function getExistingFieldOptions($entity_type, $bundle) { + $info = array(); + $field_types = field_info_field_types(); + + foreach (field_info_instances() as $existing_entity_type => $bundles) { + foreach ($bundles as $existing_bundle => $instances) { + // No need to look in the current bundle. + if (!($existing_bundle == $bundle && $existing_entity_type == $entity_type)) { + foreach ($instances as $instance) { + $field = field_info_field($instance['field_name']); + // Don't show + // - locked fields, + // - fields already in the current bundle, + // - fields that cannot be added to the entity type, + // - fields that should not be added via user interface. + + if (empty($field['locked']) + && !field_info_instance($entity_type, $field['field_name'], $bundle) + && (empty($field['entity_types']) || in_array($entity_type, $field['entity_types'])) + && empty($field_types[$field['type']]['no_ui'])) { + $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']); + $info[$instance['field_name']] = array( + 'type' => $field['type'], + 'type_label' => $field_types[$field['type']]['label'], + 'field' => $field['field_name'], + 'label' => $instance['label'], + 'widget_type' => $widget['type'], + ); + } + } + } + } + } + return $info; + } + + /** + * Checks if a field machine name is taken. + * + * @param string $value + * The machine name, not prefixed with 'field_'. + * + * @return bool + * Whether or not the field machine name is taken. + */ + public static function fieldNameExists($value) { + // Prefix with 'field_'. + $field_name = 'field_' . $value; + + // We need to check inactive fields as well, so we can't use + // field_info_fields(). + return (bool) field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); + } + } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php similarity index 47% copy from core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php copy to core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php index ec602ff..65d4196 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldAddForm.php @@ -2,21 +2,59 @@ /** * @file - * Contains \Drupal\field_ui\FieldOverview. + * Contains \Drupal\field_ui\Form\FieldAddForm. */ -namespace Drupal\field_ui; +namespace Drupal\field_ui\Form; -use Drupal\field_ui\OverviewBase; +use Drupal\Core\Controller\ControllerInterface; use Drupal\Core\Entity\EntityManager; +use Drupal\Core\Form\FormInterface; +use Drupal\field_ui\FieldUI; +use Drupal\field\Plugin\Core\Entity\Field; +use Drupal\field\Plugin\Core\Entity\FieldInstance; use Drupal\field\Plugin\Type\Widget\WidgetPluginManager; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\field\Plugin\Core\Entity\Field; /** - * Field UI field overview form. + * Provides a form for the add field page. */ -class FieldOverview extends OverviewBase { +class FieldAddForm implements FormInterface, ControllerInterface { + + /** + * The field instance being edited. + * + * @var \Drupal\field\Plugin\Core\Entity\FieldInstance + */ + protected $instance; + + /** + * The name of the entity type. + * + * @var string + */ + protected $entity_type = ''; + + /** + * The entity bundle. + * + * @var string + */ + protected $bundle = ''; + + /** + * The entity view or form mode. + * + * @var string + */ + protected $mode = ''; + + /** + * The admin path of the overview page. + * + * @var string + */ + protected $adminPath = NULL; /** * The widget plugin manager. @@ -26,22 +64,26 @@ class FieldOverview extends OverviewBase { protected $widgetManager; /** - * Constructs a new DisplayOverview. + * The entity manager. * - * @param \Drupal\Core\Entity\EntityManager $entity_manager - * The entity manager. - * @param \Drupal\field\Plugin\Type\Widget\WidgetPluginManager $widget_manager - * The widget plugin manager. + * @var \Drupal\Core\Entity\EntityManager */ - public function __construct(EntityManager $entity_manager, WidgetPluginManager $widget_manager) { - parent::__construct($entity_manager); + protected $entityManager; + public function __construct(EntityManager $entity_manager, WidgetPluginManager $widget_manager) { + $this->entityManager = $entity_manager; $this->widgetManager = $widget_manager; } /** * {@inheritdoc} */ + public function getFormID() { + return 'field_ui_field_add_form'; + } + /** + * {@inheritdoc} + */ public static function create(ContainerInterface $container) { return new static( $container->get('plugin.manager.entity'), @@ -50,202 +92,46 @@ public static function create(ContainerInterface $container) { } /** - * Implements Drupal\field_ui\OverviewBase::getRegions(). - */ - public function getRegions() { - return array( - 'content' => array( - 'title' => t('Content'), - 'invisible' => TRUE, - 'message' => t('No fields are present yet.'), - ), - 'hidden' => array( - 'title' => t('Hidden'), - 'invisible' => TRUE, - 'message' => t('No fields.'), - ), - ); - } - - /** - * Implements \Drupal\Core\Form\FormInterface::getFormID(). - */ - public function getFormID() { - return 'field_ui_field_overview_form'; - } - - /** - * Implements \Drupal\Core\Form\FormInterface::buildForm(). + * {@inheritdoc} */ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL, $form_mode = NULL) { - parent::buildForm($form, $form_state, $entity_type, $bundle); - - $this->mode = (isset($form_mode) ? $form_mode : 'default'); - // When displaying the form, make sure the list of fields is up-to-date. - if (empty($form_state['post'])) { - field_info_cache_clear(); + $entity_info = $this->entityManager->getDefinition($entity_type); + if (!empty($entity_info['bundle_prefix'])) { + $bundle = $entity_info['bundle_prefix'] . $bundle; } + $this->entity_type = $entity_type; + $this->bundle = $bundle; + $this->mode = $form_mode; + $this->adminPath = $this->entityManager->getAdminPath($this->entity_type, $this->bundle); + + $form['#attributes'] = array( + 'class' => array('field-ui-overview'), + 'id' => 'field-overview', + ); + // Gather bundle information. - $instances = field_info_instances($this->entity_type, $this->bundle); + $instances = field_info_instances($entity_type, $bundle); $field_types = field_info_field_types(); - $widget_types = field_info_widget_types(); - $extra_fields = field_info_extra_fields($this->entity_type, $this->bundle, 'form'); - $entity_form_display = entity_get_form_display($this->entity_type, $this->bundle, $this->mode); + $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form'); + $entity_form_display = entity_get_form_display($entity_type, $bundle, $form_mode); // Field prefix. $field_prefix = config('field_ui.settings')->get('field_prefix'); - $form += array( + drupal_set_title(t('Add a new field.')); + $form = array( '#entity_type' => $this->entity_type, '#bundle' => $this->bundle, '#fields' => array_keys($instances), '#extra' => array_keys($extra_fields), - ); - - $table = array( - '#type' => 'field_ui_table', - '#pre_render' => array(array($this, 'tablePreRender')), '#tree' => TRUE, - '#header' => array( - t('Label'), - t('Weight'), - t('Parent'), - t('Machine name'), - t('Field type'), - t('Widget'), - t('Operations'), - ), - '#parent_options' => array(), - '#regions' => $this->getRegions(), '#attributes' => array( 'class' => array('field-ui-overview'), 'id' => 'field-overview', ), ); - // Fields. - foreach ($instances as $name => $instance) { - $field = field_info_field($instance['field_name']); - $widget_configuration = $entity_form_display->getComponent($instance['field_name']); - $admin_field_path = $this->adminPath . '/fields/' . $instance->id(); - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), - '#row_type' => 'field', - '#region_callback' => array($this, 'getRowRegion'), - 'label' => array( - '#markup' => check_plain($instance['label']), - ), - 'weight' => array( - '#type' => 'textfield', - '#title' => t('Weight for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#default_value' => $widget_configuration ? $widget_configuration['weight'] : '0', - '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#markup' => $instance['field_name'], - ), - 'type' => array( - '#type' => 'link', - '#title' => $field_types[$field['type']]['label'], - '#href' => $admin_field_path . '/field', - '#options' => array('attributes' => array('title' => t('Edit field settings.'))), - ), - 'widget_type' => array( - '#type' => 'link', - '#title' => $widget_configuration ? $widget_types[$widget_configuration['type']]['label'] : $widget_types['hidden']['label'], - '#href' => $admin_field_path . '/widget-type', - '#options' => array('attributes' => array('title' => t('Change widget type.'))), - ), - ); - - $links = array(); - $links['edit'] = array( - 'title' => t('Edit'), - 'href' => $admin_field_path, - 'attributes' => array('title' => t('Edit instance settings.')), - ); - $links['delete'] = array( - 'title' => t('Delete'), - 'href' => "$admin_field_path/delete", - 'attributes' => array('title' => t('Delete instance.')), - ); - $table[$name]['operations']['data'] = array( - '#type' => 'operations', - '#links' => $links, - ); - - if (!empty($field['locked'])) { - $table[$name]['operations'] = array('#markup' => t('Locked')); - $table[$name]['#attributes']['class'][] = 'menu-disabled'; - } - } - - // Non-field elements. - foreach ($extra_fields as $name => $extra_field) { - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), - '#row_type' => 'extra_field', - '#region_callback' => array($this, 'getRowRegion'), - 'label' => array( - '#markup' => check_plain($extra_field['label']), - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $extra_field['weight'], - '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - '#title_display' => 'invisible', - '#title' => t('Weight for @title', array('@title' => $extra_field['label'])), - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for @title', array('@title' => $extra_field['label'])), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#markup' => $name, - ), - 'type' => array( - '#markup' => isset($extra_field['description']) ? $extra_field['description'] : '', - '#cell_attributes' => array('colspan' => 2), - ), - 'operations' => array( - '#markup' => '', - ), - ); - } - - // Additional row: add new field. $max_weight = $entity_form_display->getHighestWeight(); // Prepare the widget types to be display as options. @@ -266,51 +152,70 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, } asort($field_type_options); + $form['type'] = array( + '#type' => 'select', + '#title' => t('Type of new field'), + '#title_display' => 'invisible', + '#options' => $field_type_options, + '#empty_option' => t('- Select a field type -'), + '#description' => t('Type of data to store.'), + '#attributes' => array('class' => array('field-type-select')), + ); + + // Determine which options from the 'type' field already have existing + // fields and add them to the $states array so we can determine if the + // new-or-existing select list should be displayed. + $existing_fields = FieldUI::getExistingFieldOptions($this->entity_type, $this->bundle); + $states[] = array('value' => FALSE); + foreach ($existing_fields as $field) { + $states[] = array('value' => $field['type']); + } + + $form['new-or-existing'] = array( + '#type' => 'select', + '#title' => t('New or Existing'), + '#options' => array( + t('New'), + t('Existing'), + ), + '#empty_option' => t('- New or Existing -'), + '#states' => array( + 'visible' => array( + 'select[name="type"]' => $states, + ), + ), + ); + if ($field_type_options && $widget_type_options) { + $states[] = array('value' => ''); $name = '_add_new_field'; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), - '#row_type' => 'add_new_field', - '#region_callback' => array($this, 'getRowRegion'), + $form[$name] = array( + '#type' => 'container', + '#attributes' => array('class' => array('new-field-settings')), + // Only show this field if a type has been selected and 'Existing' + // has not explicitly been selected. + '#states' => array( + 'invisible' => array( + 'select[name="type"]' => $states, + 'select[name="new-or-existing"]' => array('!value' => 0), + ), + ), 'label' => array( '#type' => 'textfield', '#title' => t('New field label'), - '#title_display' => 'invisible', '#size' => 15, '#description' => t('Label'), - '#prefix' => '
' . t('Add new field') .'
', - '#suffix' => '
', ), 'weight' => array( '#type' => 'textfield', '#default_value' => $max_weight + 1, '#size' => 3, - '#title_display' => 'invisible', '#title' => t('Weight for new field'), - '#attributes' => array('class' => array('field-weight')), - '#prefix' => '
 
', - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for new field'), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#prefix' => '
 
', - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), + '#attributes' => array('class' => array('field-weight', 'element-invisible')), ), 'field_name' => array( '#type' => 'machine_name', '#title' => t('New field name'), - '#title_display' => 'invisible', // This field should stay LTR even for RTL languages. '#field_prefix' => '' . $field_prefix, '#field_suffix' => '‎', @@ -319,35 +224,23 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, // Calculate characters depending on the length of the field prefix // setting. Maximum length is 32. '#maxlength' => Field::ID_MAX_LENGTH - strlen($field_prefix), - '#prefix' => '
 
', '#machine_name' => array( - 'source' => array('fields', $name, 'label'), - 'exists' => array($this, 'fieldNameExists'), + 'source' => array($name, 'label'), + 'exists' => array(new FieldUI, 'fieldNameExists'), 'standalone' => TRUE, 'label' => '', ), '#required' => FALSE, ), - 'type' => array( - '#type' => 'select', - '#title' => t('Type of new field'), - '#title_display' => 'invisible', - '#options' => $field_type_options, - '#empty_option' => t('- Select a field type -'), - '#description' => t('Type of data to store.'), - '#attributes' => array('class' => array('field-type-select')), - '#prefix' => '
 
', - ), 'widget_type' => array( '#type' => 'select', '#title' => t('Widget for new field'), - '#title_display' => 'invisible', '#options' => $widget_type_options, '#empty_option' => t('- Select a widget -'), '#description' => t('Form element to edit the data.'), '#attributes' => array('class' => array('widget-type-select')), - '#cell_attributes' => array('colspan' => 3), - '#prefix' => '
 
', + '#prefix' => '
', + '#suffix' => '
', ), // Place the 'translatable' property as an explicit value so that // contrib modules can form_alter() the value for newly created fields. @@ -359,7 +252,6 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, } // Additional row: re-use existing field. - $existing_fields = $this->getExistingFieldOptions(); if ($existing_fields && $widget_type_options) { // Build list of options. $existing_field_options = array(); @@ -373,75 +265,47 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, } asort($existing_field_options); $name = '_add_existing_field'; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), - '#row_type' => 'add_new_field', - '#region_callback' => array($this, 'getRowRegion'), - 'label' => array( - '#type' => 'textfield', - '#title' => t('Existing field label'), - '#title_display' => 'invisible', - '#size' => 15, - '#description' => t('Label'), - '#attributes' => array('class' => array('label-textfield')), - '#prefix' => '
' . t('Re-use existing field') .'
', - '#suffix' => '
', - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $max_weight + 2, - '#size' => 3, - '#title_display' => 'invisible', - '#title' => t('Weight for added field'), - '#attributes' => array('class' => array('field-weight')), - '#prefix' => '
 
', - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for existing field'), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#prefix' => '
 
', - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), + $form[$name] = array( + '#type' => 'container', + '#attributes' => array('class' => array('existing-field-settings')), + // Only show this field if 'Existing' has explicitly been selected. + '#states' => array( + 'invisible' => array( + 'select[name="new-or-existing"]' => array('!value' => 1), ), ), 'field_name' => array( '#type' => 'select', '#title' => t('Existing field to share'), - '#title_display' => 'invisible', '#options' => $existing_field_options, '#empty_option' => t('- Select an existing field -'), '#description' => t('Field to share'), '#attributes' => array('class' => array('field-select')), - '#cell_attributes' => array('colspan' => 2), - '#prefix' => '
 
', + ), + 'label' => array( + '#type' => 'textfield', + '#title' => t('Existing field label'), + '#size' => 15, + '#description' => t('Label'), + '#attributes' => array('class' => array('label-textfield')), ), 'widget_type' => array( '#type' => 'select', '#title' => t('Widget for existing field'), - '#title_display' => 'invisible', '#options' => $widget_type_options, '#empty_option' => t('- Select a widget -'), '#description' => t('Form element to edit the data.'), '#attributes' => array('class' => array('widget-type-select')), - '#cell_attributes' => array('colspan' => 3), - '#prefix' => '
 
', + ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $max_weight + 2, + '#size' => 3, + '#title' => t('Weight for added field'), + '#attributes' => array('class' => array('field-weight', 'element-invisible')), ), ); } - $form['fields'] = $table; - - // Add AJAX wrapper. - $form['fields']['#prefix'] = '
'; - $form['fields']['#suffix'] = '
'; // This key is used to store the current updated field. $form_state += array( @@ -449,7 +313,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, ); $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save field settings')); $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui'); @@ -464,15 +328,11 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, 'data' => array('fields' => $js_fields, 'fieldWidgetTypes' => $widget_options), ); - // Add tabledrag behavior. - $form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'order', 'sibling', 'field-weight'); - $form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name'); - return $form; } /** - * Implements \Drupal\Core\Form\FormInterface::validateForm(). + * {@inheritdoc} */ public function validateForm(array &$form, array &$form_state) { $this->validateAddNew($form, $form_state); @@ -480,7 +340,7 @@ public function validateForm(array &$form, array &$form_state) { } /** - * Validates the 'add new field' row. + * Validates the 'add new field' field settings. * * @param array $form * An associative array containing the structure of the form. @@ -490,16 +350,16 @@ public function validateForm(array &$form, array &$form_state) { * @see Drupal\field_ui\FieldOverview::validateForm() */ protected function validateAddNew(array $form, array &$form_state) { - $field = $form_state['values']['fields']['_add_new_field']; + if (!($form_state['values']['new-or-existing'])) { + $field = $form_state['values']['_add_new_field']; + $value = $form_state['values']; - // Validate if any information was provided in the 'add new field' row. - if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) { // Missing label. if (!$field['label']) { - form_set_error('fields][_add_new_field][label', t('Add new field: you need to provide a label.')); + form_set_error('fields][_add_new_field:][label', t('Add new field: you need to provide a label.')); } - // Missing field name. + // Missing field name.jk if (!$field['field_name']) { form_set_error('fields][_add_new_field][field_name', t('Add new field: you need to provide a field name.')); } @@ -507,32 +367,32 @@ protected function validateAddNew(array $form, array &$form_state) { else { $field_name = $field['field_name']; - // Add the field prefix. - $field_name = config('field_ui.settings')->get('field_prefix') . $field_name; - form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state); + // Add the 'field_' prefix. + $field_name = 'field_' . $field_name; + form_set_value($form['_add_new_field']['field_name'], $field_name, $form_state); } // Missing field type. - if (!$field['type']) { - form_set_error('fields][_add_new_field][type', t('Add new field: you need to select a field type.')); + if (!$form_state['values']['type']) { + form_set_error('type', t('Add new field: you need to select a field type.')); } // Missing widget type. if (!$field['widget_type']) { - form_set_error('fields][_add_new_field][widget_type', t('Add new field: you need to select a widget.')); + form_set_error('_add_new_field][widget_type', t('Add new field: you need to select a widget.')); } // Wrong widget type. - elseif ($field['type']) { - $widget_types = $this->widgetManager->getOptions($field['type']); + elseif ($form_state['values']['type']) { + $widget_types = $this->widgetManager->getOptions($form_state['values']['type']); if (!isset($widget_types[$field['widget_type']])) { - form_set_error('fields][_add_new_field][widget_type', t('Add new field: invalid widget.')); + form_set_error('_add_new_field][widget_type', t('Add new field: invalid widget.')); } } } } /** - * Validates the 're-use existing field' row. + * Validates the 're-use existing field' field settings. * * @param array $form * An associative array containing the structure of the form. @@ -544,8 +404,8 @@ protected function validateAddNew(array $form, array &$form_state) { protected function validateAddExisting(array $form, array &$form_state) { // The form element might be absent if no existing fields can be added to // this bundle. - if (isset($form_state['values']['fields']['_add_existing_field'])) { - $field = $form_state['values']['fields']['_add_existing_field']; + if (isset($form_state['values']['_add_existing_field'])) { + $field = $form_state['values']['_add_existing_field']; // Validate if any information was provided in the // 're-use existing field' row. @@ -576,39 +436,24 @@ protected function validateAddExisting(array $form, array &$form_state) { } /** - * Overrides \Drupal\field_ui\OverviewBase::submitForm(). + * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { - $form_values = $form_state['values']['fields']; + $form_values = $form_state['values']; $entity_form_display = entity_get_form_display($this->entity_type, $this->bundle, $this->mode); - // Collect data for 'regular' fields. - foreach ($form['#fields'] as $field_name) { - $options = $entity_form_display->getComponent($field_name); - $options['weight'] = $form_values[$field_name]['weight']; - - $entity_form_display->setComponent($field_name, $options); - } - - // Collect data for 'extra' fields. - foreach ($form['#extra'] as $field_name) { - $entity_form_display->setComponent($field_name, array( - 'weight' => $form_values[$field_name]['weight'], - )); - } - // Save the form display. $entity_form_display->save(); $destinations = array(); // Create new field. - if (!empty($form_values['_add_new_field']['field_name'])) { + if (!empty($form_state['values']['_add_new_field']['field_name'])) { $values = $form_values['_add_new_field']; $field = array( 'field_name' => $values['field_name'], - 'type' => $values['type'], + 'type' => $form_state['values']['type'], 'translatable' => $values['translatable'], ); $instance = array( @@ -712,85 +557,4 @@ public function submitForm(array &$form, array &$form_state) { } } - /** - * Returns the region to which a row in the display overview belongs. - * - * @param array $row - * The row element. - * - * @return string|null - * The region name this row belongs to. - */ - public function getRowRegion($row) { - switch ($row['#row_type']) { - case 'field': - case 'extra_field': - return 'content'; - case 'add_new_field': - // If no input in 'label', assume the row has not been dragged out of the - // 'add new' section. - return (!empty($row['label']['#value']) ? 'content' : 'hidden'); - } - } - - /** - * Returns an array of existing fields to be added to a bundle. - * - * @return array - * An array of existing fields keyed by field name. - */ - protected function getExistingFieldOptions() { - $info = array(); - $field_types = field_info_field_types(); - - foreach (field_info_instances() as $existing_entity_type => $bundles) { - foreach ($bundles as $existing_bundle => $instances) { - // No need to look in the current bundle. - if (!($existing_bundle == $this->bundle && $existing_entity_type == $this->entity_type)) { - foreach ($instances as $instance) { - $field = field_info_field($instance['field_name']); - // Don't show - // - locked fields, - // - fields already in the current bundle, - // - fields that cannot be added to the entity type, - // - fields that should not be added via user interface. - - if (empty($field['locked']) - && !field_info_instance($this->entity_type, $field['field_name'], $this->bundle) - && (empty($field['entity_types']) || in_array($this->entity_type, $field['entity_types'])) - && empty($field_types[$field['type']]['no_ui'])) { - $widget = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($instance['field_name']); - $info[$instance['field_name']] = array( - 'type' => $field['type'], - 'type_label' => $field_types[$field['type']]['label'], - 'field' => $field['field_name'], - 'label' => $instance['label'], - 'widget_type' => $widget['type'], - ); - } - } - } - } - } - return $info; - } - - /** - * Checks if a field machine name is taken. - * - * @param string $value - * The machine name, not prefixed with 'field_'. - * - * @return bool - * Whether or not the field machine name is taken. - */ - public function fieldNameExists($value) { - // Prefix with 'field_'. - $field_name = 'field_' . $value; - - // We need to check inactive fields as well, so we can't use - // field_info_fields(). - return (bool) field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); - } - } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php index 55477a0..82971d9 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php @@ -100,6 +100,13 @@ public function routes(RouteBuildEvent $event) { ); $collection->add("field_ui.display_overview.$entity_type", $route); + $route = new Route( + "$path/add-field", + array('_form' => '\Drupal\field_ui\Form\FieldAddForm') + $defaults, + array('_permission' => 'administer ' . $entity_type . ' fields') + ); + $collection->add("field_ui.add.$entity_type", $route); + foreach (entity_get_view_modes($entity_type) as $view_mode => $view_mode_info) { $route = new Route( "$path/display/$view_mode",