diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index 3f39e75..08d0099 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -97,16 +97,8 @@ function hook_entity_view_mode_info_alter(&$view_modes) { * - admin: An array of information that allows Field UI pages to attach * themselves to the existing administration pages for the bundle. * Elements: - * - path: the path of the bundle's main administration page, as defined - * in hook_menu(). If the path includes a placeholder for the bundle, - * the 'bundle argument', 'bundle helper' and 'real path' keys below - * are required. - * - bundle argument: The position of the placeholder in 'path', if any. * - real path: The actual path (no placeholder) of the bundle's main * administration page. This will be used to generate links. - * - access callback: As in hook_menu(). 'user_access' will be assumed if - * no value is provided. - * - access arguments: As in hook_menu(). * - translatable: (optional) A boolean value specifying whether this bundle * has translation support enabled. Defaults to FALSE. * diff --git a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php index 0487d03..68f6a18 100644 --- a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php +++ b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php @@ -194,6 +194,27 @@ class EntityType extends Plugin { public $bundle_keys; /** + * The base path for the entity type administration page. + * + * If the entity type has a bundle, include {bundle} in the path. + * + * For example, the node entity type specifies + * "admin/structure/types/manage/{bundle}" as its base path. + * + * @var string + */ + public $entity_menu_base_path; + + /** + * The prefix for the bundles for this entity. + * + * For example, the comment bundle is prefixed with 'comment_node_'. + * + * @var string + */ + public $entity_bundle_prefix; + + /** * The base menu router path to which the entity admin user interface responds. * * It can be used to generate UI links and to attach additional router items diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module index 4a1cbcb..9226e68 100644 --- a/core/modules/block/custom_block/custom_block.module +++ b/core/modules/block/custom_block/custom_block.module @@ -189,9 +189,7 @@ function custom_block_entity_bundle_info() { $bundles['custom_block'][$config->get('id')] = array( 'label' => $config->get('label'), 'admin' => array( - 'path' => 'admin/structure/custom-blocks/manage/%', 'real path' => 'admin/structure/custom-blocks/manage/' . $config->get('id'), - 'bundle argument' => 4, ), ); } diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php index 63f5e82..4d67f0a 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php @@ -31,6 +31,7 @@ * }, * base_table = "custom_block", * revision_table = "custom_block_revision", + * entity_menu_base_path = "admin/structure/custom-blocks/manage/{bundle}", * menu_base_path = "block/%custom_block", * fieldable = TRUE, * translatable = TRUE, diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php index eee184a..35f4b98 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php @@ -99,7 +99,7 @@ public function testCustomBlockTypeEditing() { $this->assertEqual(url('block/add/basic', array('absolute' => TRUE)), $this->getUrl(), 'Original machine name was used in URL.'); // Remove the body field. - $this->drupalPost('admin/structure/custom-blocks/manage/basic/fields/block_body/delete', array(), t('Delete')); + $this->drupalPost('admin/structure/custom-blocks/manage/basic/fields/custom_block.basic.block_body/delete', array(), t('Delete')); // Resave the settings for this type. $this->drupalPost('admin/structure/custom-blocks/manage/basic', array(), t('Save')); // Check that the body field doesn't exist. diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 5690c72..8466ce2 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -119,14 +119,6 @@ function comment_entity_bundle_info() { // have to be extracted manually from the bundle name. 'node bundle' => $type, 'admin' => array( - // Place the Field UI paths for comments one level below the - // corresponding paths for nodes, so that they appear in the same set - // of local tasks. Note that the paths use a different placeholder name - // and thus a different menu loader callback, so that Field UI page - // callbacks get a comment bundle name from the node type in the URL. - // See comment_node_type_load() and comment_menu_alter(). - 'path' => 'admin/structure/types/manage/%comment_node_type/comment', - 'bundle argument' => 4, 'real path' => 'admin/structure/types/manage/' . $type . '/comment', ), ); @@ -301,10 +293,10 @@ function comment_menu_alter(&$items) { // Adjust the Field UI tabs on admin/structure/types/manage/[node-type]. // See comment_entity_bundle_info(). - $items['admin/structure/types/manage/%comment_node_type/comment/fields']['title'] = 'Comment fields'; - $items['admin/structure/types/manage/%comment_node_type/comment/fields']['weight'] = 3; - $items['admin/structure/types/manage/%comment_node_type/comment/display']['title'] = 'Comment display'; - $items['admin/structure/types/manage/%comment_node_type/comment/display']['weight'] = 4; + $items['admin/structure/types/manage/%/comment/fields']['title'] = 'Comment fields'; + $items['admin/structure/types/manage/%/comment/fields']['weight'] = 3; + $items['admin/structure/types/manage/%/comment/display']['title'] = 'Comment display'; + $items['admin/structure/types/manage/%/comment/display']['weight'] = 4; } /** diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php index b57c74f..643c081 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php @@ -34,6 +34,8 @@ * fieldable = TRUE, * translatable = TRUE, * static_cache = FALSE, + * entity_menu_base_path = "admin/structure/types/manage/{bundle}/comment", + * entity_bundle_prefix = "comment_node_", * entity_keys = { * "id" = "cid", * "bundle" = "node_type", diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php index a29db8c..c92d2ab 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php @@ -107,7 +107,7 @@ function testCommentFormat() { // Disable text processing for comments. $this->drupalLogin($this->admin_user); $edit = array('instance[settings][text_processing]' => 0); - $this->drupalPost('admin/structure/types/manage/article/comment/fields/comment_body', $edit, t('Save settings')); + $this->drupalPost('admin/structure/types/manage/article/comment/fields/comment.comment_node_article.comment_body', $edit, t('Save settings')); // Post a comment without an explicit subject. $this->drupalLogin($this->web_user); diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module index e134ccc..c3e6fae 100644 --- a/core/modules/contact/contact.module +++ b/core/modules/contact/contact.module @@ -179,9 +179,7 @@ function contact_entity_bundle_info() { $bundles['contact_message'][$config->get('id')] = array( 'label' => $config->get('label'), 'admin' => array( - 'path' => 'admin/structure/contact/manage/%contact_category', 'real path' => 'admin/structure/contact/manage/' . $config->get('id'), - 'bundle argument' => 4, 'access arguments' => array('administer contact forms'), ), ); diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc index 2d7e7ca..510ff0b 100644 --- a/core/modules/field_ui/field_ui.admin.inc +++ b/core/modules/field_ui/field_ui.admin.inc @@ -292,31 +292,6 @@ function theme_field_ui_table($variables) { } /** - * Returns the built and processed 'Manage fields' form of a bundle. - * - * The resulting form allows fields and pseudo-fields to be re-ordered. - * - * @param string $entity_type - * The entity type for the fieldable entity. - * @param string $bundle - * The bundle for the fieldable entity. - * - * @return - * The processed form for the given entity type and bundle. - * - * @see field_ui_menu() - * @see Drupal\field_ui\FieldOverview::validate() - * @see Drupal\field_ui\FieldOverview::submit() - * @ingroup forms - */ -function field_ui_field_overview($entity_type, $bundle) { - $bundle = field_extract_bundle($entity_type, $bundle); - field_ui_inactive_message($entity_type, $bundle); - - return drupal_get_form(new FieldOverview($entity_type, $bundle)); -} - -/** * Render API callback: Checks if a field machine name is taken. * * @param $value @@ -335,33 +310,6 @@ function _field_ui_field_name_exists($value) { } /** - * Returns the built and processed 'Manage display' form of a bundle. - * - * The resulting form allows fields and pseudo-fields to be re-ordered. - * - * @param string $entity_type - * The entity type for the fieldable entity. - * @param string $bundle - * The bundle for the fieldable entity. - * @param string $view_mode - * The view mode for the fieldable entity. - * - * @return - * The processed form for the given entity type and bundle. - * - * @see field_ui_menu() - * @see field_ui_display_overview_multistep_submit() - * @see Drupal\field_ui\DisplayOverview::submit() - * @ingroup forms - */ -function field_ui_display_overview($entity_type, $bundle, $view_mode) { - $bundle = field_extract_bundle($entity_type, $bundle); - field_ui_inactive_message($entity_type, $bundle); - - return drupal_get_form(new DisplayOverview($entity_type, $bundle, $view_mode)); -} - -/** * Returns an array of field_type options. */ function field_ui_field_type_options() { @@ -488,552 +436,6 @@ function field_ui_existing_field_options($entity_type, $bundle) { } /** - * Form constructor for the field settings edit page. - * - * @see field_ui_menu() - * @see field_ui_field_settings_form_submit() - * @ingroup forms - */ -function field_ui_field_settings_form($form, &$form_state, $instance) { - $bundle = $instance['bundle']; - $entity_type = $instance['entity_type']; - $field = field_info_field($instance['field_name']); - $form['#field'] = $field; - $form['#entity_type'] = $entity_type; - $form['#bundle'] = $bundle; - - drupal_set_title($instance['label']); - - $description = '

' . 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' => $instance['label'])) . '

'; - - // Create a form structure for the field values. - $form['field'] = array( - '#prefix' => $description, - '#tree' => TRUE, - ); - - // See if data already exists for this field. - // If so, prevent changes to the field settings. - $has_data = field_has_data($field); - if ($has_data) { - $form['field']['#prefix'] = '
' . t('There is data for this field in the database. The field settings can no longer be changed.') . '
' . $form['field']['#prefix']; - } - - // Build the configurable field values. - $cardinality = $field['cardinality']; - $form['field']['container'] = array( - // We can't use the container element because it doesn't support the title - // or description properties. - '#type' => 'item', - '#field_prefix' => '
', - '#field_suffix' => '
', - '#title' => t('Maximum number of values users can enter'), - ); - $form['field']['container']['cardinality'] = array( - '#type' => 'select', - '#options' => drupal_map_assoc(range(1, 5)) + array(FIELD_CARDINALITY_UNLIMITED => t('Unlimited')) + array('other' => t('More')), - '#default_value' => ($cardinality < 6) ? $cardinality : 'other', - ); - // @todo Convert when http://drupal.org/node/1207060 gets in. - $form['field']['container']['cardinality_other'] = array( - '#type' => 'number', - '#default_value' => $cardinality > 5 ? $cardinality : 6, - '#min' => 1, - '#title' => t('Custom value'), - '#title_display' => 'invisible', - '#states' => array( - 'visible' => array( - ':input[name="field[container][cardinality]"]' => array('value' => 'other'), - ), - ), - ); - if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) { - $form['field']['container']['#description'] = t('%unlimited will provide an %add-more button so users can add as many values as they like.', array( - '%unlimited' => t('Unlimited'), - '%add-more' => t('Add another item'), - )); - } - - // Build the non-configurable field values. - $form['field']['field_name'] = array('#type' => 'value', '#value' => $field['field_name']); - $form['field']['type'] = array('#type' => 'value', '#value' => $field['type']); - $form['field']['module'] = array('#type' => 'value', '#value' => $field['module']); - $form['field']['active'] = array('#type' => 'value', '#value' => $field['active']); - - // 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. - $form['field']['settings'] = array( - '#weight' => 10, - ); - $additions = module_invoke($field['module'], 'field_settings_form', $field, $instance, $has_data); - if (is_array($additions)) { - $form['field']['settings'] += $additions; - } - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save field settings')); - return $form; -} - -/** - * Form validation handler for field_ui_field_edit_form(). - * - * @see field_ui_field_settings_form_submit(). - */ -function field_ui_field_settings_form_validate($form, &$form_state) { - // Validate field cardinality. - $cardinality = $form_state['values']['field']['container']['cardinality']; - $cardinality_other = $form_state['values']['field']['container']['cardinality_other']; - if ($cardinality == 'other' && empty($cardinality_other)) { - form_error($form['field']['container']['cardinality_other'], t('Number of values is required.')); - } -} - -/** - * Form submission handler for field_ui_field_settings_form(). - */ -function field_ui_field_settings_form_submit($form, &$form_state) { - $form_values = $form_state['values']; - $field_values = $form_values['field']; - - // Save field cardinality. - $cardinality = $field_values['container']['cardinality']; - $cardinality_other = $field_values['container']['cardinality_other']; - $cardinality_other = $form_state['values']['field']['container']['cardinality_other']; - if ($cardinality == 'other') { - $cardinality = $cardinality_other; - } - $field_values['cardinality'] = $cardinality; - unset($field_values['container']); - - // Merge incoming form values into the existing field. - $field = field_info_field($field_values['field_name']); - foreach ($field_values as $key => $value) { - $field[$key] = $value; - } - - $entity_type = $form['#entity_type']; - $bundle = $form['#bundle']; - $instance = field_info_instance($entity_type, $field['field_name'], $bundle); - - // Update the field. - try { - field_update_field($field); - drupal_set_message(t('Updated field %label field settings.', array('%label' => $instance['label']))); - $form_state['redirect'] = field_ui_next_destination($entity_type, $bundle); - } - catch (Exception $e) { - drupal_set_message(t('Attempt to update field %label failed: %message.', array('%label' => $instance['label'], '%message' => $e->getMessage())), 'error'); - } -} - -/** - * Form constructor for the widget selection form. - * - * @see field_ui_menu() - * @see field_ui_widget_type_form_submit() - * @ingroup forms - */ -function field_ui_widget_type_form($form, &$form_state, FieldInstance $instance) { - drupal_set_title($instance['label']); - - $bundle = $instance['bundle']; - $entity_type = $instance['entity_type']; - $field_name = $instance['field_name']; - - $field = field_info_field($field_name); - $bundles = entity_get_bundles(); - $bundle_label = $bundles[$entity_type][$bundle]['label']; - - $form = array( - '#bundle' => $bundle, - '#entity_type' => $entity_type, - '#field_name' => $field_name, - ); - - $form['widget_type'] = array( - '#type' => 'select', - '#title' => t('Widget type'), - '#required' => TRUE, - '#options' => field_ui_widget_type_options($field['type']), - '#default_value' => $instance->getWidget()->getPluginId(), - '#description' => t('The type of form element you would like to present to the user when creating this field in the %type type.', array('%type' => $bundle_label)), - ); - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Continue')); - - $form['#validate'] = array(); - $form['#submit'] = array('field_ui_widget_type_form_submit'); - - return $form; -} - -/** - * Form submission handler for field_ui_widget_type_form(). - */ -function field_ui_widget_type_form_submit($form, &$form_state) { - $form_values = $form_state['values']; - $bundle = $form['#bundle']; - $entity_type = $form['#entity_type']; - $field_name = $form['#field_name']; - - // Retrieve the stored instance settings to merge with the incoming values. - $instance = field_read_instance($entity_type, $field_name, $bundle); - - // Set the right module information. - $widget_type = field_info_widget_types($form_values['widget_type']); - $widget_module = $widget_type['module']; - - $instance['widget']['type'] = $form_values['widget_type']; - $instance['widget']['module'] = $widget_module; - - try { - field_update_instance($instance); - drupal_set_message(t('Changed the widget for field %label.', array('%label' => $instance['label']))); - - if ($instance['required'] && empty($instance['default_value']) && empty($instance['default_value_function']) && $instance['widget']['type'] == 'field_hidden') { - drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance['label'])), 'warning'); - } - } - catch (Exception $e) { - drupal_set_message(t('There was a problem changing the widget for field %label.', array('%label' => $instance['label'])), 'error'); - } - - $form_state['redirect'] = field_ui_next_destination($entity_type, $bundle); -} - -/** - * Form constructor for removing a field instance from a bundle. - * - * @see field_ui_menu() - * @see field_ui_field_delete_form_submit() - * @ingroup forms - */ -function field_ui_field_delete_form($form, &$form_state, $instance) { - $bundle = $instance['bundle']; - $entity_type = $instance['entity_type']; - $field = field_info_field($instance['field_name']); - - $admin_path = field_ui_bundle_admin_path($entity_type, $bundle); - - $form['entity_type'] = array('#type' => 'value', '#value' => $entity_type); - $form['bundle'] = array('#type' => 'value', '#value' => $bundle); - $form['field_name'] = array('#type' => 'value', '#value' => $field['field_name']); - - $output = confirm_form($form, - t('Are you sure you want to delete the field %field?', array('%field' => $instance['label'])), - $admin_path . '/fields', - t('If you have any content left in this field, it will be lost. This action cannot be undone.'), - t('Delete'), t('Cancel'), - 'confirm' - ); - - if ($field['locked']) { - unset($output['actions']['submit']); - $output['description']['#markup'] = t('This field is locked and cannot be deleted.'); - } - - return $output; -} - -/** - * Form submission handler for field_ui_field_delete_form(). - * - * Removes a field instance from a bundle. If the field has no more instances, - * it will be marked as deleted too. - */ -function field_ui_field_delete_form_submit($form, &$form_state) { - $form_values = $form_state['values']; - $field_name = $form_values['field_name']; - $bundle = $form_values['bundle']; - $entity_type = $form_values['entity_type']; - - $field = field_info_field($field_name); - $instance = field_info_instance($entity_type, $field_name, $bundle); - $bundles = entity_get_bundles(); - $bundle_label = $bundles[$entity_type][$bundle]['label']; - - if (!empty($bundle) && $field && !$field['locked'] && $form_values['confirm']) { - field_delete_instance($instance); - drupal_set_message(t('The field %field has been deleted from the %type content type.', array('%field' => $instance['label'], '%type' => $bundle_label))); - } - else { - drupal_set_message(t('There was a problem removing the %field from the %type content type.', array('%field' => $instance['label'], '%type' => $bundle_label)), 'error'); - } - - $admin_path = field_ui_bundle_admin_path($entity_type, $bundle); - $form_state['redirect'] = field_ui_get_destinations(array($admin_path . '/fields')); - - // Fields are purged on cron. However field module prevents disabling modules - // when field types they provided are used in a field until it is fully - // purged. In the case that a field has minimal or no content, a single call - // to field_purge_batch() will remove it from the system. Call this with a - // low batch limit to avoid administrators having to wait for cron runs when - // removing instances that meet this criteria. - field_purge_batch(10); -} - -/** - * Form constructor for the field instance settings form. - * - * @see field_ui_menu() - * @see field_ui_field_edit_form_validate() - * @see field_ui_field_edit_form_submit() - * @see field_ui_field_edit_form_delete_submit() - * @ingroup forms - */ -function field_ui_field_edit_form($form, &$form_state, $instance) { - $bundle = $instance['bundle']; - $entity_type = $instance['entity_type']; - $field = field_info_field($instance['field_name']); - $bundles = entity_get_bundles(); - - drupal_set_title(t('%instance settings for %bundle', array( - '%instance' => $instance['label'], - '%bundle' => $bundles[$entity_type][$bundle]['label'], - )), PASS_THROUGH); - - $form['#field'] = $field; - $form['#instance'] = $instance; - // Create an arbitrary entity object (used by the 'default value' widget). - $ids = (object) array('entity_type' => $instance['entity_type'], 'bundle' => $instance['bundle'], 'entity_id' => NULL); - $form['#entity'] = _field_create_entity_from_ids($ids); - $form['#entity']->field_ui_default_value = TRUE; - - if (!empty($field['locked'])) { - $form['locked'] = array( - '#markup' => t('The field %field is locked and cannot be edited.', array('%field' => $instance['label'])), - ); - return $form; - } - - $widget_type = field_info_widget_types($instance['widget']['type']); - - // Create a form structure for the instance values. - $form['instance'] = array( - '#tree' => TRUE, - ); - - // Build the non-configurable instance values. - $form['instance']['field_name'] = array( - '#type' => 'value', - '#value' => $instance['field_name'], - ); - $form['instance']['entity_type'] = array( - '#type' => 'value', - '#value' => $entity_type, - ); - $form['instance']['bundle'] = array( - '#type' => 'value', - '#value' => $bundle, - ); - $form['instance']['widget']['weight'] = array( - '#type' => 'value', - '#value' => !empty($instance['widget']['weight']) ? $instance['widget']['weight'] : 0, - ); - - // Build the configurable instance values. - $form['instance']['label'] = array( - '#type' => 'textfield', - '#title' => t('Label'), - '#default_value' => !empty($instance['label']) ? $instance['label'] : $field['field_name'], - '#required' => TRUE, - '#weight' => -20, - ); - - $form['instance']['description'] = array( - '#type' => 'textarea', - '#title' => t('Help text'), - '#default_value' => !empty($instance['description']) ? $instance['description'] : '', - '#rows' => 5, - '#description' => t('Instructions to present to the user below this field on the editing form.
Allowed HTML tags: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '
' . t('This field supports tokens.'), - '#weight' => -10, - ); - - $form['instance']['required'] = array( - '#type' => 'checkbox', - '#title' => t('Required field'), - '#default_value' => !empty($instance['required']), - '#weight' => -5, - ); - - // Build the widget component of the instance. - $form['instance']['widget']['type'] = array( - '#type' => 'value', - '#value' => $instance['widget']['type'], - ); - - // Add additional field instance settings from the field module. - $additions = module_invoke($field['module'], 'field_instance_settings_form', $field, $instance, $form_state); - if (is_array($additions)) { - $form['instance']['settings'] = $additions; - $form['instance']['settings']['#weight'] = 10; - } - - // Add widget settings for the widget type. - $additions = $instance->getWidget()->settingsForm($form, $form_state); - $form['instance']['widget']['settings'] = $additions ? $additions : array('#type' => 'value', '#value' => array()); - $form['instance']['widget']['#weight'] = 20; - - // Add handling for default value if not provided by any other module. - if (field_behaviors_widget('default_value', $instance) == FIELD_BEHAVIOR_DEFAULT && empty($instance['default_value_function'])) { - $form['instance']['default_value_widget'] = field_ui_default_value_widget($field, $instance, $form, $form_state); - } - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save settings') - ); - $form['actions']['delete'] = array( - '#type' => 'submit', - '#value' => t('Delete field'), - '#submit' => array('field_ui_field_edit_form_delete_submit'), - ); - return $form; -} - -/** - * Form submission handler for 'Delete' button in field_ui_field_edit_form(). - */ -function field_ui_field_edit_form_delete_submit($form, &$form_state) { - $destination = array(); - if (isset($_GET['destination'])) { - $destination = drupal_get_destination(); - unset($_GET['destination']); - } - $instance = $form['#instance']; - $form_state['redirect'] = array('admin/structure/types/manage/' . $instance['bundle'] . '/fields/' . $instance['field_name'] . '/delete', array('query' => $destination)); -} - -/** - * Builds the default value widget for a given field instance. - */ -function field_ui_default_value_widget($field, $instance, &$form, &$form_state) { - $field_name = $field['field_name']; - $entity = $form['#entity']; - - $element = array( - '#type' => 'details', - '#title' => t('Default value'), - '#tree' => TRUE, - '#description' => t('The default value for this field, used when creating new content.'), - // Stick to an empty 'parents' on this form in order not to breaks widgets - // that do not use field_widget_[field|instance]() and still access - // $form_state['field'] directly. - '#parents' => array(), - ); - - // Adjust the instance definition used for the form element. We want a - // non-required input and no description. - $instance['required'] = FALSE; - $instance['description'] = ''; - - // Adjust the instance definition to use the default widget of this field type - // instead of the hidden widget. - if ($instance['widget']['type'] == 'field_hidden') { - $field_type = field_info_field_types($field['type']); - $default_widget = field_info_widget_types($field_type['default_widget']); - - $instance['widget'] = array( - 'type' => $default_widget['id'], - 'settings' => $default_widget['settings'], - 'weight' => 0, - ); - } - - // Insert the widget. Since we do not use the "official" instance definition, - // the whole flow cannot use field_invoke_method(). - $items = array(); - if (!empty($instance['default_value'])) { - $items = (array) $instance['default_value']; - } - $element += $instance->getWidget()->form($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); - - return $element; -} - -/** - * Form validation handler for field_ui_field_edit_form(). - * - * @see field_ui_field_edit_form_submit(). - */ -function field_ui_field_edit_form_validate($form, &$form_state) { - // Take the incoming values as the $instance definition, so that the 'default - // value' gets validated using the instance settings being submitted. - $instance = $form['#instance']; - $field_name = $instance['field_name']; - $entity = $form['#entity']; - - if (isset($form['instance']['default_value_widget'])) { - $element = $form['instance']['default_value_widget']; - - // Extract the 'default value'. - $items = array(); - $instance->getWidget()->extractFormValues($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); - - // Grab the field definition from $form_state. - $field_state = field_form_get_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state); - $field = $field_state['field']; - - // Validate the value. - $errors = array(); - $function = $field['module'] . '_field_validate'; - if (function_exists($function)) { - $function(NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $errors); - } - - // Report errors. - if (isset($errors[$field_name][LANGUAGE_NOT_SPECIFIED])) { - // Store reported errors in $form_state. - $field_state['errors'] = $errors[$field_name][LANGUAGE_NOT_SPECIFIED]; - field_form_set_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state, $field_state); - - // Assign reported errors to the correct form element. - $instance->getWidget()->flagErrors($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); - } - } -} - -/** - * Form submission handler for field_ui_field_edit_form(). - * - * @see field_ui_field_edit_form_validate(). - */ -function field_ui_field_edit_form_submit($form, &$form_state) { - $instance = $form['#instance']; - $field = $form['#field']; - $entity = $form['#entity']; - - // Handle the default value. - if (isset($form['instance']['default_value_widget'])) { - $element = $form['instance']['default_value_widget']; - - // Extract field values. - $items = array(); - $instance->getWidget()->extractFormValues($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); - - $instance['default_value'] = $items ? $items : NULL; - } - - // Merge incoming values into the instance. - foreach ($form_state['values']['instance'] as $key => $value) { - $instance[$key] = $value; - } - field_update_instance($instance); - - drupal_set_message(t('Saved %label configuration.', array('%label' => $instance['label']))); - - if ($instance['required'] && empty($instance['default_value']) && empty($instance['default_value_function']) && $instance['widget']['type'] == 'field_hidden') { - drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance['label'])), 'warning'); - } - - $form_state['redirect'] = field_ui_next_destination($instance['entity_type'], $instance['bundle']); -} - -/** * Extracts next redirect path from an array of multiple destinations. * * @see field_ui_next_destination() diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index a0f29e3..3cd76d4 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -65,128 +65,73 @@ function field_ui_menu() { // Create tabs for all possible bundles. foreach (entity_get_info() as $entity_type => $entity_info) { - if ($entity_info['fieldable']) { - foreach (entity_get_bundles($entity_type) as $bundle_name => $bundle_info) { - if (isset($bundle_info['admin'])) { - // Extract path information from the bundle. - $path = $bundle_info['admin']['path']; - // Different bundles can appear on the same path (e.g. %node_type and - // %comment_node_type). To allow field_ui_instance_load() to extract - // the actual bundle object from the translated menu router path - // arguments, we need to identify the argument position of the bundle - // name string ('bundle argument') and pass that position to the menu - // loader. The position needs to be casted into a string; otherwise it - // would be replaced with the bundle name string. - if (isset($bundle_info['admin']['bundle argument'])) { - $bundle_arg = $bundle_info['admin']['bundle argument']; - $bundle_pos = (string) $bundle_arg; - } - else { - $bundle_arg = $bundle_name; - $bundle_pos = '0'; - } - // This is the position of the %field_ui_instance placeholder in the - // items below. - $field_position = count(explode('/', $path)) + 1; - - // User access check to be done against the permission to edit - // fields or the display per entity type. - $access_fields = array( - 'access callback' => 'user_access', - 'access arguments' => array('administer ' . $entity_type . ' fields'), - ); - $access_display = array( - 'access callback' => 'user_access', - 'access arguments' => array('administer ' . $entity_type . ' display'), - ); + if ($entity_info['fieldable'] && isset($entity_info['entity_menu_base_path'])) { + // Extract path information from the entity type. + $path = $entity_info['entity_menu_base_path']; + $default_path = preg_replace('/{' . DRUPAL_PHP_FUNCTION_PATTERN . '}/', '%', $path); + // This is the position of the %field_ui_instance placeholder in the + // items below. + $field_position = count(explode('/', $path)) + 1; - $items["$path/fields"] = array( - 'title' => 'Manage fields', - 'page callback' => 'field_ui_field_overview', - 'page arguments' => array($entity_type, $bundle_arg), - 'type' => MENU_LOCAL_TASK, - 'weight' => 1, - 'file' => 'field_ui.admin.inc', - ) + $access_fields; - $items["$path/fields/%field_ui_instance"] = array( - 'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'), - 'title callback' => 'field_ui_instance_title', - 'title arguments' => array($field_position), - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_field_edit_form', $field_position), - 'file' => 'field_ui.admin.inc', - ) + $access_fields; - $items["$path/fields/%field_ui_instance/edit"] = array( - 'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'), - 'title' => 'Edit', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_field_edit_form', $field_position), - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'file' => 'field_ui.admin.inc', - ) + $access_fields; - $items["$path/fields/%field_ui_instance/field-settings"] = array( - 'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'), - 'title' => 'Field settings', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_field_settings_form', $field_position), - 'type' => MENU_LOCAL_TASK, - 'file' => 'field_ui.admin.inc', - ) + $access_fields; - $items["$path/fields/%field_ui_instance/widget-type"] = array( - 'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'), - 'title' => 'Widget type', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_widget_type_form', $field_position), - 'type' => MENU_LOCAL_TASK, - 'file' => 'field_ui.admin.inc', - ) + $access_fields; - $items["$path/fields/%field_ui_instance/delete"] = array( - 'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'), - 'title' => 'Delete', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_field_delete_form', $field_position), - 'type' => MENU_VISIBLE_IN_BREADCRUMB, - 'weight' => 10, - 'file' => 'field_ui.admin.inc', - ) + $access_fields; + $items["$path/fields"] = array( + 'title' => 'Manage fields', + 'type' => MENU_LOCAL_TASK, + 'route_name' => "field_ui.overview.$entity_type", + 'weight' => 1, + ); + $items["$path/fields/%"] = array( + 'title callback' => 'field_ui_instance_title', + 'title arguments' => array($field_position), + 'route_name' => "field_ui.instance_edit.$entity_type", + ); + $items["$default_path/fields/%/edit"] = array( + 'title' => 'Edit', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + $items["$path/fields/%/field-settings"] = array( + 'title' => 'Field settings', + 'type' => MENU_LOCAL_TASK, + 'route_name' => "field_ui.settings.$entity_type", + ); + $items["$path/fields/%/widget-type"] = array( + 'title' => 'Widget type', + 'type' => MENU_LOCAL_TASK, + 'route_name' => "field_ui.widget_type.$entity_type", + ); + $items["$path/fields/%/delete"] = array( + 'title' => 'Delete', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + 'route_name' => "field_ui.delete.$entity_type", + 'weight' => 10, + ); - // 'Manage display' tab. - $items["$path/display"] = array( - 'title' => 'Manage display', - 'page callback' => 'field_ui_display_overview', - 'page arguments' => array($entity_type, $bundle_arg, 'default'), - 'type' => MENU_LOCAL_TASK, - 'weight' => 2, - 'file' => 'field_ui.admin.inc', - ) + $access_display; + // 'Manage display' tab. + $items["$path/display"] = array( + 'title' => 'Manage display', + 'type' => MENU_LOCAL_TASK, + 'route_name' => "field_ui.display_overview.$entity_type", + 'weight' => 2, + ); - // View modes secondary tabs. - // The same base $path for the menu item (with a placeholder) can be - // used for all bundles of a given entity type; but depending on - // administrator settings, each bundle has a different set of view - // modes available for customisation. So we define menu items for all - // view modes, and use an access callback to determine which ones are - // actually visible for a given bundle. - $weight = 0; - $view_modes = array('default' => array('label' => t('Default'))) + entity_get_view_modes($entity_type); - foreach ($view_modes as $view_mode => $view_mode_info) { - $items["$path/display/$view_mode"] = array( - 'title' => $view_mode_info['label'], - 'page callback' => 'field_ui_display_overview', - 'page arguments' => array($entity_type, $bundle_arg, $view_mode), - // The access callback needs to check both the current 'custom - // display' setting for the view mode, and the overall access - // rules for the bundle admin pages. - 'access callback' => '_field_ui_view_mode_menu_access', - 'access arguments' => array($entity_type, $bundle_arg, $view_mode, $access_display['access arguments'][0]), - 'type' => ($view_mode == 'default' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK), - 'file' => 'field_ui.admin.inc', - ); - if ($view_mode != 'default') { - $items["$path/display/$view_mode"]['weight'] = $weight++; - } - } - } + // View modes secondary tabs. + // The same base $path for the menu item (with a placeholder) can be + // used for all bundles of a given entity type; but depending on + // administrator settings, each bundle has a different set of view + // modes available for customisation. So we define menu items for all + // view modes, and use an access callback to determine which ones are + // actually visible for a given bundle. + $items["$default_path/display/default"] = array( + 'title' => t('Default'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + $weight = 0; + foreach (entity_get_view_modes($entity_type) as $view_mode => $view_mode_info) { + $items["$path/display/$view_mode"] = array( + 'title' => $view_mode_info['label'], + 'type' => MENU_LOCAL_TASK, + 'weight' => $weight++, + 'route_name' => "field_ui.display_overview.$entity_type.$view_mode", + ); } } } @@ -267,25 +212,8 @@ function field_ui_instance_load($field_name, $entity_type, $bundle_name, $bundle * @see field_ui_menu() */ function field_ui_instance_title($instance) { - return $instance['label']; -} - -/** - * Access callback: Checks access for the 'view mode display settings' pages. - * - * @see field_ui_menu() - */ -function _field_ui_view_mode_menu_access($entity_type, $bundle, $view_mode, $permission) { - // First, determine visibility according to the 'use custom display' - // setting for the view mode. - $bundle = field_extract_bundle($entity_type, $bundle); - $view_mode_settings = field_view_mode_settings($entity_type, $bundle); - $visibility = ($view_mode == 'default') || !empty($view_mode_settings[$view_mode]['custom_settings']); - - // Then, determine access according to the $permission parameter. - if ($visibility) { - return user_access($permission); - } + $entity = entity_load('field_instance', $instance); + return $entity->label(); } /** diff --git a/core/modules/field_ui/field_ui.services.yml b/core/modules/field_ui/field_ui.services.yml new file mode 100644 index 0000000..cfc1214 --- /dev/null +++ b/core/modules/field_ui/field_ui.services.yml @@ -0,0 +1,10 @@ +services: + field_ui.subscriber: + class: Drupal\field_ui\Routing\RouteSubscriber + arguments: ['@plugin.manager.entity'] + tags: + - { name: event_subscriber } + access_check.field_ui.view_mode: + class: Drupal\field_ui\Access\ViewModeAccessCheck + tags: + - { name: access_check } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php b/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php new file mode 100644 index 0000000..640ae84 --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php @@ -0,0 +1,43 @@ +getRequirements()); + } + + /** + * {@inheritdoc} + */ + public function access(Route $route, Request $request) { + if ($entity_type = $request->attributes->get('entity_type')) { + $bundle = $request->attributes->get('bundle'); + $view_mode = $request->attributes->get('view_mode'); + + $view_mode_settings = field_view_mode_settings($entity_type, $bundle); + $visibility = ($view_mode == 'default') || !empty($view_mode_settings[$view_mode]['custom_settings']); + if ($visibility) { + $permission = $route->getRequirement('_field_ui_view_mode_access'); + return user_access($permission); + } + } + } + +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php index 7ee40f4..836cc88 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php @@ -41,7 +41,10 @@ public function getFormID() { /** * Implements \Drupal\Core\Form\FormInterface::buildForm(). */ - public function buildForm(array $form, array &$form_state) { + public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL, $view_mode = NULL) { + parent::buildForm($form, $form_state, $entity_type, $bundle); + + $this->view_mode = (isset($view_mode) ? $view_mode : 'default'); // Gather type information. $instances = field_info_instances($this->entity_type, $this->bundle); $field_types = field_info_field_types(); 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 c17bfb2..5347b20 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php @@ -15,16 +15,6 @@ class FieldOverview extends OverviewBase { /** - * Overrides Drupal\field_ui\OverviewBase::__construct(). - */ - public function __construct($entity_type, $bundle, $view_mode = NULL) { - $this->entity_type = $entity_type; - $this->bundle = $bundle; - $this->view_mode = 'form'; - $this->adminPath = field_ui_bundle_admin_path($this->entity_type, $this->bundle); - } - - /** * Implements Drupal\field_ui\OverviewBase::getRegions(). */ public function getRegions() { @@ -52,7 +42,10 @@ public function getFormID() { /** * Implements \Drupal\Core\Form\FormInterface::buildForm(). */ - public function buildForm(array $form, array &$form_state) { + public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) { + parent::buildForm($form, $form_state, $entity_type, $bundle); + + $this->view_mode = 'form'; // When displaying the form, make sure the list of fields is up-to-date. if (empty($form_state['post'])) { field_info_cache_clear(); @@ -94,7 +87,7 @@ public function buildForm(array $form, array &$form_state) { // Fields. foreach ($instances as $name => $instance) { $field = field_info_field($instance['field_name']); - $admin_field_path = $this->adminPath . '/fields/' . $instance['field_name']; + $admin_field_path = $this->adminPath . '/fields/' . $instance->id(); $table[$name] = array( '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), '#row_type' => 'field', @@ -571,7 +564,7 @@ public function submitForm(array &$form, array &$form_state) { // Create the field and instance. try { field_create_field($field); - field_create_instance($instance); + $new_instance = field_create_instance($instance); // Make sure the field is displayed in the 'default' view mode (using // default formatter and settings). It stays hidden for other view @@ -582,8 +575,8 @@ public function submitForm(array &$form, array &$form_state) { // Always show the field settings step, as the cardinality needs to be // configured for new fields. - $destinations[] = $this->adminPath. '/fields/' . $field['field_name'] . '/field-settings'; - $destinations[] = $this->adminPath . '/fields/' . $field['field_name']; + $destinations[] = $this->adminPath. '/fields/' . $new_instance->id() . '/field-settings'; + $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']; @@ -613,7 +606,7 @@ public function submitForm(array &$form, array &$form_state) { ); try { - field_create_instance($instance); + $new_instance = field_create_instance($instance); // Make sure the field is displayed in the 'default' view mode (using // default formatter and settings). It stays hidden for other view @@ -622,7 +615,7 @@ public function submitForm(array &$form, array &$form_state) { ->setComponent($field['field_name']) ->save(); - $destinations[] = $this->adminPath . '/fields/' . $instance['field_name']; + $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']; } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldDeleteForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldDeleteForm.php new file mode 100644 index 0000000..265142b --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldDeleteForm.php @@ -0,0 +1,92 @@ + $this->instance->label())); + } + + /** + * {@inheritdoc} + */ + protected function getConfirmText() { + return t('Delete'); + } + + /** + * {@inheritdoc} + */ + protected function getCancelPath() { + return field_ui_bundle_admin_path($this->instance->entity_type, $this->instance->bundle) . '/fields'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state, FieldInstance $field_instance = NULL) { + $this->instance = $form_state['instance'] = $field_instance; + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin'); + + $field = $this->instance->getField(); + $bundles = entity_get_bundles(); + $bundle_label = $bundles[$this->instance->entity_type][$this->instance->bundle]['label']; + + if ($field && !$field['locked']) { + field_delete_instance($this->instance); + drupal_set_message(t('The field %field has been deleted from the %type content type.', array('%field' => $this->instance->label(), '%type' => $bundle_label))); + } + else { + drupal_set_message(t('There was a problem removing the %field from the %type content type.', array('%field' => $this->instance->label(), '%type' => $bundle_label)), 'error'); + } + + $admin_path = field_ui_bundle_admin_path($this->instance->entity_type, $this->instance->bundle); + $form_state['redirect'] = field_ui_get_destinations(array($admin_path . '/fields')); + + // Fields are purged on cron. However field module prevents disabling modules + // when field types they provided are used in a field until it is fully + // purged. In the case that a field has minimal or no content, a single call + // to field_purge_batch() will remove it from the system. Call this with a + // low batch limit to avoid administrators having to wait for cron runs when + // removing instances that meet this criteria. + field_purge_batch(10); + } + +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php new file mode 100644 index 0000000..4c12e50 --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php @@ -0,0 +1,280 @@ +instance = $form_state['instance'] = $field_instance; + + $bundle = $this->instance['bundle']; + $entity_type = $this->instance['entity_type']; + $field = field_info_field($this->instance['field_name']); + $bundles = entity_get_bundles(); + + drupal_set_title(t('%instance settings for %bundle', array( + '%instance' => $this->instance->label(), + '%bundle' => $bundles[$entity_type][$bundle]['label'], + )), PASS_THROUGH); + + $form['#field'] = $field; + // Create an arbitrary entity object (used by the 'default value' widget). + $ids = (object) array('entity_type' => $this->instance['entity_type'], 'bundle' => $this->instance['bundle'], 'entity_id' => NULL); + $form['#entity'] = _field_create_entity_from_ids($ids); + $form['#entity']->field_ui_default_value = TRUE; + + if (!empty($field['locked'])) { + $form['locked'] = array( + '#markup' => t('The field %field is locked and cannot be edited.', array('%field' => $this->instance->label())), + ); + return $form; + } + + $widget_type = field_info_widget_types($this->instance['widget']['type']); + + // Create a form structure for the instance values. + $form['instance'] = array( + '#tree' => TRUE, + ); + + // Build the non-configurable instance values. + $form['instance']['field_name'] = array( + '#type' => 'value', + '#value' => $this->instance['field_name'], + ); + $form['instance']['entity_type'] = array( + '#type' => 'value', + '#value' => $entity_type, + ); + $form['instance']['bundle'] = array( + '#type' => 'value', + '#value' => $bundle, + ); + $form['instance']['widget']['weight'] = array( + '#type' => 'value', + '#value' => !empty($this->instance['widget']['weight']) ? $this->instance['widget']['weight'] : 0, + ); + + // Build the configurable instance values. + $form['instance']['label'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#default_value' => $this->instance->label() ?: $field['field_name'], + '#required' => TRUE, + '#weight' => -20, + ); + + $form['instance']['description'] = array( + '#type' => 'textarea', + '#title' => t('Help text'), + '#default_value' => !empty($this->instance['description']) ? $this->instance['description'] : '', + '#rows' => 5, + '#description' => t('Instructions to present to the user below this field on the editing form.
Allowed HTML tags: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '
' . t('This field supports tokens.'), + '#weight' => -10, + ); + + $form['instance']['required'] = array( + '#type' => 'checkbox', + '#title' => t('Required field'), + '#default_value' => !empty($this->instance['required']), + '#weight' => -5, + ); + + // Build the widget component of the instance. + $form['instance']['widget']['type'] = array( + '#type' => 'value', + '#value' => $this->instance['widget']['type'], + ); + + // Add additional field instance settings from the field module. + $additions = module_invoke($field['module'], 'field_instance_settings_form', $field, $this->instance, $form_state); + if (is_array($additions)) { + $form['instance']['settings'] = $additions; + $form['instance']['settings']['#weight'] = 10; + } + + // Add widget settings for the widget type. + $additions = $this->instance->getWidget()->settingsForm($form, $form_state); + $form['instance']['widget']['settings'] = $additions ?: array('#type' => 'value', '#value' => array()); + $form['instance']['widget']['#weight'] = 20; + + // Add handling for default value if not provided by any other module. + if (field_behaviors_widget('default_value', $this->instance) == FIELD_BEHAVIOR_DEFAULT && empty($this->instance['default_value_function'])) { + $form['instance']['default_value_widget'] = $this->getDefaultValueWidget($field, $form, $form_state); + } + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save settings') + ); + $form['actions']['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete field'), + '#submit' => array(array($this, 'delete')), + ); + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + // Take the incoming values as the $this->instance definition, so that the 'default + // value' gets validated using the instance settings being submitted. + $this->instance = $this->instance; + $field_name = $this->instance['field_name']; + $entity = $form['#entity']; + + if (isset($form['instance']['default_value_widget'])) { + $element = $form['instance']['default_value_widget']; + + // Extract the 'default value'. + $items = array(); + $this->instance->getWidget()->extractFormValues($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); + + // Grab the field definition from $form_state. + $field_state = field_form_get_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state); + $field = $field_state['field']; + + // Validate the value. + $errors = array(); + $function = $field['module'] . '_field_validate'; + if (function_exists($function)) { + $function(NULL, $field, $this->instance, LANGUAGE_NOT_SPECIFIED, $items, $errors); + } + + // Report errors. + if (isset($errors[$field_name][LANGUAGE_NOT_SPECIFIED])) { + // Store reported errors in $form_state. + $field_state['errors'] = $errors[$field_name][LANGUAGE_NOT_SPECIFIED]; + field_form_set_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state, $field_state); + + // Assign reported errors to the correct form element. + $this->instance->getWidget()->flagErrors($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); + } + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin'); + $field = $form['#field']; + $entity = $form['#entity']; + + // Handle the default value. + if (isset($form['instance']['default_value_widget'])) { + $element = $form['instance']['default_value_widget']; + + // Extract field values. + $items = array(); + $this->instance->getWidget()->extractFormValues($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); + + $this->instance['default_value'] = $items ? $items : NULL; + } + + // Merge incoming values into the instance. + foreach ($form_state['values']['instance'] as $key => $value) { + $this->instance[$key] = $value; + } + field_update_instance($this->instance); + + drupal_set_message(t('Saved %label configuration.', array('%label' => $this->instance->label()))); + + if ($this->instance['required'] && empty($this->instance['default_value']) && empty($this->instance['default_value_function']) && $this->instance['widget']['type'] == 'field_hidden') { + drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $this->instance['label'])), 'warning'); + } + + $form_state['redirect'] = field_ui_next_destination($this->instance['entity_type'], $this->instance['bundle']); + } + + /** + * Redirects to the field instance deletion form. + */ + public function delete(array &$form, array &$form_state) { + $destination = array(); + if (isset($_GET['destination'])) { + $destination = drupal_get_destination(); + unset($_GET['destination']); + } + $form_state['redirect'] = array('admin/structure/types/manage/' . $this->instance['bundle'] . '/fields/' . $this->instance->id() . '/delete', array('query' => $destination)); + } + + /** + * Builds the default value widget for a given field instance. + */ + protected function getDefaultValueWidget($field, array &$form, &$form_state) { + $field_name = $field['field_name']; + $entity = $form['#entity']; + + $element = array( + '#type' => 'details', + '#title' => t('Default value'), + '#tree' => TRUE, + '#description' => t('The default value for this field, used when creating new content.'), + // Stick to an empty 'parents' on this form in order not to breaks widgets + // that do not use field_widget_[field|instance]() and still access + // $form_state['field'] directly. + '#parents' => array(), + ); + + // Adjust the instance definition used for the form element. We want a + // non-required input and no description. + $this->instance['required'] = FALSE; + $this->instance['description'] = ''; + + // Adjust the instance definition to use the default widget of this field type + // instead of the hidden widget. + if ($this->instance['widget']['type'] == 'field_hidden') { + $field_type = field_info_field_types($field['type']); + $default_widget = field_info_widget_types($field_type['default_widget']); + + $this->instance['widget'] = array( + 'type' => $default_widget['id'], + 'settings' => $default_widget['settings'], + 'weight' => 0, + ); + } + + // Insert the widget. Since we do not use the "official" instance definition, + // the whole flow cannot use field_invoke_method(). + $items = array(); + if (!empty($this->instance['default_value'])) { + $items = (array) $this->instance['default_value']; + } + $element += $this->instance->getWidget()->form($entity, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state); + + return $element; + } + +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldSettingsForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldSettingsForm.php new file mode 100644 index 0000000..7e87f35 --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldSettingsForm.php @@ -0,0 +1,161 @@ +instance = $form_state['instance'] = $field_instance; + $field = $this->instance->getField(); + $form['#field'] = $field; + + drupal_set_title($this->instance->label()); + + $description = '

' . 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' => $this->instance->label())) . '

'; + + // Create a form structure for the field values. + $form['field'] = array( + '#prefix' => $description, + '#tree' => TRUE, + ); + + // See if data already exists for this field. + // If so, prevent changes to the field settings. + $has_data = field_has_data($field); + if ($has_data) { + $form['field']['#prefix'] = '
' . t('There is data for this field in the database. The field settings can no longer be changed.') . '
' . $form['field']['#prefix']; + } + + // Build the configurable field values. + $cardinality = $field['cardinality']; + $form['field']['container'] = array( + // We can't use the container element because it doesn't support the title + // or description properties. + '#type' => 'item', + '#field_prefix' => '
', + '#field_suffix' => '
', + '#title' => t('Maximum number of values users can enter'), + ); + $form['field']['container']['cardinality'] = array( + '#type' => 'select', + '#options' => drupal_map_assoc(range(1, 5)) + array(FIELD_CARDINALITY_UNLIMITED => t('Unlimited')) + array('other' => t('More')), + '#default_value' => ($cardinality < 6) ? $cardinality : 'other', + ); + // @todo Convert when http://drupal.org/node/1207060 gets in. + $form['field']['container']['cardinality_other'] = array( + '#type' => 'number', + '#default_value' => $cardinality > 5 ? $cardinality : 6, + '#min' => 1, + '#title' => t('Custom value'), + '#title_display' => 'invisible', + '#states' => array( + 'visible' => array( + ':input[name="field[container][cardinality]"]' => array('value' => 'other'), + ), + ), + ); + if (field_behaviors_widget('multiple values', $this->instance) == FIELD_BEHAVIOR_DEFAULT) { + $form['field']['container']['#description'] = t('%unlimited will provide an %add-more button so users can add as many values as they like.', array( + '%unlimited' => t('Unlimited'), + '%add-more' => t('Add another item'), + )); + } + + // Build the non-configurable field values. + $form['field']['field_name'] = array('#type' => 'value', '#value' => $field['field_name']); + $form['field']['type'] = array('#type' => 'value', '#value' => $field['type']); + $form['field']['module'] = array('#type' => 'value', '#value' => $field['module']); + $form['field']['active'] = array('#type' => 'value', '#value' => $field['active']); + + // 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. + $form['field']['settings'] = array( + '#weight' => 10, + ); + $additions = module_invoke($field['module'], 'field_settings_form', $field, $this->instance, $has_data); + if (is_array($additions)) { + $form['field']['settings'] += $additions; + } + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save field settings')); + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + // Validate field cardinality. + $cardinality = $form_state['values']['field']['container']['cardinality']; + $cardinality_other = $form_state['values']['field']['container']['cardinality_other']; + if ($cardinality == 'other' && empty($cardinality_other)) { + form_error($form['field']['container']['cardinality_other'], t('Number of values is required.')); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin'); + $form_values = $form_state['values']; + $field_values = $form_values['field']; + + // Save field cardinality. + $cardinality = $field_values['container']['cardinality']; + $cardinality_other = $field_values['container']['cardinality_other']; + $cardinality_other = $form_state['values']['field']['container']['cardinality_other']; + if ($cardinality == 'other') { + $cardinality = $cardinality_other; + } + $field_values['cardinality'] = $cardinality; + unset($field_values['container']); + + // Merge incoming form values into the existing field. + $field = field_info_field($field_values['field_name']); + foreach ($field_values as $key => $value) { + $field[$key] = $value; + } + + // Update the field. + try { + field_update_field($field); + drupal_set_message(t('Updated field %label field settings.', array('%label' => $this->instance->label()))); + $form_state['redirect'] = field_ui_next_destination($this->instance->entity_type, $this->instance->bundle); + } + catch (Exception $e) { + drupal_set_message(t('Attempt to update field %label failed: %message.', array('%label' => $this->instance->label(), '%message' => $e->getMessage())), 'error'); + } + } + +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php new file mode 100644 index 0000000..c461543 --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldWidgetTypeForm.php @@ -0,0 +1,109 @@ +instance = $form_state['instance'] = $field_instance; + form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin'); + drupal_set_title($this->instance['label']); + + $bundle = $this->instance['bundle']; + $entity_type = $this->instance['entity_type']; + $field_name = $this->instance['field_name']; + + $field = field_info_field($field_name); + $bundles = entity_get_bundles(); + $bundle_label = $bundles[$entity_type][$bundle]['label']; + + $form = array( + '#bundle' => $bundle, + '#entity_type' => $entity_type, + '#field_name' => $field_name, + ); + + $form['widget_type'] = array( + '#type' => 'select', + '#title' => t('Widget type'), + '#required' => TRUE, + '#options' => field_ui_widget_type_options($field['type']), + '#default_value' => $this->instance->getWidget()->getPluginId(), + '#description' => t('The type of form element you would like to present to the user when creating this field in the %type type.', array('%type' => $bundle_label)), + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Continue')); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $form_values = $form_state['values']; + $bundle = $form['#bundle']; + $entity_type = $form['#entity_type']; + $field_name = $form['#field_name']; + + // Retrieve the stored instance settings to merge with the incoming values. + $instance = field_read_instance($entity_type, $field_name, $bundle); + + // Set the right module information. + $widget_type = field_info_widget_types($form_values['widget_type']); + $widget_module = $widget_type['module']; + + $instance['widget']['type'] = $form_values['widget_type']; + $instance['widget']['module'] = $widget_module; + + try { + field_update_instance($instance); + drupal_set_message(t('Changed the widget for field %label.', array('%label' => $instance['label']))); + + if ($instance['required'] && empty($instance['default_value']) && empty($instance['default_value_function']) && $instance['widget']['type'] == 'field_hidden') { + drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance['label'])), 'warning'); + } + } + catch (Exception $e) { + drupal_set_message(t('There was a problem changing the widget for field %label.', array('%label' => $instance['label'])), 'error'); + } + + $form_state['redirect'] = field_ui_next_destination($entity_type, $bundle); + } + +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php index 5a76dc1..164570d 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php @@ -7,12 +7,15 @@ namespace Drupal\field_ui; +use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Form\FormInterface; +use Drupal\Core\ControllerInterface; +use Drupal\Core\Entity\EntityManager; /** * Abstract base class for Field UI overview forms. */ -abstract class OverviewBase implements FormInterface { +abstract class OverviewBase implements FormInterface, ControllerInterface { /** * The name of the entity type. @@ -43,20 +46,43 @@ protected $adminPath = NULL; /** - * Constructs the overview object for a entity type, bundle and view mode. + * The entity manager. * - * @param string $entity_type - * The entity type. - * @param string $bundle - * The bundle for the entity of entity_type. - * @param string $view_mode - * (optional) The view mode for the entity which takes a string or - * "default". + * @var \Drupal\Core\Entity\EntityManager */ - public function __construct($entity_type, $bundle, $view_mode = NULL) { + protected $entityManager; + + /** + * Constructs a new OverviewBase. + * + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * The entity manager. + */ + public function __construct(EntityManager $entity_manager) { + $this->entityManager = $entity_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.entity') + ); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) { + $entity_info = $this->entityManager->getDefinition($entity_type); + if (!empty($entity_info['entity_bundle_prefix'])) { + $bundle = $entity_info['entity_bundle_prefix'] . $bundle; + } + + form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin'); $this->entity_type = $entity_type; $this->bundle = $bundle; - $this->view_mode = (isset($view_mode) ? $view_mode : 'default'); $this->adminPath = field_ui_bundle_admin_path($this->entity_type, $this->bundle); } 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 new file mode 100644 index 0000000..617db6d --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php @@ -0,0 +1,116 @@ +manager = $manager; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[RoutingEvents::DYNAMIC] = 'routes'; + return $events; + } + + /** + * Adds routes for the Field UI. + */ + public function routes(RouteBuildEvent $event) { + $collection = $event->getRouteCollection(); + foreach ($this->manager->getDefinitions() as $entity_type => $entity_info) { + if ($entity_info['fieldable'] && isset($entity_info['entity_menu_base_path'])) { + $path = $entity_info['entity_menu_base_path']; + + $route = new Route( + "$path/fields/{field_instance}", + array('_form' => '\Drupal\field_ui\Form\FieldInstanceEditForm'), + array('_permission' => 'administer ' . $entity_type . ' fields') + ); + $collection->add("field_ui.instance_edit.$entity_type", $route); + + $route = new Route( + "$path/fields/{field_instance}/widget-type", + array('_form' => '\Drupal\field_ui\Form\FieldWidgetTypeForm'), + array('_permission' => 'administer ' . $entity_type . ' fields') + ); + $collection->add("field_ui.widget_type.$entity_type", $route); + + $route = new Route( + "$path/fields/{field_instance}/field-settings", + array('_form' => '\Drupal\field_ui\Form\FieldSettingsForm'), + array('_permission' => 'administer ' . $entity_type . ' fields') + ); + $collection->add("field_ui.settings.$entity_type", $route); + + $route = new Route( + "$path/fields/{field_instance}/delete", + array('_form' => '\Drupal\field_ui\Form\FieldDeleteForm'), + array('_permission' => 'administer ' . $entity_type . ' fields') + ); + $collection->add("field_ui.delete.$entity_type", $route); + + // If the entity type has no bundles, use the entity type. + $defaults['entity_type'] = $entity_type; + if (empty($entity_info['entity_keys']['bundle'])) { + $defaults['bundle'] = $entity_type; + } + $route = new Route( + "$path/fields", + array('_form' => '\Drupal\field_ui\FieldOverview') + $defaults, + array('_permission' => 'administer ' . $entity_type . ' fields') + ); + $collection->add("field_ui.overview.$entity_type", $route); + + $route = new Route( + "$path/display", + array('_form' => '\Drupal\field_ui\DisplayOverview') + $defaults, + array('_permission' => 'administer ' . $entity_type . ' display') + ); + $collection->add("field_ui.display_overview.$entity_type", $route); + + foreach (entity_get_view_modes($entity_type) as $view_mode => $view_mode_info) { + $route = new Route( + "$path/display/$view_mode", + array( + '_form' => '\Drupal\field_ui\DisplayOverview', + 'view_mode' => $view_mode, + ) + $defaults, + array('_field_ui_view_mode_access' => 'administer ' . $entity_type . ' display')); + $collection->add("field_ui.display_overview.$entity_type.$view_mode", $route); + } + } + } + } + +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/AlterTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/AlterTest.php index 016b9d0..1c688fb 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/AlterTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/AlterTest.php @@ -68,7 +68,7 @@ function testDefaultWidgetPropertiesAlter() { // Test that field_test_field_widget_properties_alter() sets the size to // 42 and that field_test_field_widget_form_alter() reports the correct // size when the form is displayed. - $this->drupalGet('admin/structure/types/manage/article/fields/alter_test_text'); + $this->drupalGet('admin/structure/types/manage/article/fields/node.article.alter_test_text'); $this->assertText('Field size: 42', 'Altered field size is found in hook_field_widget_form_alter().'); // Test that hook_field_widget_form_alter() registers this is the default // value form and sets a message. @@ -102,11 +102,11 @@ function testDefaultWidgetPropertiesAlter() { // Test that field_test_field_widget_properties_user_alter() replaces // the widget and that field_test_field_widget_form_alter() reports the // correct widget name when the form is displayed. - $this->drupalGet('admin/config/people/accounts/fields/alter_test_options'); + $this->drupalGet('admin/config/people/accounts/fields/user.user.alter_test_options'); $this->assertText('Widget type: options_buttons', 'Widget type is altered for users in hook_field_widget_form_alter().'); // Test that the widget is not altered on page nodes. - $this->drupalGet('admin/structure/types/manage/page/fields/alter_test_options'); + $this->drupalGet('admin/structure/types/manage/page/fields/node.page.alter_test_options'); $this->assertText('Widget type: options_select', 'Widget type is not altered for pages in hook_field_widget_form_alter().'); } } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php index cbc132f..3fcabf2 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php @@ -123,8 +123,9 @@ function createField() { * Tests editing an existing field. */ function updateField() { + $instance_id = 'node.' . $this->type . '.' . $this->field_name; // Go to the field edit page. - $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields/' . $this->field_name . '/field-settings'); + $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields/' . $instance_id . '/field-settings'); // Populate the field settings with new settings. $string = 'updated dummy test string'; @@ -134,7 +135,7 @@ function updateField() { $this->drupalPost(NULL, $edit, t('Save field settings')); // Go to the field instance edit page. - $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields/' . $this->field_name); + $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields/' . $instance_id); $edit = array( 'instance[settings][test_instance_setting]' => $string, 'instance[widget][settings][test_widget_setting]' => $string, @@ -176,7 +177,7 @@ function addExistingField() { * numeric value. That is tested already in FormTest::testNumber(). */ function cardinalitySettings() { - $field_edit_path = 'admin/structure/types/manage/article/fields/body/field-settings'; + $field_edit_path = 'admin/structure/types/manage/article/fields/node.article.body/field-settings'; // Assert the cardinality other field cannot be empty when cardinality is // set to other. @@ -253,10 +254,10 @@ function testDefaultValue() { 'entity_type' => 'node', 'bundle' => $this->type, ); - field_create_instance($instance); + $instance = field_create_instance($instance); $langcode = LANGUAGE_NOT_SPECIFIED; - $admin_path = 'admin/structure/types/manage/' . $this->type . '/fields/' . $field_name; + $admin_path = 'admin/structure/types/manage/' . $this->type . '/fields/' . $instance->id(); $element_id = "edit-$field_name-$langcode-0-value"; $element_name = "{$field_name}[$langcode][0][value]"; $this->drupalGet($admin_path); @@ -320,7 +321,7 @@ function testDeleteField() { $this->fieldUIAddExistingField($bundle_path2, $edit2); // Delete the first instance. - $this->fieldUIDeleteField($bundle_path1, $this->field_name, $this->field_label, $this->type); + $this->fieldUIDeleteField($bundle_path1, "node.$this->type.$this->field_name", $this->field_label, $this->type); // Reset the fields info. field_info_cache_clear(); @@ -330,7 +331,7 @@ function testDeleteField() { $this->assertNotNull(field_info_field($this->field_name), 'Field was not deleted.'); // Delete the second instance. - $this->fieldUIDeleteField($bundle_path2, $this->field_name, $this->field_label, $type_name2); + $this->fieldUIDeleteField($bundle_path2, "node.$type_name2.$this->field_name", $this->field_label, $type_name2); // Reset the fields info. field_info_cache_clear(); @@ -412,7 +413,7 @@ function testDuplicateFieldName() { */ function testWidgetChange() { $url_fields = 'admin/structure/types/manage/article/fields'; - $url_tags_widget = $url_fields . '/field_tags/widget-type'; + $url_tags_widget = $url_fields . '/node.article.field_tags/widget-type'; // Check that the field_tags field currently uses the 'options_select' // widget. @@ -463,7 +464,7 @@ function testDeleteTaxonomyField() { $this->fieldUIAddNewField($bundle_path, $edit1); // Delete the field. - $this->fieldUIDeleteField($bundle_path, $this->field_name, $this->field_label, 'Tags'); + $this->fieldUIDeleteField($bundle_path, "taxonomy_term.tags.$this->field_name", $this->field_label, 'Tags'); // Reset the fields info. field_info_cache_clear(); diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php index 041e166..8268999 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php @@ -205,12 +205,13 @@ function testPrivateFileSetting() { $type_name = 'article'; $field_name = strtolower($this->randomName()); $this->createFileField($field_name, $type_name); + $instance = field_info_instance('node', $field_name, $type_name); $test_file = $this->getTestFile('text'); // Change the field setting to make its files private, and upload a file. $edit = array('field[settings][uri_scheme]' => 'private'); - $this->drupalPost("admin/structure/types/manage/$type_name/fields/$field_name/field-settings", $edit, t('Save field settings')); + $this->drupalPost("admin/structure/types/manage/$type_name/fields/$instance->id/field-settings", $edit, t('Save field settings')); $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); $node = node_load($nid, TRUE); $node_file = file_load($node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['fid']); @@ -222,12 +223,12 @@ function testPrivateFileSetting() { // Ensure we can't change 'uri_scheme' field settings while there are some // entities with uploaded files. - $this->drupalGet("admin/structure/types/manage/$type_name/fields/$field_name/field-settings"); + $this->drupalGet("admin/structure/types/manage/$type_name/fields/$instance->id/field-settings"); $this->assertFieldByXpath('//input[@id="edit-field-settings-uri-scheme-public" and @disabled="disabled"]', 'public', t('Upload destination setting disabled.')); // Delete node and confirm that setting could be changed. node_delete($nid); - $this->drupalGet("admin/structure/types/manage/$type_name/fields/$field_name/field-settings"); + $this->drupalGet("admin/structure/types/manage/$type_name/fields/$instance->id/field-settings"); $this->assertFieldByXpath('//input[@id="edit-field-settings-uri-scheme-public" and not(@disabled)]', 'public', t('Upload destination setting enabled.')); } diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php index a30b7ed..c8570c1 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php @@ -74,7 +74,7 @@ function testDefaultImages() { ->save(); // Confirm the defaults are present on the article field settings form. - $this->drupalGet("admin/structure/types/manage/article/fields/$field_name/field-settings"); + $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id/field-settings"); $this->assertFieldByXpath( '//input[@name="field[settings][default_image][fids]"]', $default_images['field']->fid, @@ -84,7 +84,7 @@ function testDefaultImages() { ) ); // Confirm the defaults are present on the article field edit form. - $this->drupalGet("admin/structure/types/manage/article/fields/$field_name"); + $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id"); $this->assertFieldByXpath( '//input[@name="instance[settings][default_image][fids]"]', $default_images['instance']->fid, @@ -95,7 +95,7 @@ function testDefaultImages() { ); // Confirm the defaults are present on the page field settings form. - $this->drupalGet("admin/structure/types/manage/page/fields/$field_name/field-settings"); + $this->drupalGet("admin/structure/types/manage/page/fields/$instance->id/field-settings"); $this->assertFieldByXpath( '//input[@name="field[settings][default_image][fids]"]', $default_images['field']->fid, @@ -105,7 +105,7 @@ function testDefaultImages() { ) ); // Confirm the defaults are present on the page field edit form. - $this->drupalGet("admin/structure/types/manage/page/fields/$field_name"); + $this->drupalGet("admin/structure/types/manage/page/fields/$instance2->id"); $this->assertFieldByXpath( '//input[@name="instance[settings][default_image][fids]"]', $default_images['instance2']->fid, @@ -144,7 +144,7 @@ function testDefaultImages() { field_update_field($field); // Confirm that the new default is used on the article field settings form. - $this->drupalGet("admin/structure/types/manage/article/fields/$field_name/field-settings"); + $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id/field-settings"); $this->assertFieldByXpath( '//input[@name="field[settings][default_image][fids]"]', $default_images['field_new']->fid, @@ -180,7 +180,7 @@ function testDefaultImages() { // Confirm the new field instance default is used on the article field // admin form. - $this->drupalGet("admin/structure/types/manage/article/fields/$field_name"); + $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id"); $this->assertFieldByXpath( '//input[@name="instance[settings][default_image][fids]"]', $default_images['instance_new']->fid, @@ -218,7 +218,7 @@ function testDefaultImages() { field_update_instance($instance); // Confirm the article field instance default has been removed. - $this->drupalGet("admin/structure/types/manage/article/fields/$field_name"); + $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id"); $this->assertFieldByXpath( '//input[@name="instance[settings][default_image][fids]"]', '', diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php index ad92165..5342547 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php @@ -226,7 +226,7 @@ function testImageFieldDefaultImage() { $edit = array( 'files[field_settings_default_image]' => drupal_realpath($images[0]->uri), ); - $this->drupalPost("admin/structure/types/manage/article/fields/$field_name/field-settings", $edit, t('Save field settings')); + $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field-settings", $edit, t('Save field settings')); // Clear field info cache so the new default image is detected. field_info_cache_clear(); $field = field_info_field($field_name); @@ -254,7 +254,7 @@ function testImageFieldDefaultImage() { $edit = array( 'field[settings][default_image][fids]' => 0, ); - $this->drupalPost("admin/structure/types/manage/article/fields/$field_name/field-settings", $edit, t('Save field settings')); + $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field-settings", $edit, t('Save field settings')); // Clear field info cache so the new default image is detected. field_info_cache_clear(); $field = field_info_field($field_name); @@ -267,7 +267,7 @@ function testImageFieldDefaultImage() { $edit = array( 'files[field_settings_default_image]' => drupal_realpath($images[1]->uri), ); - $this->drupalPost('admin/structure/types/manage/article/fields/' . $private_field_name . '/field-settings', $edit, t('Save field settings')); + $this->drupalPost('admin/structure/types/manage/article/fields/node.article.' . $private_field_name . '/field-settings', $edit, t('Save field settings')); // Clear field info cache so the new default image is detected. field_info_cache_clear(); diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php index de04d97..8b58ad7 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php @@ -81,7 +81,10 @@ protected function attachLoad(&$menu_links, $load_revision = FALSE) { if ($routes) { $route_objects = drupal_container()->get('router.route_provider')->getRoutesByNames($routes); foreach ($routes as $entity_id => $route) { - $menu_links[$entity_id]->setRouteObject($route_objects[$route]); + // Not all stored routes will be valid on loaded. + if (isset($route_objects[$route])) { + $menu_links[$entity_id]->setRouteObject($route_objects[$route]); + } } } diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php index 99c6b88..c2a718b 100644 --- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php +++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php @@ -44,6 +44,7 @@ * bundle_keys = { * "bundle" = "type" * }, + * entity_menu_base_path = "admin/structure/types/manage/{bundle}", * permission_granularity = "bundle" * ) */ diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php index 0db0bda..452ed93 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php @@ -75,7 +75,7 @@ function testNodeAccessAdministerField() { $default = 'Sometimes words have two meanings'; $edit["{$this->field_name}[$langcode][0][value]"] = $default; $this->drupalPost( - "admin/structure/types/manage/page/fields/{$this->field_name}", + "admin/structure/types/manage/page/fields/node.page.{$this->field_name}", $edit, t('Save settings') ); diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php index 64fa105..6a5b5f6 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php @@ -121,7 +121,7 @@ function testNodeTypeEditing() { $this->assertRaw('Body', 'Body field was found.'); // Remove the body field. - $this->drupalPost('admin/structure/types/manage/bar/fields/body/delete', array(), t('Delete')); + $this->drupalPost('admin/structure/types/manage/bar/fields/node.bar.body/delete', array(), t('Delete')); // Resave the settings for this type. $this->drupalPost('admin/structure/types/manage/bar', array(), t('Save content type')); // Check that the body field doesn't exist. diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 8f9f17f..9490319 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -219,9 +219,7 @@ function node_entity_bundle_info() { $bundles['node'][$type] = array( 'label' => $name, 'admin' => array( - 'path' => 'admin/structure/types/manage/%node_type', 'real path' => 'admin/structure/types/manage/' . $type, - 'bundle argument' => 4, ), ); } diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php index 11f6035..c69c414 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php @@ -266,7 +266,7 @@ protected function createOptionsField($type) { ); field_create_instance($instance); - $this->admin_path = 'admin/structure/types/manage/' . $this->type . '/fields/' . $this->field_name . '/field-settings'; + $this->admin_path = 'admin/structure/types/manage/' . $this->type . '/fields/node.' . $this->type . '.' . $this->field_name . '/field-settings'; } /** diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php index 78efa3e..4dfd302 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php @@ -495,7 +495,7 @@ function testOnOffCheckbox() { field_create_instance($instance); // Go to the edit page and check if the default settings works as expected - $fieldEditUrl = 'admin/structure/types/manage/page/fields/bool'; + $fieldEditUrl = 'admin/structure/types/manage/page/fields/node.page.bool'; $this->drupalGet($fieldEditUrl); $this->assertText( diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php index 07c38ae..676d1ac 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php @@ -146,11 +146,11 @@ function testBreadCrumbs() { $trail += array( "admin/structure/types/manage/$type/fields" => t('Manage fields'), ); - $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body", $trail); + $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/node.$type.body", $trail); $trail += array( - "admin/structure/types/manage/$type/fields/body" => t('Body'), + "admin/structure/types/manage/$type/fields/node.$type.body" => t('Body'), ); - $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body/widget-type", $trail); + $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/node.$type.body/widget-type", $trail); // Verify Filter text format administration breadcrumbs. $filter_formats = filter_formats(); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php index 60811db..05ee65c 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php @@ -43,6 +43,7 @@ * "bundle" = "vid" * }, * menu_base_path = "taxonomy/term/%taxonomy_term", + * entity_menu_base_path = "admin/structure/taxonomy/{bundle}", * permission_granularity = "bundle" * ) */ diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 89f334b..76a5896 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -128,9 +128,7 @@ function taxonomy_entity_bundle_info() { $bundles['taxonomy_term'][$id] = array( 'label' => $config->get('name'), 'admin' => array( - 'path' => 'admin/structure/taxonomy/%taxonomy_vocabulary', 'real path' => 'admin/structure/taxonomy/' . $id, - 'bundle argument' => 3, ), ); } diff --git a/core/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php b/core/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php index 9aff558..b8b5656 100644 --- a/core/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php +++ b/core/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php @@ -63,7 +63,7 @@ function setUp() { function testTextField() { // Disable text processing for body. $edit = array('instance[settings][text_processing]' => 0); - $this->drupalPost('admin/structure/types/manage/article/fields/body', $edit, t('Save settings')); + $this->drupalPost('admin/structure/types/manage/article/fields/node.article.body', $edit, t('Save settings')); // Login as translator. $this->drupalLogin($this->translator); @@ -92,7 +92,7 @@ function testTextField() { function testTextFieldFormatted() { // Make node body multiple. $edit = array('field[container][cardinality]' => -1); - $this->drupalPost('admin/structure/types/manage/article/fields/body/field-settings', $edit, t('Save field settings')); + $this->drupalPost('admin/structure/types/manage/article/fields/node.article.body/field-settings', $edit, t('Save field settings')); $this->drupalGet('node/add/article'); $this->assertFieldByXPath("//input[@name='body_add_more']", t('Add another item'), 'Body field cardinality set to multiple.'); diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php index 829babc..845134d 100644 --- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php +++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php @@ -31,6 +31,7 @@ * default_operation = "profile", * base_table = "users", * uri_callback = "user_uri", + * entity_menu_base_path = "admin/config/people/accounts", * label_callback = "user_label", * fieldable = TRUE, * translatable = TRUE, diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 09e745a..d664899 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -2533,7 +2533,7 @@ function user_block_user_action(&$entity, $context = array()) { * field instance' form. */ function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) { - $instance = $form['#instance']; + $instance = $form_state['instance']; if ($instance['entity_type'] == 'user') { $form['instance']['settings']['user_register_form'] = array(