entity.api.php 29.6 KB
Newer Older
1 2 3 4 5 6 7
<?php

/**
 * @file
 * Hooks provided the Entity module.
 */

8
use Drupal\Core\Entity\ContentEntityInterface;
9
use Drupal\Core\Field\FieldDefinition;
10

11 12 13 14 15
/**
 * @addtogroup hooks
 * @{
 */

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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 87 88 89 90 91 92 93 94 95
/**
 * Control entity operation access.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity to check access to.
 * @param string $operation
 *   The operation that is to be performed on $entity.
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param string $langcode
 *    The code of the language $entity is accessed in.
 *
 * @return bool|null
 *   A boolean to explicitly allow or deny access, or NULL to neither allow nor
 *   deny access.
 *
 * @see \Drupal\Core\Entity\EntityAccessController
 */
function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
  return NULL;
}

/**
 * Control entity operation access for a specific entity type.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity to check access to.
 * @param string $operation
 *   The operation that is to be performed on $entity.
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param string $langcode
 *    The code of the language $entity is accessed in.
 *
 * @return bool|null
 *   A boolean to explicitly allow or deny access, or NULL to neither allow nor
 *   deny access.
 *
 * @see \Drupal\Core\Entity\EntityAccessController
 */
function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
  return NULL;
}

/**
 * Control entity create access.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param string $langcode
 *    The code of the language $entity is accessed in.
 *
 * @return bool|null
 *   A boolean to explicitly allow or deny access, or NULL to neither allow nor
 *   deny access.
 *
 * @see \Drupal\Core\Entity\EntityAccessController
 */
function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, $langcode) {
  return NULL;
}

/**
 * Control entity create access for a specific entity type.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param string $langcode
 *    The code of the language $entity is accessed in.
 *
 * @return bool|null
 *   A boolean to explicitly allow or deny access, or NULL to neither allow nor
 *   deny access.
 *
 * @see \Drupal\Core\Entity\EntityAccessController
 */
function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, $langcode) {
  return NULL;
}

96
/**
97 98
 * Add to entity type definitions.
 *
99 100
 * Modules may implement this hook to add information to defined entity types,
 * as defined in \Drupal\Core\Entity\EntityTypeInterface.
101
 *
102
 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
103 104 105 106
 *   An associative array of all entity type definitions, keyed by the entity
 *   type name. Passed by reference.
 *
 * @see \Drupal\Core\Entity\Entity
107
 * @see \Drupal\Core\Entity\EntityTypeInterface
108
 */
109 110
function hook_entity_type_build(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
111
  // Add a form controller for a custom node form without overriding the default
112 113
  // node form. To override the default node form, use hook_entity_type_alter().
  $entity_types['node']->setFormClass('mymodule_foo', 'Drupal\mymodule\NodeFooFormController');
114 115
}

116 117 118 119 120 121 122 123 124
/**
 * Alter the entity type definitions.
 *
 * Modules may implement this hook to alter the information that defines an
 * entity type. All properties that are available in
 * \Drupal\Core\Entity\Annotation\EntityType and all the ones additionally
 * provided by modules can be altered here.
 *
 * Do not use this hook to add information to entity types, unless you are just
125
 * filling-in default values. Use hook_entity_type_build() instead.
126
 *
127
 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
128 129 130 131 132 133
 *   An associative array of all entity type definitions, keyed by the entity
 *   type name. Passed by reference.
 *
 * @see \Drupal\Core\Entity\Entity
 * @see \Drupal\Core\Entity\EntityTypeInterface
 */
134 135
function hook_entity_type_alter(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
136 137
  // Set the controller class for nodes to an alternate implementation of the
  // Drupal\Core\Entity\EntityStorageControllerInterface interface.
138
  $entity_types['node']->setStorageClass('Drupal\mymodule\MyCustomNodeStorageController');
139 140
}

141 142 143 144 145 146
/**
 * Alter the view modes for entity types.
 *
 * @param array $view_modes
 *   An array of view modes, keyed first by entity type, then by view mode name.
 *
147 148
 * @see \Drupal\Core\Entity\EntityManagerInterface::getAllViewModes()
 * @see \Drupal\Core\Entity\EntityManagerInterface::getViewModes()
149 150 151
 * @see hook_entity_view_mode_info()
 */
function hook_entity_view_mode_info_alter(&$view_modes) {
152
  $view_modes['user']['full']['status'] = TRUE;
153 154 155 156 157 158 159 160 161 162 163 164 165
}

/**
 * Describe the bundles for entity types.
 *
 * @return array
 *   An associative array of all entity bundles, keyed by the entity
 *   type name, and then the bundle name, with the following keys:
 *   - label: The human-readable name of the bundle.
 *   - uri_callback: The same as the 'uri_callback' key defined for the entity
 *     type in the EntityManager, but for the bundle only. When determining
 *     the URI of an entity, if a 'uri_callback' is defined for both the
 *     entity type and the bundle, the one for the bundle is used.
166 167
 *   - translatable: (optional) A boolean value specifying whether this bundle
 *     has translation support enabled. Defaults to FALSE.
168 169 170 171 172
 *
 * @see entity_get_bundles()
 * @see hook_entity_bundle_info_alter()
 */
function hook_entity_bundle_info() {
173
  $bundles['user']['user']['label'] = t('User');
174 175 176 177 178 179 180 181 182 183 184 185 186 187
  return $bundles;
}

/**
 * Alter the bundles for entity types.
 *
 * @param array $bundles
 *   An array of bundles, keyed first by entity type, then by bundle name.
 *
 * @see entity_get_bundles()
 * @see hook_entity_bundle_info()
 */
function hook_entity_bundle_info_alter(&$bundles) {
  $bundles['user']['user']['label'] = t('Full account');
188 189
}

190 191 192 193 194
/**
 * Act on entity_bundle_create().
 *
 * This hook is invoked after the operation has been performed.
 *
195
 * @param string $entity_type_id
196 197 198 199
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param string $bundle
 *   The name of the bundle.
 */
200
function hook_entity_bundle_create($entity_type_id, $bundle) {
201 202
  // When a new bundle is created, the menu needs to be rebuilt to add the
  // Field UI menu item tabs.
203
  \Drupal::service('router.builder')->setRebuildNeeded();
204 205 206 207 208 209 210
}

/**
 * Act on entity_bundle_rename().
 *
 * This hook is invoked after the operation has been performed.
 *
211
 * @param string $entity_type_id
212 213 214 215 216 217
 *   The entity type to which the bundle is bound.
 * @param string $bundle_old
 *   The previous name of the bundle.
 * @param string $bundle_new
 *   The new name of the bundle.
 */
218
function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
219
  // Update the settings associated with the bundle in my_module.settings.
220
  $config = \Drupal::config('my_module.settings');
221
  $bundle_settings = $config->get('bundle_settings');
222 223 224
  if (isset($bundle_settings[$entity_type_id][$bundle_old])) {
    $bundle_settings[$entity_type_id][$bundle_new] = $bundle_settings[$entity_type_id][$bundle_old];
    unset($bundle_settings[$entity_type_id][$bundle_old]);
225 226 227 228 229 230 231 232 233
    $config->set('bundle_settings', $bundle_settings);
  }
}

/**
 * Act on entity_bundle_delete().
 *
 * This hook is invoked after the operation has been performed.
 *
234
 * @param string $entity_type_id
235 236 237 238
 *   The type of entity; for example, 'node' or 'user'.
 * @param string $bundle
 *   The bundle that was just deleted.
 */
239
function hook_entity_bundle_delete($entity_type_id, $bundle) {
240
  // Remove the settings associated with the bundle in my_module.settings.
241
  $config = \Drupal::config('my_module.settings');
242
  $bundle_settings = $config->get('bundle_settings');
243 244
  if (isset($bundle_settings[$entity_type_id][$bundle])) {
    unset($bundle_settings[$entity_type_id][$bundle]);
245 246 247 248
    $config->set('bundle_settings', $bundle_settings);
  }
}

249 250 251 252 253 254 255 256 257 258
/**
 * Act on a newly created entity.
 *
 * This hook runs after a new entity object has just been instantiated. It can
 * be used to set initial values, e.g. to provide defaults.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity object.
 */
function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
259
  if ($entity instanceof ContentEntityInterface && !$entity->foo->value) {
260 261 262 263
    $entity->foo->value = 'some_initial_value';
  }
}

264 265 266 267 268 269
/**
 * Act on entities when loaded.
 *
 * This is a generic load hook called for all entity types loaded via the
 * entity API.
 *
270
 * @param array $entities
271
 *   The entities keyed by entity ID.
272
 * @param string $entity_type_id
273 274
 *   The type of entities being loaded (i.e. node, user, comment).
 */
275
function hook_entity_load($entities, $entity_type_id) {
276
  foreach ($entities as $entity) {
277
    $entity->foo = mymodule_add_something($entity);
278 279 280 281 282 283
  }
}

/**
 * Act on an entity before it is about to be created or updated.
 *
284
 * @param \Drupal\Core\Entity\EntityInterface $entity
285 286
 *   The entity object.
 */
287
function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
288 289 290 291
  $entity->changed = REQUEST_TIME;
}

/**
292 293 294 295
 * Respond to creation of a new entity.
 *
 * This hook runs once the entity has been stored. Note that hook
 * implementations may not alter the stored entity data.
296
 *
297
 * @param \Drupal\Core\Entity\EntityInterface $entity
298 299
 *   The entity object.
 */
300
function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
301 302 303
  // Insert the new entity into a fictional table of all entities.
  db_insert('example_entity')
    ->fields(array(
304
      'type' => $entity->getEntityTypeId(),
305
      'id' => $entity->id(),
306 307 308 309 310 311 312
      'created' => REQUEST_TIME,
      'updated' => REQUEST_TIME,
    ))
    ->execute();
}

/**
313 314 315 316
 * Respond to updates to an entity.
 *
 * This hook runs once the entity storage has been updated. Note that hook
 * implementations may not alter the stored entity data.
317
 *
318
 * @param \Drupal\Core\Entity\EntityInterface $entity
319 320
 *   The entity object.
 */
321
function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
322 323 324 325 326
  // Update the entity's entry in a fictional table of all entities.
  db_update('example_entity')
    ->fields(array(
      'updated' => REQUEST_TIME,
    ))
327
    ->condition('type', $entity->getEntityTypeId())
328
    ->condition('id', $entity->id())
329 330 331
    ->execute();
}

332
/**
333 334 335 336
 * Respond to creation of a new entity translation.
 *
 * This hook runs once the entity translation has been stored. Note that hook
 * implementations may not alter the stored entity translation data.
337 338 339 340 341 342 343 344 345 346 347 348 349
 *
 * @param \Drupal\Core\Entity\EntityInterface $translation
 *   The entity object of the translation just stored.
 */
function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
  $variables = array(
    '@language' => $translation->language()->name,
    '@label' => $translation->getUntranslated()->label(),
  );
  watchdog('example', 'The @language translation of @label has just been stored.', $variables);
}

/**
350 351 352
 * Respond to entity translation deletion.
 *
 * This hook runs once the entity translation has been deleted from storage.
353 354 355 356 357 358 359 360 361 362 363 364 365
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The original entity object.
 */
function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
  $languages = language_list();
  $variables = array(
    '@language' => $languages[$langcode]->name,
    '@label' => $entity->label(),
  );
  watchdog('example', 'The @language translation of @label has just been deleted.', $variables);
}

366
/**
367 368
 * Act before entity deletion.
 *
369
 * @param \Drupal\Core\Entity\EntityInterface $entity
370 371
 *   The entity object for the entity that is about to be deleted.
 */
372
function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) {
373 374
  // Count references to this entity in a custom table before they are removed
  // upon entity deletion.
375
  $id = $entity->id();
376
  $type = $entity->getEntityTypeId();
377 378 379 380 381 382 383 384
  $count = db_select('example_entity_data')
    ->condition('type', $type)
    ->condition('id', $id)
    ->countQuery()
    ->execute()
    ->fetchField();

  // Log the count in a table that records this statistic for deleted entities.
385 386 387 388
  db_merge('example_deleted_entity_statistics')
    ->key(array('type' => $type, 'id' => $id))
    ->fields(array('count' => $count))
    ->execute();
389 390 391 392 393
}

/**
 * Respond to entity deletion.
 *
394
 * This hook runs once the entity has been deleted from the storage.
395
 *
396
 * @param \Drupal\Core\Entity\EntityInterface $entity
397
 *   The entity object for the entity that has been deleted.
398
 */
399
function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
400 401
  // Delete the entity's entry from a fictional table of all entities.
  db_delete('example_entity')
402
    ->condition('type', $entity->getEntityTypeId())
403
    ->condition('id', $entity->id())
404 405 406
    ->execute();
}

407 408 409
/**
 * Respond to entity revision deletion.
 *
410
 * This hook runs once the entity revision has been deleted from the storage.
411
 *
412
 * @param \Drupal\Core\Entity\EntityInterface $entity
413 414 415 416 417 418
 *   The entity object for the entity revision that has been deleted.
 */
function hook_entity_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
  // @todo: code example
}

419
/**
420
 * Alter or execute an Drupal\Core\Entity\Query\EntityQueryInterface.
421
 *
422
 * @param \Drupal\Core\Entity\Query\QueryInterface $query
423 424 425 426 427 428 429
 *   Note the $query->altered attribute which is TRUE in case the query has
 *   already been altered once. This happens with cloned queries.
 *   If there is a pager, then such a cloned query will be executed to count
 *   all elements. This query can be detected by checking for
 *   ($query->pager && $query->count), allowing the driver to return 0 from
 *   the count query and disable the pager.
 */
430 431
function hook_entity_query_alter(\Drupal\Core\Entity\Query\QueryInterface $query) {
  // @todo: code example.
432 433 434 435 436
}

/**
 * Act on entities being assembled before rendering.
 *
437
 * @param \Drupal\Core\Entity\EntityInterface $entity
438
 *   The entity object.
439
 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
440
 *   The entity view display holding the display options configured for the
441
 *   entity components.
442 443 444 445 446 447 448 449 450 451 452 453 454 455
 * @param $view_mode
 *   The view mode the entity is rendered in.
 * @param $langcode
 *   The language code used for rendering.
 *
 * The module may add elements to $entity->content prior to rendering. The
 * structure of $entity->content is a renderable array as expected by
 * drupal_render().
 *
 * @see hook_entity_view_alter()
 * @see hook_comment_view()
 * @see hook_node_view()
 * @see hook_user_view()
 */
456
function hook_entity_view(\Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
457 458 459 460 461 462 463 464 465
  // Only do the extra work if the component is configured to be displayed.
  // This assumes a 'mymodule_addition' extra field has been defined for the
  // entity bundle in hook_field_extra_fields().
  if ($display->getComponent('mymodule_addition')) {
    $entity->content['mymodule_addition'] = array(
      '#markup' => mymodule_addition($entity),
      '#theme' => 'mymodule_my_additional_field',
    );
  }
466 467 468 469 470 471 472 473 474 475 476
}

/**
 * Alter the results of ENTITY_view().
 *
 * This hook is called after the content has been assembled in a structured
 * array and may be used for doing processing which requires that the complete
 * entity content structure has been built.
 *
 * If a module wishes to act on the rendered HTML of the entity rather than the
 * structured content array, it may use this hook to add a #post_render
477
 * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
478
 * the particular entity type template, if there is one (e.g., node.html.twig).
479
 * See drupal_render() and _theme() for details.
480 481 482
 *
 * @param $build
 *   A renderable array representing the entity content.
483
 * @param \Drupal\Core\Entity\EntityInterface $entity
484
 *   The entity object being rendered.
485
 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
486
 *   The entity view display holding the display options configured for the
487
 *   entity components.
488 489 490 491 492 493 494
 *
 * @see hook_entity_view()
 * @see hook_comment_view_alter()
 * @see hook_node_view_alter()
 * @see hook_taxonomy_term_view_alter()
 * @see hook_user_view_alter()
 */
495
function hook_entity_view_alter(&$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
496 497 498 499 500 501 502 503 504 505 506 507 508
  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
    // Change its weight.
    $build['an_additional_field']['#weight'] = -10;

    // Add a #post_render callback to act on the rendered HTML of the entity.
    $build['#post_render'][] = 'my_module_node_post_render';
  }
}

/**
 * Act on entities as they are being prepared for view.
 *
 * Allows you to operate on multiple entities as they are being prepared for
509
 * view. Only use this if attaching the data during the entity loading phase
510 511
 * is not appropriate, for example when attaching other 'entity' style objects.
 *
512
 * @param string $entity_type_id
513
 *   The type of entities being viewed (i.e. node, user, comment).
514 515
 * @param array $entities
 *   The entities keyed by entity ID.
516
 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] $displays
517
 *   The array of entity view displays holding the display options configured
518 519 520
 *   for the entity components, keyed by bundle name.
 * @param string $view_mode
 *   The view mode.
521
 */
522
function hook_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) {
523
  // Load a specific node into the user object for later theming.
524
  if (!empty($entities) && $entity_type_id == 'user') {
525 526 527 528 529 530 531 532 533 534 535 536 537 538
    // Only do the extra work if the component is configured to be
    // displayed. This assumes a 'mymodule_addition' extra field has been
    // defined for the entity bundle in hook_field_extra_fields().
    $ids = array();
    foreach ($entities as $id => $entity) {
      if ($displays[$entity->bundle()]->getComponent('mymodule_addition')) {
        $ids[] = $id;
      }
    }
    if ($ids) {
      $nodes = mymodule_get_user_nodes($ids);
      foreach ($ids as $id) {
        $entities[$id]->user_node = $nodes[$id];
      }
539 540 541
    }
  }
}
542 543 544 545 546 547

/**
 * Change the view mode of an entity that is being displayed.
 *
 * @param string $view_mode
 *   The view_mode that is to be used to display the entity.
548
 * @param \Drupal\Core\Entity\EntityInterface $entity
549 550 551 552 553
 *   The entity that is being viewed.
 * @param array $context
 *   Array with additional context information, currently only contains the
 *   langcode the entity is viewed in.
 */
554
function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
555
  // For nodes, change the view mode when it is teaser.
556
  if ($entity->getEntityTypeId() == 'node' && $view_mode == 'teaser') {
557 558 559
    $view_mode = 'my_custom_view_mode';
  }
}
560

561 562 563
/**
 * Alters the settings used for displaying an entity.
 *
564
 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
565
 *   The entity view display that will be used to display the entity
566 567 568 569 570 571 572
 *   components.
 * @param array $context
 *   An associative array containing:
 *   - entity_type: The entity type, e.g., 'node' or 'user'.
 *   - bundle: The bundle, e.g., 'page' or 'article'.
 *   - view_mode: The view mode, e.g. 'full', 'teaser'...
 */
573
function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) {
574 575
  // Leave field labels out of the search index.
  if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') {
576 577 578 579
    foreach ($display->getComponents() as $name => $options) {
      if (isset($options['label'])) {
        $options['label'] = 'hidden';
        $display->setComponent($name, $options);
580 581 582 583 584
      }
    }
  }
}

585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
/**
 * Alter the render array generated by an EntityDisplay for an entity.
 *
 * @param array $build
 *   The renderable array generated by the EntityDisplay.
 * @param array $context
 *   An associative array containing:
 *   - entity: The entity being rendered.
 *   - view_mode: The view mode; for example, 'full' or 'teaser'.
 *   - display: The EntityDisplay holding the display options.
 */
function hook_entity_display_build_alter(&$build, $context) {
  // Append RDF term mappings on displayed taxonomy links.
  foreach (element_children($build) as $field_name) {
    $element = &$build[$field_name];
    if ($element['#field_type'] == 'entity_reference' && $element['#formatter'] == 'entity_reference_label') {
      foreach ($element['#items'] as $delta => $item) {
        $term = $item->entity;
        if (!empty($term->rdf_mapping['rdftype'])) {
          $element[$delta]['#options']['attributes']['typeof'] = $term->rdf_mapping['rdftype'];
        }
        if (!empty($term->rdf_mapping['name']['predicates'])) {
          $element[$delta]['#options']['attributes']['property'] = $term->rdf_mapping['name']['predicates'];
        }
      }
    }
  }
}

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
/**
 * Acts on an entity object about to be shown on an entity form.
 *
 * This can be typically used to pre-fill entity values or change the form state
 * before the entity form is built. It is invoked just once when first building
 * the entity form. Rebuilds will not trigger a new invocation.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity that is about to be shown on the form.
 * @param $form_display
 *   The current form display.
 * @param $operation
 *   The current operation.
 * @param array $form_state
 *   An associative array containing the current state of the form.
 *
 * @see \Drupal\Core\Entity\EntityFormController::prepareEntity()
 */
function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $form_display, $operation, array &$form_state) {
  if ($operation == 'edit') {
    $entity->label->value = 'Altered label';
    $form_state['mymodule']['label_altered'] = TRUE;
  }
}

639 640 641
/**
 * Alters the settings used for displaying an entity form.
 *
642
 * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
643 644 645 646 647 648 649 650
 *   The entity_form_display object that will be used to display the entity form
 *   components.
 * @param array $context
 *   An associative array containing:
 *   - entity_type: The entity type, e.g., 'node' or 'user'.
 *   - bundle: The bundle, e.g., 'page' or 'article'.
 *   - form_mode: The form mode, e.g. 'default', 'profile', 'register'...
 */
651
function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
652 653 654 655 656 657 658 659
  // Hide the 'user_picture' field from the register form.
  if ($context['entity_type'] == 'user' && $context['form_mode'] == 'register') {
    $form_display->setComponent('user_picture', array(
      'type' => 'hidden',
    ));
  }
}

660
/**
661
 * Provides custom base field definitions for a content entity type.
662
 *
663 664
 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
 *   The entity type definition.
665
 *
666 667 668 669 670 671
 * @return \Drupal\Core\Field\FieldDefinitionInterface[]
 *   An array of field definitions, keyed by field name.
 *
 * @see hook_entity_base_field_info_alter()
 * @see hook_entity_bundle_field_info()
 * @see hook_entity_bundle_field_info_alter()
672
 * @see \Drupal\Core\Field\FieldDefinitionInterface
673
 * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions()
674
 */
675 676 677 678
function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'node') {
    $fields = array();
    $fields['mymodule_text'] = FieldDefinition::create('string')
679 680 681 682 683
      ->setLabel(t('The text'))
      ->setDescription(t('A text property added by mymodule.'))
      ->setComputed(TRUE)
      ->setClass('\Drupal\mymodule\EntityComputedText');

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
    return $fields;
  }
}

/**
 * Alters base field definitions for a content entity type.
 *
 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
 *   The array of base field definitions for the entity type.
 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
 *   The entity type definition.
 *
 * @see hook_entity_base_field_info()
 * @see hook_entity_bundle_field_info()
 * @see hook_entity_bundle_field_info_alter()
 */
function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
  // Alter the mymodule_text field to use a custom class.
  if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
    $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
  }
}

/**
 * Provides field definitions for a specific bundle within an entity type.
 *
 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
 *   The entity type definition.
 * @param string $bundle
 *   The bundle.
 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions
 *   The list of base field definitions for the entity type.
 *
 * @return \Drupal\Core\Field\FieldDefinitionInterface[]
 *   An array of bundle field definitions, keyed by field name.
 *
 * @see hook_entity_base_field_info()
 * @see hook_entity_base_field_info_alter()
 * @see hook_entity_bundle_field_info_alter()
 * @see \Drupal\Core\Field\FieldDefinitionInterface
 * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions()
 */
function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  // Add a property only to nodes of the 'article' bundle.
  if ($entity_type->id() == 'node' && $bundle == 'article') {
    $fields = array();
    $fields['mymodule_text_more'] = FieldDefinition::create('string')
731 732 733
        ->setLabel(t('More text'))
        ->setComputed(TRUE)
        ->setClass('\Drupal\mymodule\EntityComputedMoreText');
734
    return $fields;
735 736 737 738
  }
}

/**
739
 * Alters bundle field definitions.
740
 *
741 742 743 744 745 746
 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
 *   The array of bundle field definitions.
 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
 *   The entity type definition.
 * @param string $bundle
 *   The bundle.
747
 *
748 749 750
 * @see hook_entity_base_field_info()
 * @see hook_entity_base_field_info_alter()
 * @see hook_entity_bundle_field_info()
751
 */
752 753
function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
  if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) {
754
    // Alter the mymodule_text field to use a custom class.
755
    $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
756 757
  }
}
758

759 760 761 762 763
/**
 * Alter entity operations.
 *
 * @param array $operations
 *   Operations array as returned by
764
 *   \Drupal\Core\Entity\EntityListBuilderInterface::getOperations().
765 766 767 768 769 770 771
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity on which the linked operations will be performed.
 */
function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) {
  $operations['translate'] = array(
    'title' => t('Translate'),
    'weight' => 50,
772
  ) + $entity->urlInfo('my-custom-link-template');
773 774
}

775 776 777
/**
 * Control access to fields.
 *
778
 * This hook is invoked from
779
 * \Drupal\Core\Entity\EntityAccessController::fieldAccess() to let modules
780
 * grant or deny operations on fields.
781 782 783
 *
 * @param string $operation
 *   The operation to be performed. See
784
 *   \Drupal\Core\Access\AccessibleInterface::access() for possible values.
785
 * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
786
 *   The field definition.
787
 * @param \Drupal\Core\Session\AccountInterface $account
788
 *   The user account to check.
789
 * @param \Drupal\Core\Field\FieldItemListInterface $items
790 791
 *   (optional) The entity field object on which the operation is to be
 *   performed.
792
 *
793
 * @return bool|null
794 795 796
 *   TRUE if access should be allowed, FALSE if access should be denied and NULL
 *   if the implementation has no opinion.
 */
797
function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Field\FieldItemListInterface $items = NULL) {
798
  if ($field_definition->getName() == 'field_of_interest' && $operation == 'edit') {
799 800 801 802 803
    return user_access('update field of interest', $account);
  }
}

/**
804
 * Alters the default access behavior for a given field.
805 806 807 808 809 810 811 812 813 814 815
 *
 * Use this hook to override access grants from another module. Note that the
 * original default access flag is masked under the ':default' key.
 *
 * @param array $grants
 *   An array of grants gathered by hook_entity_field_access(). The array is
 *   keyed by the module that defines the field's access control; the values are
 *   grant responses for each module (Boolean or NULL).
 * @param array $context
 *   Context array on the performed operation with the following keys:
 *   - operation: The operation to be performed (string).
816
 *   - field_definition: The field definition object
817
 *     (\Drupal\Core\Field\FieldDefinitionInterface)
818
 *   - account: The user account to check access for
819
 *     (Drupal\user\Entity\User).
820
 *   - items: (optional) The entity field items
821
 *     (\Drupal\Core\Field\FieldItemListInterface).
822 823
 */
function hook_entity_field_access_alter(array &$grants, array $context) {
824
  $field_definition = $context['field_definition'];
825
  if ($field_definition->getName() == 'field_of_interest' && $grants['node'] === FALSE) {
826 827 828 829 830 831 832 833
    // Override node module's restriction to no opinion. We don't want to
    // provide our own access hook, we only want to take out node module's part
    // in the access handling of this field. We also don't want to switch node
    // module's grant to TRUE, because the grants of other modules should still
    // decide on their own if this field is accessible or not.
    $grants['node'] = NULL;
  }
}