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
 */
function hook_field_info_alter(&$info) {
  // Change the default widget for fields of type 'foo'.
  if (isset($info['foo'])) {
56
    $info['foo']['default_widget'] = 'mymodule_widget';
57
58
59
  }
}

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
function hook_field_purge_field_storage(\Drupal\field\Entity\FieldStorageConfig $field_storage) {
396
  \Drupal::database()->delete('my_module_field_storage_info')
397
    ->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
function hook_field_purge_field(\Drupal\field\Entity\FieldConfig $field) {
413
  \Drupal::database()->delete('my_module_field_info')
414
    ->condition('id', $field->id())
415
416
417
    ->execute();
}

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

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