Commit 6ed57d39 authored by alexpott's avatar alexpott

Issue #1946404 by tim.plunkett, amateescu, swentel: Convert forms in...

Issue #1946404 by tim.plunkett, amateescu, swentel: Convert forms in field_ui().admin.inc to the new form interface.
parent 47308d21
......@@ -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.
*
......
......@@ -193,6 +193,27 @@ class EntityType extends Plugin {
*/
public $bundle_keys;
/**
* The base router path for the entity type's field 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 field admin path.
*
* @var string (optional)
*/
public $route_base_path;
/**
* The prefix for the bundles of this entity type.
*
* For example, the comment bundle is prefixed with 'comment_node_'.
*
* @var string (optional)
*/
public $bundle_prefix;
/**
* The base menu router path to which the entity admin user interface responds.
*
......
......@@ -187,9 +187,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,
),
);
}
......
......@@ -31,6 +31,7 @@
* },
* base_table = "custom_block",
* revision_table = "custom_block_revision",
* route_base_path = "admin/structure/custom-blocks/manage/{bundle}",
* menu_base_path = "block/%custom_block",
* fieldable = TRUE,
* translatable = TRUE,
......
......@@ -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.
......
......@@ -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;
}
/**
......
......@@ -34,6 +34,8 @@
* fieldable = TRUE,
* translatable = TRUE,
* static_cache = FALSE,
* route_base_path = "admin/structure/types/manage/{bundle}/comment",
* bundle_prefix = "comment_node_",
* entity_keys = {
* "id" = "cid",
* "bundle" = "node_type",
......
......@@ -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);
......
......@@ -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'),
),
);
......
This diff is collapsed.
......@@ -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';
}
if ($entity_info['fieldable'] && isset($entity_info['route_base_path'])) {
// Extract path information from the entity type.
$path = $entity_info['route_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;
// 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'),
);
$items["$path/fields"] = array(
'title' => 'Manage fields',
'page callback' => 'field_ui_field_overview',
'page arguments' => array($entity_type, $bundle_arg),
'type' => MENU_LOCAL_TASK,
'route_name' => "field_ui.overview.$entity_type",
'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'),
);
$items["$path/fields/%"] = array(
'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'),
'route_name' => "field_ui.instance_edit.$entity_type",
);
$items["$default_path/fields/%/edit"] = array(
'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'),
);
$items["$path/fields/%/field-settings"] = array(
'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'),
'route_name' => "field_ui.settings.$entity_type",
);
$items["$path/fields/%/widget-type"] = array(
'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'),
'route_name' => "field_ui.widget_type.$entity_type",
);
$items["$path/fields/%/delete"] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array('field_ui_field_delete_form', $field_position),
'type' => MENU_VISIBLE_IN_BREADCRUMB,
'route_name' => "field_ui.delete.$entity_type",
'weight' => 10,
'file' => 'field_ui.admin.inc',
) + $access_fields;
);
// '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,
'route_name' => "field_ui.display_overview.$entity_type",
'weight' => 2,
'file' => 'field_ui.admin.inc',
) + $access_display;
);
// 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
// view modes, and use a route requirement 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;
$view_modes = array('default' => array('label' => t('Default'))) + entity_get_view_modes($entity_type);
foreach ($view_modes as $view_mode => $view_mode_info) {
foreach (entity_get_view_modes($entity_type) 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',
'type' => MENU_LOCAL_TASK,
'weight' => $weight++,
'route_name' => "field_ui.display_overview.$entity_type.$view_mode",
);
if ($view_mode != 'default') {
$items["$path/display/$view_mode"]['weight'] = $weight++;
}
}
}
}
}
}
......@@ -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();
}
/**
......
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 }
<?php
/**
* @file
* Contains \Drupal\field_ui\Access\ViewModeAccessCheck.
*/
namespace Drupal\field_ui\Access;
use Drupal\Core\Access\AccessCheckInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
/**
* Allows access to routes to be controlled by an '_access' boolean parameter.
*/
class ViewModeAccessCheck implements AccessCheckInterface {
/**
* {@inheritdoc}
*/
public function applies(Route $route) {
return array_key_exists('_field_ui_view_mode_access', $route->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);
}
}
}
}
......@@ -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();
......
......@@ -14,16 +14,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().
*/
......@@ -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',
......@@ -570,8 +563,9 @@ public function submitForm(array &$form, array &$form_state) {
// Create the field and instance.
try {
field_create_field($field);
field_create_instance($instance);
$this->entityManager->getStorageController('field_entity')->create($field)->save();
$new_instance = $this->entityManager->getStorageController('field_instance')->create($instance);
$new_instance->save();
// Make sure the field is displayed in the 'default' view mode (using
// default formatter and settings). It stays hidden for other view
......@@ -582,8 +576,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 +607,8 @@ public function submitForm(array &$form, array &$form_state) {
);
try {
field_create_instance($instance);
$new_instance = $this->entityManager->getStorageController('field_instance')->create($instance);
$new_instance->save();
// Make sure the field is displayed in the 'default' view mode (using
// default formatter and settings). It stays hidden for other view
......@@ -622,7 +617,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'];
}
......
<?php
/**
* @file
* Contains \Drupal\field_ui\Form\FieldDeleteForm.
*/
namespace Drupal\field_ui\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\field\Plugin\Core\Entity\FieldInstance;
/**
* Provides a form for removing a field instance from a bundle.
*/
class FieldDeleteForm extends ConfirmFormBase {
/**
* The field instance being deleted.
*
* @var \Drupal\field\Plugin\Core\Entity\FieldInstance
*/
protected $instance;
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'field_ui_field_delete_form';
}
/**
* {@inheritdoc}
*/
protected function getQuestion() {
return t('Are you sure you want to delete the field %field?', array('%field' => $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']) {
$this->instance->delete();
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);
}
}
<?php
/**
* @file
* Contains \Drupal\field_ui\Form\FieldSettingsForm.
*/
namespace Drupal\field_ui\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\field\Plugin\Core\Entity\FieldInstance;
use Drupal\field\Field;
/**
* Provides a form for the field settings edit page.
*/
class FieldSettingsForm implements FormInterface {
/**
* The field instance being edited.
*
* @var \Drupal\field\Plugin\Core\Entity\FieldInstance
*/
protected $instance;
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'field_ui_field_settings_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, FieldInstance $field_instance = NULL) {
$this->instance = $form_state['instance'] = $field_instance;
$field = $this->instance->getField();
$form['#field'] = $field;
drupal_set_title($this->instance->label());
$description = '<p>' . 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())) . '</p>';
// 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'] = '<div class="messages error">' . t('There is data for this field in the database. The field settings can no longer be changed.') . '</div>' . $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' => '<div class="container-inline">',
'#field_suffix' => '</div>',
'#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,