field.api.php 15.8 KB
Newer Older
1 2
<?php

3 4 5 6 7
/**
 * @file
 * Field API documentation.
 */

8
/**
9
 * @addtogroup hooks
10 11 12 13 14 15
 * @{
 */

/**
 * @defgroup field_types Field Types API
 * @{
16
 * Defines field, widget, display formatter, and storage types.
17
 *
18 19 20
 * In the Field API, each field has a type, which determines what kind of data
 * (integer, string, date, etc.) the field can hold, which settings it provides,
 * and so on. The data type(s) accepted by a field are defined in
21
 * hook_field_schema().
22
 *
23
 * Field types are plugins annotated with class
24
 * \Drupal\Core\Field\Annotation\FieldType, and implement plugin interface
25 26 27 28 29 30 31
 * \Drupal\Core\Field\FieldItemInterface. Field Type plugins are managed by the
 * \Drupal\Core\Field\FieldTypePluginManager class. Field type classes usually
 * extend base class \Drupal\Core\Field\FieldItemBase. Field-type plugins need
 * to be in the namespace \Drupal\{your_module}\Plugin\Field\FieldType. See the
 * @link plugin_api Plugin API topic @endlink for more information on how to
 * define plugins.
 *
32
 * The Field Types API also defines two kinds of pluggable handlers: widgets
33 34 35
 * and formatters. @link field_widget Widgets @endlink specify how the field
 * appears in edit forms, while @link field_formatter formatters @endlink
 * specify how the field appears in displayed entities.
36
 *
37 38
 * See @link field Field API @endlink for information about the other parts of
 * the Field API.
39 40 41 42 43
 *
 * @see field
 * @see field_widget
 * @see field_formatter
 * @see plugin_api
44 45
 */

46 47 48 49
/**
 * Perform alterations on Field API field types.
 *
 * @param $info
50 51
 *   Array of information on field types as collected by the "field type" plugin
 *   manager.
52 53 54 55 56 57 58 59
 */
function hook_field_info_alter(&$info) {
  // Change the default widget for fields of type 'foo'.
  if (isset($info['foo'])) {
    $info['foo']['default widget'] = 'mymodule_widget';
  }
}

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
/**
 * Perform alterations on preconfigured field options.
 *
 * @param array $options
 *   Array of options as returned from
 *   \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions().
 * @param string $field_type
 *   The field type plugin ID.
 *
 * @see \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface::getPreconfiguredOptions()
 */
function hook_field_ui_preconfigured_options_alter(array &$options, $field_type) {
  // If the field is not an "entity_reference"-based field, bail out.
  /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
  $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
  $class = $field_type_manager->getPluginClass($field_type);
  if (!is_a($class, 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem', TRUE)) {
    return;
  }

  // Set the default formatter for media in entity reference fields to be the
  // "Rendered entity" formatter.
  if (!empty($options['media'])) {
    $options['media']['entity_view_display']['type'] = 'entity_reference_entity_view';
  }
}

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/**
 * Forbid a field storage update from occurring.
 *
 * Any module may forbid any update for any reason. For example, the
 * field's storage module might forbid an update if it would change
 * the storage schema while data for the field exists. A field type
 * module might forbid an update if it would change existing data's
 * semantics, or if there are external dependencies on field settings
 * that cannot be updated.
 *
 * To forbid the update from occurring, throw a
 * \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException.
 *
 * @param \Drupal\field\FieldStorageConfigInterface $field_storage
 *   The field storage as it will be post-update.
 * @param \Drupal\field\FieldStorageConfigInterface $prior_field_storage
 *   The field storage as it is pre-update.
 *
 * @see entity_crud
 */
function hook_field_storage_config_update_forbid(\Drupal\field\FieldStorageConfigInterface $field_storage, \Drupal\field\FieldStorageConfigInterface $prior_field_storage) {
108 109 110 111
  if ($field_storage->module == 'options' && $field_storage->hasData()) {
    // Forbid any update that removes allowed values with actual data.
    $allowed_values = $field_storage->getSetting('allowed_values');
    $prior_allowed_values = $prior_field_storage->getSetting('allowed_values');
112
    $lost_keys = array_keys(array_diff_key($prior_allowed_values, $allowed_values));
113
    if (_options_values_in_use($field_storage->getTargetEntityTypeId(), $field_storage->getName(), $lost_keys)) {
114
      throw new \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', ['@field_name' => $field_storage->getName()]));
115 116 117 118
    }
  }
}

119
/**
120
 * @} End of "defgroup field_types".
121 122 123 124 125 126 127 128 129 130
 */

/**
 * @defgroup field_widget Field Widget API
 * @{
 * Define Field API widget types.
 *
 * Field API widgets specify how fields are displayed in edit forms. Fields of a
 * given @link field_types field type @endlink may be edited using more than one
 * widget. In this case, the Field UI module allows the site builder to choose
131 132 133
 * which widget to use.
 *
 * Widgets are Plugins managed by the
134
 * \Drupal\Core\Field\WidgetPluginManager class. A widget is a plugin annotated
135
 * with class \Drupal\Core\Field\Annotation\FieldWidget that implements
136 137 138
 * \Drupal\Core\Field\WidgetInterface (in most cases, by
 * subclassing \Drupal\Core\Field\WidgetBase). Widget plugins need to be in the
 * namespace \Drupal\{your_module}\Plugin\Field\FieldWidget.
139
 *
140 141 142
 * Widgets are @link form_api Form API @endlink elements with additional
 * processing capabilities. The methods of the WidgetInterface object are
 * typically called by respective methods in the
143
 * \Drupal\Core\Entity\Entity\EntityFormDisplay class.
144 145 146 147
 *
 * @see field
 * @see field_types
 * @see field_formatter
148
 * @see plugin_api
149 150
 */

151 152 153
/**
 * Perform alterations on Field API widget types.
 *
154
 * @param array $info
155
 *   An array of information on existing widget types, as collected by the
156
 *   annotation discovery mechanism.
157
 */
158
function hook_field_widget_info_alter(array &$info) {
159
  // Let a new field type re-use an existing widget.
160
  $info['options_select']['field_types'][] = 'my_field_type';
161 162
}

163 164 165
/**
 * Alter forms for field widgets provided by other modules.
 *
166 167 168 169 170
 * This hook can only modify individual elements within a field widget and
 * cannot alter the top level (parent element) for multi-value fields. In most
 * cases, you should use hook_field_widget_multivalue_form_alter() instead and
 * loop over the elements.
 *
171
 * @param $element
172 173
 *   The field widget form element as constructed by
 *   \Drupal\Core\Field\WidgetBaseInterface::form().
174
 * @param $form_state
175
 *   The current state of the form.
176
 * @param $context
177
 *   An associative array containing the following key-value pairs:
178 179
 *   - form: The form structure to which widgets are being attached. This may be
 *     a full form structure, or a sub-element of a larger form.
180
 *   - widget: The widget plugin instance.
181
 *   - items: The field values, as a
182
 *     \Drupal\Core\Field\FieldItemListInterface object.
183
 *   - delta: The order of this item in the array of subelements (0, 1, 2, etc).
184 185
 *   - default: A boolean indicating whether the form is being shown as a dummy
 *     form to set default values.
186
 *
187
 * @see \Drupal\Core\Field\WidgetBaseInterface::form()
188
 * @see \Drupal\Core\Field\WidgetBase::formSingleElement()
189
 * @see hook_field_widget_WIDGET_TYPE_form_alter()
190
 * @see hook_field_widget_multivalue_form_alter()
191
 */
192
function hook_field_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
193
  // Add a css class to widget form elements for all fields of type mytype.
194
  $field_definition = $context['items']->getFieldDefinition();
195
  if ($field_definition->getType() == 'mytype') {
196 197 198 199 200 201 202 203 204 205 206 207
    // Be sure not to overwrite existing attributes.
    $element['#attributes']['class'][] = 'myclass';
  }
}

/**
 * Alter widget forms for a specific widget provided by another module.
 *
 * Modules can implement hook_field_widget_WIDGET_TYPE_form_alter() to modify a
 * specific widget form, rather than using hook_field_widget_form_alter() and
 * checking the widget type.
 *
208 209 210 211 212
 * This hook can only modify individual elements within a field widget and
 * cannot alter the top level (parent element) for multi-value fields. In most
 * cases, you should use hook_field_widget_multivalue_WIDGET_TYPE_form_alter()
 * instead and loop over the elements.
 *
213
 * @param $element
214 215
 *   The field widget form element as constructed by
 *   \Drupal\Core\Field\WidgetBaseInterface::form().
216
 * @param $form_state
217
 *   The current state of the form.
218
 * @param $context
219 220
 *   An associative array. See hook_field_widget_form_alter() for the structure
 *   and content of the array.
221
 *
222
 * @see \Drupal\Core\Field\WidgetBaseInterface::form()
223
 * @see \Drupal\Core\Field\WidgetBase::formSingleElement()
224
 * @see hook_field_widget_form_alter()
225
 * @see hook_field_widget_multivalue_WIDGET_TYPE_form_alter()
226
 */
227
function hook_field_widget_WIDGET_TYPE_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
228 229 230
  // Code here will only act on widgets of type WIDGET_TYPE.  For example,
  // hook_field_widget_mymodule_autocomplete_form_alter() will only act on
  // widgets of type 'mymodule_autocomplete'.
231
  $element['#autocomplete_route_name'] = 'mymodule.autocomplete_route';
232 233
}

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
/**
 * Alter forms for multi-value field widgets provided by other modules.
 *
 * To alter the individual elements within the widget, loop over
 * \Drupal\Core\Render\Element::children($elements).
 *
 * @param array $elements
 *   The field widget form elements as constructed by
 *   \Drupal\Core\Field\WidgetBase::formMultipleElements().
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 * @param array $context
 *   An associative array containing the following key-value pairs:
 *   - form: The form structure to which widgets are being attached. This may be
 *     a full form structure, or a sub-element of a larger form.
 *   - widget: The widget plugin instance.
 *   - items: The field values, as a
 *     \Drupal\Core\Field\FieldItemListInterface object.
 *   - default: A boolean indicating whether the form is being shown as a dummy
 *     form to set default values.
 *
 * @see \Drupal\Core\Field\WidgetBaseInterface::form()
 * @see \Drupal\Core\Field\WidgetBase::formMultipleElements()
 * @see hook_field_widget_multivalue_WIDGET_TYPE_form_alter()
 */
function hook_field_widget_multivalue_form_alter(array &$elements, \Drupal\Core\Form\FormStateInterface $form_state, array $context) {
  // Add a css class to widget form elements for all fields of type mytype.
  $field_definition = $context['items']->getFieldDefinition();
  if ($field_definition->getType() == 'mytype') {
    // Be sure not to overwrite existing attributes.
    $elements['#attributes']['class'][] = 'myclass';
  }
}

/**
 * Alter multi-value widget forms for a widget provided by another module.
 *
 * Modules can implement hook_field_widget_multivalue_WIDGET_TYPE_form_alter() to
 * modify a specific widget form, rather than using
 * hook_field_widget_form_alter() and checking the widget type.
 *
 * To alter the individual elements within the widget, loop over
 * \Drupal\Core\Render\Element::children($elements).
 *
 * @param array $elements
 *   The field widget form elements as constructed by
 *   \Drupal\Core\Field\WidgetBase::formMultipleElements().
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 * @param array $context
 *   An associative array. See hook_field_widget_multivalue_form_alter() for
 *   the structure and content of the array.
 *
 * @see \Drupal\Core\Field\WidgetBaseInterface::form()
 * @see \Drupal\Core\Field\WidgetBase::formMultipleElements()
 * @see hook_field_widget_multivalue_form_alter()
 */
function hook_field_widget_multivalue_WIDGET_TYPE_form_alter(array &$elements, \Drupal\Core\Form\FormStateInterface $form_state, array $context) {
  // Code here will only act on widgets of type WIDGET_TYPE. For example,
  // hook_field_widget_multivalue_mymodule_autocomplete_form_alter() will only
  // act on widgets of type 'mymodule_autocomplete'.
295
  // Change the autocomplete route for each autocomplete element within the
296 297 298 299 300 301
  // multivalue widget.
  foreach (Element::children($elements) as $delta => $element) {
    $elements[$delta]['#autocomplete_route_name'] = 'mymodule.autocomplete_route';
  }
}

302
/**
303
 * @} End of "defgroup field_widget".
304 305 306 307 308 309 310 311 312 313 314 315
 */


/**
 * @defgroup field_formatter Field Formatter API
 * @{
 * Define Field API formatter types.
 *
 * Field API formatters specify how fields are displayed when the entity to
 * which the field is attached is displayed. Fields of a given
 * @link field_types field type @endlink may be displayed using more than one
 * formatter. In this case, the Field UI module allows the site builder to
316 317 318
 * choose which formatter to use.
 *
 * Formatters are Plugins managed by the
319
 * \Drupal\Core\Field\FormatterPluginManager class. A formatter is a plugin
320
 * annotated with class \Drupal\Core\Field\Annotation\FieldFormatter that
321 322 323
 * implements \Drupal\Core\Field\FormatterInterface (in most cases, by
 * subclassing \Drupal\Core\Field\FormatterBase). Formatter plugins need to be
 * in the namespace \Drupal\{your_module}\Plugin\Field\FieldFormatter.
324 325 326 327
 *
 * @see field
 * @see field_types
 * @see field_widget
328
 * @see plugin_api
329 330
 */

331 332 333
/**
 * Perform alterations on Field API formatter types.
 *
334
 * @param array $info
335
 *   An array of information on existing formatter types, as collected by the
336
 *   annotation discovery mechanism.
337
 */
338
function hook_field_formatter_info_alter(array &$info) {
339
  // Let a new field type re-use an existing formatter.
340
  $info['text_default']['field_types'][] = 'my_field_type';
341 342
}

343
/**
344
 * @} End of "defgroup field_formatter".
345 346
 */

347 348 349 350 351 352
/**
 * Returns the maximum weight for the entity components handled by the module.
 *
 * Field API takes care of fields and 'extra_fields'. This hook is intended for
 * third-party modules adding other entity components (e.g. field_group).
 *
353
 * @param string $entity_type
354
 *   The type of entity; e.g. 'node' or 'user'.
355
 * @param string $bundle
356
 *   The bundle name.
357 358 359 360 361 362 363
 * @param string $context
 *   The context for which the maximum weight is requested. Either 'form' or
 *   'display'.
 * @param string $context_mode
 *   The view or form mode name.
 *
 * @return int
364 365
 *   The maximum weight of the entity's components, or NULL if no components
 *   were found.
366 367
 *
 * @ingroup field_info
368
 */
369
function hook_field_info_max_weight($entity_type, $bundle, $context, $context_mode) {
370
  $weights = [];
371

372
  foreach (my_module_entity_additions($entity_type, $bundle, $context, $context_mode) as $addition) {
373 374 375 376 377 378
    $weights[] = $addition['weight'];
  }

  return $weights ? max($weights) : NULL;
}

379
/**
380
 * @addtogroup field_purge
381 382 383
 * @{
 */

384
/**
385
 * Acts when a field storage definition is being purged.
386
 *
387 388 389 390
 * In field_purge_field_storage(), after the storage definition has been removed
 * from the system, the entity storage has purged stored field data, and the
 * field definitions cache has been cleared, this hook is invoked on all modules
 * to allow them to respond to the field storage being purged.
391
 *
392 393
 * @param $field_storage \Drupal\field\Entity\FieldStorageConfig
 *   The field storage being purged.
394
 */
395 396 397
function hook_field_purge_field_storage(\Drupal\field\Entity\FieldStorageConfig $field_storage) {
  db_delete('my_module_field_storage_info')
    ->condition('uuid', $field_storage->uuid())
398 399 400 401
    ->execute();
}

/**
402
 * Acts when a field is being purged.
403
 *
404
 * In field_purge_field(), after the field definition has been removed
405
 * from the system, the entity storage has purged stored field data, and the
406
 * field info cache has been cleared, this hook is invoked on all modules to
407
 * allow them to respond to the field being purged.
408
 *
409 410
 * @param $field
 *   The field being purged.
411
 */
412 413 414
function hook_field_purge_field(\Drupal\field\Entity\FieldConfig $field) {
  db_delete('my_module_field_info')
    ->condition('id', $field->id())
415 416 417
    ->execute();
}

418
/**
419
 * @} End of "addtogroup field_purge".
420 421
 */

422
/**
423
 * @} End of "addtogroup hooks".
424
 */