field_ui.module 16.4 KB
Newer Older
1
<?php
2

3 4
/**
 * @file
5
 * Allows administrators to attach custom fields to fieldable types.
6 7
 */

8
use Drupal\Component\Utility\Html;
9
use Drupal\Core\Entity\EntityInterface;
10
use Drupal\Core\Form\FormStateInterface;
11
use Drupal\Core\Render\Element;
12
use Drupal\Core\Routing\RouteMatchInterface;
13
use Drupal\Core\Entity\EntityViewModeInterface;
14
use Drupal\Core\Url;
15
use Drupal\field_ui\FieldUI;
16
use Drupal\field_ui\Plugin\Derivative\FieldUiLocalTask;
17

18
/**
19
 * Implements hook_help().
20
 */
21
function field_ui_help($route_name, RouteMatchInterface $route_match) {
22 23
  $module_handler = \Drupal::moduleHandler();

24 25
  switch ($route_name) {
    case 'help.page.field_ui':
26 27
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
28
      $output .= '<p>' . t('The Field UI module provides an administrative user interface (UI) for managing and displaying fields. Fields can be attached to most content entity sub-types. Different field types, widgets, and formatters are provided by the modules enabled on your site, and managed by the Field module. For background information and terminology related to fields and entities, see the <a href="!field">Field module help page</a>. For more information about the Field UI, see <a href="!field_ui_docs">the online documentation for the Field UI module</a>.', array('!field' => \Drupal::url('help.page', array('name' => 'field')), '!field_ui_docs' => 'https://drupal.org/documentation/modules/field-ui')) . '</p>';
29 30
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
31 32 33 34 35 36 37 38 39
      $output .= '<dt>' . t('Creating a field') . '</dt>';
      $output .= '<dd>' . t('On the <em>Manage fields</em> page for your entity type or sub-type, you can add, configure, and delete fields for that entity type or sub-type. Each field has a <em>machine name</em>, which is used internally to identify the field and must be unique across an entity type; once a field is created, you cannot change the machine name. Most fields have two types of settings. The field-level settings depend on the field type, and affect how the data in the field is stored. Once they are set, they can no longer be changed; examples include how many data values are allowed for the field and where files are stored. The sub-type-level settings are specific to each entity sub-type the field is used on, and they can be changed later; examples include the field label, help text, default value, and whether the field is required or not. You can return to these settings by choosing the <em>Edit</em> link for the field from the <em>Manage fields</em> page.');
      $output .= '<dt>' . t('Re-using fields') . '</dt>';
      $output .= '<dd>' . t('Once you have created a field, you can use it again in other sub-types of the same entity type. For instance, if you create a field for the article content type, you can also use it for the page content type, but you cannot use it for custom blocks or taxonomy terms. If there are fields available for re-use, after clicking <em>Add field</em> from the <em>Manage fields</em> page, you will see a list of available fields for re-use. After selecting a field for re-use, you can configure the sub-type-level settings.') . '</dd>';
      $output .= '<dt>' . t('Configuring field editing') . '</dt>';
      $output .= '<dd>' . t('On the <em>Manage form display</em> page of your entity type or sub-type, you can configure how the field data is edited by default and in each form mode. If your entity type has multiple form modes (on most sites, most entities do not), you can toggle between the form modes at the top of the page, and you can toggle whether each form mode uses the default settings or custom settings in the <em>Custom display settings</em> section. For each field in each form mode, you can select the widget to use for editing; some widgets have additional configuration options, such as the size for a text field, and these can be edited using the Edit button (which looks like a wheel). You can also change the order of the fields on the form. You can exclude a field from a form by choosing <em>Hidden</em> from the widget drop-down list, or by dragging it into the <em>Disabled</em> section.') . '</dd>';
      $output .= '<dt>' . t('Configuring field display') . '</dt>';
      $output .= '<dd>' . t('On the <em>Manage display</em> page of your entity type or sub-type, you can configure how each field is displayed by default and in each view mode. If your entity type has multiple view modes, you can toggle between the view modes at the top of the page, and you can toggle whether each view mode uses the default settings or custom settings in the <em>Custom display settings</em> section. For each field in each view mode, you can choose whether and how to display the label of the field from the <em>Label</em> drop-down list. You can also select the formatter to use for display; some formatters have configuration options, which you can edit using the Edit button (which looks like a wheel). You can also change the display order of fields. You can exclude a field from a specific view mode by choosing <em>Hidden</em> from the formatter drop-down list, or by dragging it into the <em>Disabled</em> section.') . '</dd>';
      $output .= '<dt>' . t('Configuring view and form modes') . '</dt>';
40
      $output .= '<dd>' . t('You can add, edit, and delete view modes for entities on the <a href="!view_modes">View modes page</a>, and you can add, edit, and delete form modes for entities on the <a href="!form_modes">Form modes page</a>. Once you have defined a view mode or form mode for an entity type, it will be available on the Manage display or Manage form display page for each sub-type of that entity.', array('!view_modes' => \Drupal::url('entity.entity_view_mode.collection'), '!form_modes' => \Drupal::url('entity.entity_form_mode.collection'))) . '</dd>';
41
      $output .= '<dt>' . t('Listing fields') . '</dt>';
42
      $output .= '<dd>' . t('There are two reports available that list the fields defined on your site. The <a href="!entity-list" title="Entities field list report">Entities</a> report lists all your fields, showing the field machine names, types, and the entity types or sub-types they are used on (each sub-type links to the Manage fields page). If the <a href="!views">Views</a> and <a href="!views-ui">Views UI</a> modules are enabled, the <a href="!views-list" title="Used in views field list report">Used in views</a> report lists each field that is used in a view, with a link to edit that view.', array('!entity-list' => \Drupal::url('entity.field_storage_config.collection'), '!views-list' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('views_ui.reports_fields') : '#', '!views' => (\Drupal::moduleHandler()->moduleExists('views')) ? \Drupal::url('help.page', array('name' => 'views')) : '#','!views-ui' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('help.page', array('name' => 'views_ui')) : '#')) . '</dd>';
43
      $output .= '</dl>';
44 45
      return $output;

46
    case 'entity.field_storage_config.collection':
47 48 49 50
      return '<p>' . t('This list shows all fields currently in use for easy reference.') . '</p>';
  }
}

51 52 53 54 55 56 57
/**
 * Implements hook_theme().
 */
function field_ui_theme() {
  return array(
    'field_ui_table' => array(
      'render element' => 'elements',
58
      'function' => 'theme_field_ui_table',
59 60 61 62
    ),
  );
}

63
/**
64
 * Implements hook_entity_type_build().
65
 */
66 67
function field_ui_entity_type_build(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
68 69
  $entity_types['field_config']->setFormClass('delete', 'Drupal\field_ui\Form\FieldConfigDeleteForm');
  $entity_types['field_config']->setListBuilderClass('Drupal\field_ui\FieldConfigListBuilder');
70
  $entity_types['field_storage_config']->setListBuilderClass('Drupal\field_ui\FieldStorageConfigListBuilder');
71
  $entity_types['field_storage_config']->setLinkTemplate('collection', '/admin/reports/fields');
72 73
  $entity_types['entity_form_display']->setFormClass('edit', 'Drupal\field_ui\Form\EntityFormDisplayEditForm');
  $entity_types['entity_view_display']->setFormClass('edit', 'Drupal\field_ui\Form\EntityViewDisplayEditForm');
74 75
}

76
/**
77
 * Implements hook_entity_bundle_create().
78
 */
79
function field_ui_entity_bundle_create($entity_type, $bundle) {
80 81
  // When a new bundle is created, the menu needs to be rebuilt to add our
  // menu item tabs.
82
  \Drupal::service('router.builder_indicator')->setRebuildNeeded();
83 84
}

85 86 87 88 89 90
/**
 * Implements hook_entity_bundle_rename().
 */
function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
  // When a bundle is renamed, the menu needs to be rebuilt to add our
  // menu item tabs.
91
  \Drupal::service('router.builder_indicator')->setRebuildNeeded();
92 93
}

94
/**
95 96
 * Implements hook_form_FORM_ID_alter().
 *
97
 * Adds a button 'Save and manage fields' to the 'Create content type' form.
98 99 100
 *
 * @see node_type_form()
 * @see field_ui_form_node_type_form_submit()
101
 */
102
function field_ui_form_node_type_form_alter(&$form, FormStateInterface $form_state) {
103
  // We want to display the button only on add page.
104
  if ($form_state->getFormObject()->getEntity()->isNew()) {
105 106 107 108
    $form['actions']['save_continue'] = $form['actions']['submit'];
    $form['actions']['save_continue']['#value'] = t('Save and manage fields');
    $form['actions']['save_continue']['#weight'] = $form['actions']['save_continue']['#weight'] + 5;
    $form['actions']['save_continue']['#submit'][] = 'field_ui_form_node_type_form_submit';
109 110
    // Hide the 'Save content type' button.
    $form['actions']['submit']['#access'] = FALSE;
111 112 113
  }
}

114
/**
115
 * Implements hook_entity_operation().
116
 */
117 118
function field_ui_entity_operation(EntityInterface $entity) {
  $operations = array();
119
  $info = $entity->getEntityType();
120
  // Add manage fields and display links if this entity type is the bundle
121
  // of another and that type has field UI enabled.
122
  if (($bundle_of = $info->getBundleOf()) && \Drupal::entityManager()->getDefinition($bundle_of)->get('field_ui_base_route')) {
123 124
    $account = \Drupal::currentUser();
    if ($account->hasPermission('administer '. $bundle_of . ' fields')) {
125 126 127
      $operations['manage-fields'] = array(
        'title' => t('Manage fields'),
        'weight' => 15,
128 129 130
        'url' => Url::fromRoute("entity.{$bundle_of}.field_ui_fields", array(
          $entity->getEntityTypeId() => $entity->id(),
        )),
131
      );
132
    }
133
    if ($account->hasPermission('administer '. $bundle_of . ' form display')) {
134 135 136
      $operations['manage-form-display'] = array(
        'title' => t('Manage form display'),
        'weight' => 20,
137
        'url' => Url::fromRoute("entity.entity_form_display.{$bundle_of}.default", array(
138 139
          $entity->getEntityTypeId() => $entity->id(),
        )),
140
      );
141
    }
142
    if ($account->hasPermission('administer '. $bundle_of . ' display')) {
143 144 145
      $operations['manage-display'] = array(
        'title' => t('Manage display'),
        'weight' => 25,
146
        'url' => Url::fromRoute("entity.entity_view_display.{$bundle_of}.default", array(
147 148
          $entity->getEntityTypeId() => $entity->id(),
        )),
149
      );
150 151
    }
  }
152 153

  return $operations;
154 155
}

156
/**
157
 * Form submission handler for the 'Save and manage fields' button.
158 159
 *
 * @see field_ui_form_node_type_form_alter()
160
 */
161
function field_ui_form_node_type_form_submit($form, FormStateInterface $form_state) {
162
  if ($form_state->getTriggeringElement()['#parents'][0] === 'save_continue' && $route_info = FieldUI::getOverviewRouteInfo('node', $form_state->getValue('type'))) {
163
    $form_state->setRedirectUrl($route_info);
164 165
  }
}
166

167 168 169 170
/**
 * Implements hook_view_mode_presave().
 */
function field_ui_view_mode_presave(EntityViewModeInterface $view_mode) {
171
  \Drupal::service('router.builder_indicator')->setRebuildNeeded();
172 173 174 175 176 177
}

/**
 * Implements hook_view_mode_delete().
 */
function field_ui_view_mode_delete(EntityViewModeInterface $view_mode) {
178
  \Drupal::service('router.builder_indicator')->setRebuildNeeded();
179
}
180 181 182 183 184 185 186 187 188 189 190 191 192

/**
 * Returns HTML for Field UI overview tables.
 *
 * @param $variables
 *   An associative array containing:
 *   - elements: An associative array containing a Form API structure to be
 *     rendered as a table.
 *
 * @ingroup themeable
 */
function theme_field_ui_table($variables) {
  $elements = $variables['elements'];
193
  $table = array('#type' => 'table');
194 195

  // Add table headers and attributes.
196 197 198
  foreach (array('#header', '#attributes') as $key) {
    if (isset($elements[$key])) {
      $table[$key] = $elements[$key];
199 200 201 202 203 204
    }
  }

  // Determine the colspan to use for region rows, by checking the number of
  // columns in the headers.
  $columns_count = 0;
205
  foreach ($table['#header'] as $header) {
206 207 208 209 210
    $columns_count += (is_array($header) && isset($header['colspan']) ? $header['colspan'] : 1);
  }

  // Render rows, region by region.
  foreach ($elements['#regions'] as $region_name => $region) {
211
    $region_name_class = Html::getClass($region_name);
212 213 214

    // Add region rows.
    if (isset($region['title']) && empty($region['invisible'])) {
215
      $table['#rows'][] = array(
216 217 218 219 220 221 222 223 224
        'class' => array('region-title', 'region-' . $region_name_class . '-title'),
        'no_striping' => TRUE,
        'data' => array(
          array('data' => $region['title'], 'colspan' => $columns_count),
        ),
      );
    }
    if (isset($region['message'])) {
      $class = (empty($region['rows_order']) ? 'region-empty' : 'region-populated');
225
      $table['#rows'][] = array(
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
        'class' => array('region-message', 'region-' . $region_name_class . '-message', $class),
        'no_striping' => TRUE,
        'data' => array(
          array('data' => $region['message'], 'colspan' => $columns_count),
        ),
      );
    }

    // Add form rows, in the order determined at pre-render time.
    foreach ($region['rows_order'] as $name) {
      $element = $elements[$name];

      $row = array('data' => array());
      if (isset($element['#attributes'])) {
        $row += $element['#attributes'];
      }

      // Render children as table cells.
244
      foreach (Element::children($element) as $cell_key) {
245 246 247 248 249 250 251 252 253 254
        $child = &$element[$cell_key];
        // Do not render a cell for children of #type 'value'.
        if (!(isset($child['#type']) && $child['#type'] == 'value')) {
          $cell = array('data' => drupal_render($child));
          if (isset($child['#cell_attributes'])) {
            $cell += $child['#cell_attributes'];
          }
          $row['data'][] = $cell;
        }
      }
255
      $table['#rows'][] = $row;
256 257 258
    }
  }

259
  return drupal_render($table);
260 261
}

262 263 264 265 266 267 268 269
/**
 * Implements hook_local_tasks_alter().
 */
function field_ui_local_tasks_alter(&$local_tasks) {
  $container = \Drupal::getContainer();
  $local_task = FieldUiLocalTask::create($container, 'field_ui.fields');
  $local_task->alterLocalTasks($local_tasks);
}
270 271 272 273 274 275 276 277 278 279 280 281

/**
 * Implements hook_entity_type_alter().
 */
function field_ui_entity_type_alter(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  $form_mode = $entity_types['entity_form_mode'];
  $form_mode->setListBuilderClass('Drupal\field_ui\EntityFormModeListBuilder');
  $form_mode->setFormClass('add', 'Drupal\field_ui\Form\EntityFormModeAddForm');
  $form_mode->setFormClass('edit', 'Drupal\field_ui\Form\EntityDisplayModeEditForm');
  $form_mode->setFormClass('delete', 'Drupal\field_ui\Form\EntityDisplayModeDeleteForm');
  $form_mode->set('admin_permission', 'administer display modes');
282 283
  $form_mode->setLinkTemplate('delete-form', '/admin/structure/display-modes/form/manage/{entity_form_mode}/delete');
  $form_mode->setLinkTemplate('edit-form', '/admin/structure/display-modes/form/manage/{entity_form_mode}');
284
  $form_mode->setLinkTemplate('add-form', '/admin/structure/display-modes/form/add/{entity_type_id}');
285
  $form_mode->setLinkTemplate('collection', '/admin/structure/display-modes/form');
286 287 288 289 290 291 292

  $view_mode = $entity_types['entity_view_mode'];
  $view_mode->setListBuilderClass('Drupal\field_ui\EntityDisplayModeListBuilder');
  $view_mode->setFormClass('add', 'Drupal\field_ui\Form\EntityDisplayModeAddForm');
  $view_mode->setFormClass('edit', 'Drupal\field_ui\Form\EntityDisplayModeEditForm');
  $view_mode->setFormClass('delete', 'Drupal\field_ui\Form\EntityDisplayModeDeleteForm');
  $view_mode->set('admin_permission', 'administer display modes');
293 294
  $view_mode->setLinkTemplate('delete-form', '/admin/structure/display-modes/view/manage/{entity_view_mode}/delete');
  $view_mode->setLinkTemplate('edit-form', '/admin/structure/display-modes/view/manage/{entity_view_mode}');
295
  $view_mode->setLinkTemplate('add-form', '/admin/structure/display-modes/view/add/{entity_type_id}');
296
  $view_mode->setLinkTemplate('collection', '/admin/structure/display-modes/view');
297
}