entity.inc 31 KB
Newer Older
1 2 3 4 5 6 7
<?php

/**
 * @file
 * Entity API for handling entities like nodes or users.
 */

8
use Drupal\Core\Cache\CacheBackendInterface;
9 10
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityInterface;
11
use Drupal\Core\Language\Language;
12 13

/**
14
 * Gets the entity definition for an entity type.
15
 *
16 17 18 19 20 21 22 23
 * @param string|null $entity_type
 *   (optional) The entity type (e.g. 'node'). Leave NULL to retrieve
 *   information for all entity types.
 *
 * @return array
 *   An array containing the entity type's definition, as retrieved with
 *   \Drupal\Core\Entity\EntityManager. If $entity_type is NULL, an associative
 *   array of all entity type definitions keyed by entity type is returned.
24
 *
25
 * @see \Drupal\Core\Entity\EntityManager
26
 * @see hook_entity_info_alter()
27 28
 *
 * @deprecated Use \Drupal\Core\Entity\EntityManager::getDefinitions() directly.
29 30 31
 */
function entity_get_info($entity_type = NULL) {
  if (empty($entity_type)) {
32
    return \Drupal::entityManager()->getDefinitions();
33
  }
34
  else {
35
    return \Drupal::entityManager()->getDefinition($entity_type);
36 37 38 39 40 41 42
  }
}

/**
 * Resets the cached information about entity types.
 */
function entity_info_cache_clear() {
43
  drupal_static_reset('entity_get_view_modes');
44
  // Clear all languages.
45 46
  \Drupal::entityManager()->clearCachedDefinitions();
  \Drupal::entityManager()->clearCachedFieldDefinitions();
47 48
}

49 50 51 52 53 54 55 56 57 58 59 60
/**
 * Clears the entity render cache for all entity types.
 */
function entity_render_cache_clear() {
  $entity_manager = Drupal::entityManager();
  foreach ($entity_manager->getDefinitions() as $entity_type => $info) {
    if ($entity_manager->hasController($entity_type, 'render')) {
      $entity_manager->getRenderController($entity_type)->resetCache();
    }
  }
}

61
/**
62
 * Returns the entity bundle info.
63
 *
64 65 66 67 68 69
 * @param string|null $entity_type
 *   The entity type whose bundle info should be returned, or NULL for all
 *   bundles info. Defaults to NULL.
 *
 * @return array
 *   The bundle info for a specific entity type, or all entity types.
70 71 72
 *
 * @see \Drupal\Core\Entity\EntityManager::getBundleInfo()
 * @see \Drupal\Core\Entity\EntityManager::getAllBundleInfo()
73 74
 */
function entity_get_bundles($entity_type = NULL) {
75
  if (isset($entity_type)) {
76
    return \Drupal::entityManager()->getBundleInfo($entity_type);
77
  }
78
  else {
79
    return \Drupal::entityManager()->getAllBundleInfo();
80 81 82
  }
}

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/**
 * Notifies modules about an operation that was performed on a entity bundle.
 *
 * @param string $hook
 *   One of 'create', 'rename' or 'delete'.
 * @param string $entity_type
 *   The entity type to which the bundle is bound.
 * @param string $bundle
 *   The name of the bundle on which the operation was performed.
 * @param string|null $bundle_new
 *   The new name of the bundle in case of a 'rename' operation. Defaults to
 *   NULL.
 */
function entity_invoke_bundle_hook($hook, $entity_type, $bundle, $bundle_new = NULL) {
  entity_info_cache_clear();
98 99 100

  // Notify the entity storage controller.
  $method = 'onBundle' . ucfirst($hook);
101 102 103 104
  $storage_controller = \Drupal::entityManager()->getStorageController($entity_type);
  if (method_exists($storage_controller, $method)) {
    $storage_controller->$method($bundle, $bundle_new);
  }
105
  // Invoke hook_entity_bundle_*() hooks.
106
  \Drupal::moduleHandler()->invokeAll('entity_bundle_' . $hook, array($entity_type, $bundle, $bundle_new));
107 108
}

109 110 111 112 113 114 115 116 117 118 119 120 121
/**
 * Returns the entity form mode info.
 *
 * @param string|null $entity_type
 *   The entity type whose form mode info should be returned, or NULL for all
 *   form mode info. Defaults to NULL.
 *
 * @return array
 *   The form mode info for a specific entity type, or all entity types.
 */
function entity_get_form_modes($entity_type = NULL) {
  $form_modes = &drupal_static(__FUNCTION__);
  if (!$form_modes) {
122
    $langcode = language(Language::TYPE_INTERFACE)->id;
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    if ($cache = cache()->get("entity_form_mode_info:$langcode")) {
      $form_modes = $cache->data;
    }
    else {
      $form_modes = array();
      foreach (entity_load_multiple('form_mode') as $form_mode) {
        list($form_mode_entity_type, $form_mode_name) = explode('.', $form_mode->id(), 2);
        $form_modes[$form_mode_entity_type][$form_mode_name] = (array) $form_mode;
      }
      drupal_alter('entity_form_mode_info', $form_modes);
      cache()->set("entity_form_mode_info:$langcode", $form_modes, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
    }
  }

  if (empty($entity_type)) {
    return $form_modes;
  }
  elseif (isset($form_modes[$entity_type])) {
    return $form_modes[$entity_type];
  }

  return array();
}

147 148 149 150 151 152
/**
 * Returns the entity view mode info.
 *
 * @param string|null $entity_type
 *   The entity type whose view mode info should be returned, or NULL for all
 *   view mode info. Defaults to NULL.
153 154
 *
 * @return array
155
 *   The view mode info for a specific entity type, or all entity types.
156
 */
157 158 159
function entity_get_view_modes($entity_type = NULL) {
  $view_modes = &drupal_static(__FUNCTION__);
  if (!$view_modes) {
160
    $langcode = language(Language::TYPE_INTERFACE)->id;
161 162 163 164
    if ($cache = cache()->get("entity_view_mode_info:$langcode")) {
      $view_modes = $cache->data;
    }
    else {
165 166 167 168
      $view_modes = array();
      foreach (entity_load_multiple('view_mode') as $view_mode) {
        list($view_mode_entity_type, $view_mode_name) = explode('.', $view_mode->id(), 2);
        $view_modes[$view_mode_entity_type][$view_mode_name] = (array) $view_mode;
169 170 171 172 173 174 175 176 177 178 179 180 181 182
      }
      drupal_alter('entity_view_mode_info', $view_modes);
      cache()->set("entity_view_mode_info:$langcode", $view_modes, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
    }
  }

  if (empty($entity_type)) {
    return $view_modes;
  }
  elseif (isset($view_modes[$entity_type])) {
    return $view_modes[$entity_type];
  }

  return array();
183 184
}

185
/**
186 187 188 189
 * Loads an entity from the database.
 *
 * @param string $entity_type
 *   The entity type to load, e.g. node or user.
190
 * @param mixed $id
191 192 193 194
 *   The id of the entity to load.
 * @param bool $reset
 *   Whether to reset the internal cache for the requested entity type.
 *
195
 * @return Drupal\Core\Entity\EntityInterface
196
 *   The entity object, or NULL if there is no entity with the given id.
197
 *
198
 * @see \Drupal\Core\Entity\EntityManager
199 200 201
 * @see \Drupal\Core\Entity\EntityStorageControllerInterface
 * @see \Drupal\Core\Entity\DatabaseStorageController
 * @see \Drupal\Core\Entity\Query\QueryInterface
202 203
 */
function entity_load($entity_type, $id, $reset = FALSE) {
204
  $controller = \Drupal::entityManager()->getStorageController($entity_type);
205 206 207 208
  if ($reset) {
    $controller->resetCache(array($id));
  }
  return $controller->load($id);
209 210
}

211 212 213 214 215 216 217 218
/**
 * Loads an entity from the database.
 *
 * @param string $entity_type
 *   The entity type to load, e.g. node or user.
 * @param int $revision_id
 *   The id of the entity to load.
 *
219
 * @return Drupal\Core\Entity\EntityInterface
220 221 222
 *   The entity object, or FALSE if there is no entity with the given revision
 *   id.
 *
223
 * @see \Drupal\Core\Entity\EntityManager
224 225
 * @see \Drupal\Core\Entity\EntityStorageControllerInterface
 * @see \Drupal\Core\Entity\DatabaseStorageController
226 227
 */
function entity_revision_load($entity_type, $revision_id) {
228
  return \Drupal::entityManager()
229 230
    ->getStorageController($entity_type)
    ->loadRevision($revision_id);
231 232
}

233
/**
234
 * Deletes an entity revision.
235 236 237 238 239 240 241
 *
 * @param string $entity_type
 *   The entity type to load, e.g. node or user.
 * @param $revision_id
 *   The revision ID to delete.
 */
function entity_revision_delete($entity_type, $revision_id) {
242
  \Drupal::entityManager()
243 244
    ->getStorageController($entity_type)
    ->deleteRevision($revision_id);
245 246
}

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
/**
 * Loads an entity by UUID.
 *
 * Note that some entity types may not support UUIDs.
 *
 * @param string $entity_type
 *   The entity type to load; e.g., 'node' or 'user'.
 * @param string $uuid
 *   The UUID of the entity to load.
 * @param bool $reset
 *   Whether to reset the internal cache for the requested entity type.
 *
 * @return EntityInterface|FALSE
 *   The entity object, or FALSE if there is no entity with the given UUID.
 *
262
 * @throws Drupal\Core\Entity\EntityStorageException
263 264
 *   Thrown in case the requested entity type does not support UUIDs.
 *
265
 * @see \Drupal\Core\Entity\EntityManager
266 267 268
 */
function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) {
  $entity_info = entity_get_info($entity_type);
269
  if (empty($entity_info['entity_keys']['uuid'])) {
270 271
    throw new EntityStorageException("Entity type $entity_type does not support UUIDs.");
  }
272
  $uuid_key = $entity_info['entity_keys']['uuid'];
273

274
  $controller = \Drupal::entityManager()->getStorageController($entity_type);
275 276 277
  if ($reset) {
    $controller->resetCache();
  }
278 279
  $entities = $controller->loadByProperties(array($uuid_key => $uuid));
  return reset($entities);
280 281
}

282 283
/**
 * Loads multiple entities from the database.
284 285 286 287 288 289
 *
 * This function should be used whenever you need to load more than one entity
 * from the database. The entities are loaded into memory and will not require
 * database access if loaded again during the same page request.
 *
 * The actual loading is done through a class that has to implement the
290 291
 * Drupal\Core\Entity\EntityStorageControllerInterface interface. By default,
 * Drupal\Core\Entity\DatabaseStorageController is used. Entity types can
292
 * specify that a different class should be used by setting the
293 294
 * "controllers['storage']" key in the entity plugin annotation. These classes
 * can either implement the Drupal\Core\Entity\EntityStorageControllerInterface
295 296
 * interface, or, most commonly, extend the
 * Drupal\Core\Entity\DatabaseStorageController class.
297
 * See Drupal\node\Entity\Node and Drupal\node\NodeStorageController
298
 * for an example.
299
 *
300
 * @param string $entity_type
301
 *   The entity type to load, e.g. node or user.
302 303
 * @param array $ids
 *   (optional) An array of entity IDs. If omitted, all entities are loaded.
304
 * @param bool $reset
305 306
 *   Whether to reset the internal cache for the requested entity type.
 *
307
 * @return array
308 309
 *   An array of entity objects indexed by their ids.
 *
310
 * @see \Drupal\Core\Entity\EntityManager
311 312 313
 * @see \Drupal\Core\Entity\EntityStorageControllerInterface
 * @see \Drupal\Core\Entity\DatabaseStorageController
 * @see \Drupal\Core\Entity\Query\QueryInterface
314
 */
315
function entity_load_multiple($entity_type, array $ids = NULL, $reset = FALSE) {
316
  $controller = \Drupal::entityManager()->getStorageController($entity_type);
317
  if ($reset) {
318
    $controller->resetCache($ids);
319
  }
320
  return $controller->loadMultiple($ids);
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
}

/**
 * Load entities by their property values.
 *
 * @param string $entity_type
 *   The entity type to load, e.g. node or user.
 * @param array $values
 *   An associative array where the keys are the property names and the
 *   values are the values those properties must have.
 *
 * @return array
 *   An array of entity objects indexed by their ids.
 */
function entity_load_multiple_by_properties($entity_type, array $values) {
336
  return \Drupal::entityManager()
337 338
    ->getStorageController($entity_type)
    ->loadByProperties($values);
339 340 341 342 343 344 345 346 347 348 349 350 351
}

/**
 * Loads the unchanged, i.e. not modified, entity from the database.
 *
 * Unlike entity_load() this function ensures the entity is directly loaded from
 * the database, thus bypassing any static cache. In particular, this function
 * is useful to determine changes by comparing the entity being saved to the
 * stored entity.
 *
 * @param $entity_type
 *   The entity type to load, e.g. node or user.
 * @param $id
352
 *   The ID of the entity to load.
353 354 355 356 357
 *
 * @return
 *   The unchanged entity, or FALSE if the entity cannot be loaded.
 */
function entity_load_unchanged($entity_type, $id) {
358
  return \Drupal::entityManager()
359 360
    ->getStorageController($entity_type)
    ->loadUnchanged($id);
361 362
}

363 364 365
/**
 * Deletes multiple entities permanently.
 *
366
 * @param string $entity_type
367
 *   The type of the entity.
368
 * @param array $ids
369 370
 *   An array of entity IDs of the entities to delete.
 */
371
function entity_delete_multiple($entity_type, array $ids) {
372
  $controller = \Drupal::entityManager()->getStorageController($entity_type);
373
  $entities = $controller->loadMultiple($ids);
374
  $controller->delete($entities);
375 376 377
}

/**
378
 * Constructs a new entity object, without permanently saving it.
379 380 381 382 383 384 385
 *
 * @param $entity_type
 *   The type of the entity.
 * @param $values
 *   An array of values to set, keyed by property name. If the entity type has
 *   bundles the bundle key has to be specified.
 *
386
 * @return Drupal\Core\Entity\EntityInterface
387 388 389
 *   A new entity object.
 */
function entity_create($entity_type, array $values) {
390
  return \Drupal::entityManager()
391 392
    ->getStorageController($entity_type)
    ->create($values);
393 394
}

395 396
/**
 * Gets the entity controller class for an entity type.
397
 *
398
 * @return Drupal\Core\Entity\EntityStorageControllerInterface
399 400
 *
 * @deprecated Use \Drupal\Core\Entity\EntityManager::getStorageController().
401 402
 */
function entity_get_controller($entity_type) {
403
  return \Drupal::entityManager()
404
    ->getStorageController($entity_type);
405 406 407 408 409
}

/**
 * Returns the label of an entity.
 *
410
 * This is a wrapper for Drupal\Core\Entity\EntityInterface::label(). This function
411
 * should only be used as a callback, e.g. for menu title callbacks.
412
 *
413
 * @param Drupal\Core\Entity\EntityInterface $entity
414
 *   The entity for which to generate the label.
415 416 417 418
 * @param $langcode
 *   (optional) The language code of the language that should be used for
 *   getting the label. If set to NULL, the entity's default language is
 *   used.
419 420
 *
 * @return
421
 *   The label of the entity, or NULL if there is no label defined.
422
 *
423
 * @see Drupal\Core\Entity\EntityInterface::label()
424
 */
425 426
function entity_page_label(EntityInterface $entity, $langcode = NULL) {
  return $entity->label($langcode);
427 428
}

429 430 431 432 433 434 435 436 437
/**
 * Returns the entity access controller for the given entity type.
 *
 * @param string $entity_type
 *   The type of the entity.
 *
 * @return \Drupal\Core\Entity\EntityAccessControllerInterface
 *   An entity access controller instance.
 *
438
 * @deprecated Use \Drupal\Core\Entity\EntityManager::getRenderController().
439 440
 */
function entity_access_controller($entity_type) {
441
  return \Drupal::entityManager()
442
    ->getAccessController($entity_type);
443 444
}

445
/**
446 447 448 449 450 451 452 453
 * Returns an entity form controller for the given operation.
 *
 * Since there might be different scenarios in which an entity is edited,
 * multiple form controllers suitable to the different operations may be defined.
 * If no controller is found for the default operation, the base class will be
 * used. If a non-existing non-default operation is specified an exception will
 * be thrown.
 *
454
 * @see \Drupal\Core\Entity\EntityManager
455 456 457 458 459 460 461 462
 *
 * @param $entity_type
 *   The type of the entity.
 * @param $operation
 *   (optional) The name of an operation, such as creation, editing or deletion,
 *   identifying the controlled form. Defaults to 'default' which is the usual
 *   create/edit form.
 *
463
 * @return Drupal\Core\Entity\EntityFormControllerInterface
464
 *   An entity form controller instance.
465 466
 *
 * @deprecated Use \Drupal\Core\Entity\EntityManager::getFormController().
467 468
 */
function entity_form_controller($entity_type, $operation = 'default') {
469
  return \Drupal::entityManager()
470
    ->getFormController($entity_type, $operation);
471 472 473 474 475 476 477 478 479 480 481 482 483
}

/**
 * Returns the default form state for the given entity and operation.
 *
 * @param EntityInterface $entity
 *   The entity to be created or edited.
 * @param $operation
 *   (optional) The operation identifying the form to be processed.
 *
 * @return
 *   A $form_state array already filled the entity form controller.
 */
484
function entity_form_state_defaults(EntityInterface $entity, $operation = 'default') {
485
  $form_state = array();
486
  $controller = \Drupal::entityManager()->getFormController($entity->entityType(), $operation);
487 488 489 490
  $controller->setEntity($entity);
  $form_state['build_info']['callback_object'] = $controller;
  $form_state['build_info']['base_form_id'] = $controller->getBaseFormID();
  $form_state['build_info']['args'] = array();
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
  return $form_state;
}

/**
 * Retrieves, populates, and processes an entity form.
 *
 * @param EntityInterface $entity
 *   The entity to be created or edited.
 * @param $operation
 *   (optional) The operation identifying the form to be submitted.
 * @param $form_state
 *   (optional) A keyed array containing the current state of the form.
 *
 * @return
 *   A $form_state array already filled with the entity form controller.
 */
function entity_form_submit(EntityInterface $entity, $operation = 'default', &$form_state = array()) {
  $form_state += entity_form_state_defaults($entity, $operation);
509
  $form_id = $form_state['build_info']['callback_object']->getFormID();
510 511 512 513 514 515 516 517 518 519
  drupal_form_submit($form_id, $form_state);
}

/**
 * Returns the built and processed entity form for the given entity.
 *
 * @param EntityInterface $entity
 *   The entity to be created or edited.
 * @param $operation
 *   (optional) The operation identifying the form variation to be returned.
520 521 522 523 524 525 526
 * @param array $form_state
 *   (optional) An associative array containing the current state of the form.
 *   Use this to pass additional information to the form, such as the langcode.
 *   @code
 *   $form_state['langcode'] = $langcode;
 *   $form = entity_get_form($entity, 'default', $form_state);
 *   @endcode
527 528 529
 *
 * @return
 *   The processed form for the given entity and operation.
530
 *
531
 * @deprecated Use \Drupal::entityManager()->getForm() or _entity_form from a
532
 *   routing.yml file instead of a page callback.
533
 */
534
function entity_get_form(EntityInterface $entity, $operation = 'default', array $form_state = array()) {
535
  return \Drupal::entityManager()->getForm($entity, $operation, $form_state);
536 537 538
}

/**
539
 * Copies submitted values to entity properties for simple entity forms.
540 541 542 543 544 545 546 547 548
 *
 * During the submission handling of an entity form's "Save", "Preview", and
 * possibly other buttons, the form state's entity needs to be updated with the
 * submitted form values. Each entity form implements its own builder function
 * for doing this, appropriate for the particular entity and form, whereas
 * modules may specify additional builder functions in $form['#entity_builders']
 * for copying the form values of added form elements to entity properties.
 * Many of the main entity builder functions can call this helper function to
 * re-use its logic of copying $form_state['values'][PROPERTY] values to
549 550 551 552
 * $entity->PROPERTY for all entries in $form_state['values'] that are not
 * field data, and calling field_attach_extract_form_values() to copy field
 * data. Apart from that this helper invokes any additional builder functions
 * that have been specified in $form['#entity_builders'].
553 554 555 556 557 558
 *
 * For some entity forms (e.g., forms with complex non-field data and forms that
 * simultaneously edit multiple entities), this behavior may be inappropriate,
 * so the builder function for such forms needs to implement the required
 * functionality instead of calling this function.
 */
559
function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state, array $options = array()) {
560 561 562 563
  $info = entity_get_info($entity_type);

  // Copy top-level form values that are not for fields to entity properties,
  // without changing existing entity properties that are not being edited by
564 565
  // this form. Copying field values must be done using
  // field_attach_extract_form_values().
566
  $values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $entity->bundle())) : $form_state['values'];
567
  foreach ($values_excluding_fields as $key => $value) {
568
    $entity->set($key, $value);
569 570 571 572 573
  }

  // Invoke all specified builders for copying form values to entity properties.
  if (isset($form['#entity_builders'])) {
    foreach ($form['#entity_builders'] as $function) {
574
      call_user_func_array($function, array($entity_type, $entity, &$form, &$form_state));
575 576 577 578 579
    }
  }

  // Copy field values to the entity.
  if ($info['fieldable']) {
580
    field_attach_extract_form_values($entity, $form, $form_state, $options);
581 582
  }
}
583 584 585 586 587 588 589 590 591 592

/**
 * Returns an entity list controller for a given entity type.
 *
 * @param string $entity_type
 *   The type of the entity.
 *
 * @return Drupal\Core\Entity\EntityListControllerInterface
 *   An entity list controller.
 *
593
 * @deprecated Use \Drupal\Core\Entity\EntityManager::getFormController().
594 595
 */
function entity_list_controller($entity_type) {
596
  return \Drupal::entityManager()
597
    ->getListController($entity_type);
598
}
599 600 601 602 603 604 605 606 607 608

/**
 * Returns an entity render controller for a given entity type.
 *
 * @param string $entity_type
 *   The type of the entity.
 *
 * @return Drupal\Core\Entity\EntityRenderControllerInterface
 *   An entity render controller.
 *
609
 * @deprecated Use \Drupal\Core\Entity\EntityManager::getFormController().
610 611
 */
function entity_render_controller($entity_type) {
612
  return \Drupal::entityManager()
613
    ->getRenderController($entity_type);
614 615 616 617 618 619 620 621 622 623 624 625
}

/**
 * Returns the render array for an entity.
 *
 * @param Drupal\Core\Entity\EntityInterface $entity
 *   The entity to be rendered.
 * @param string $view_mode
 *   The view mode that should be used to display the entity.
 * @param string $langcode
 *   (optional) For which language the entity should be rendered, defaults to
 *   the current content language.
626 627 628
 * @param bool $reset
 *   (optional) Whether to reset the render cache for the requested entity.
 *   Defaults to FALSE.
629 630 631 632
 *
 * @return array
 *   A render array for the entity.
 */
633 634 635 636 637 638
function entity_view(EntityInterface $entity, $view_mode, $langcode = NULL, $reset = FALSE) {
  $render_controller = \Drupal::entityManager()->getRenderController($entity->entityType());
  if ($reset) {
    $render_controller->resetCache(array($entity->id()));
  }
  return $render_controller->view($entity, $view_mode, $langcode);
639 640 641 642 643 644 645 646 647 648 649 650
}

/**
 * Returns the render array for the provided entities.
 *
 * @param array $entities
 *   The entities to be rendered, must be of the same type.
 * @param string $view_mode
 *   The view mode that should be used to display the entity.
 * @param string $langcode
 *   (optional) For which language the entity should be rendered, defaults to
 *   the current content language.
651 652 653
 * @param bool $reset
 *   (optional) Whether to reset the render cache for the requested entities.
 *   Defaults to FALSE.
654 655 656 657 658
 *
 * @return array
 *   A render array for the entities, indexed by the same keys as the
 *   entities array passed in $entities.
 */
659 660 661 662 663 664
function entity_view_multiple(array $entities, $view_mode, $langcode = NULL, $reset = FALSE) {
  $render_controller = \Drupal::entityManager()->getRenderController(reset($entities)->entityType());
  if ($reset) {
    $render_controller->resetCache(array_keys($entities));
  }
  return $render_controller->viewMultiple($entities, $view_mode, $langcode);
665
}
666

667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
/**
 * Returns the entity_display object associated to a bundle and view mode.
 *
 * Use this function when assigning suggested display options for a component
 * in a given view mode. Note that they will only be actually used at render
 * time if the view mode itself is configured to use dedicated display settings
 * for the bundle; if not, the 'default' display is used instead.
 *
 * The function reads the entity_display object from the current configuration,
 * or returns a ready-to-use empty one if configuration entry exists yet for
 * this bundle and view mode. This streamlines manipulation of display objects
 * by always returning a consistent object that reflects the current state of
 * the configuration.
 *
 * Example usage:
 * - Set the 'body' field to be displayed and the 'field_image' field to be
 *   hidden on article nodes in the 'default' display.
 * @code
685
 * entity_get_display('node', 'article', 'default')
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
 *   ->setComponent('body', array(
 *     'type' => 'text_summary_or_trimmed',
 *     'settings' => array('trim_length' => '200')
 *     'weight' => 1,
 *   ))
 *   ->removeComponent('field_image')
 *   ->save();
 * @endcode
 *
 * @param string $entity_type
 *   The entity type.
 * @param string $bundle
 *   The bundle.
 * @param string $view_mode
 *   The view mode, or 'default' to retrieve the 'default' display object for
 *   this bundle.
 *
703
 * @return \Drupal\entity\Entity\EntityDisplay
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
 *   The display object associated to the view mode.
 */
function entity_get_display($entity_type, $bundle, $view_mode) {
  // Try loading the display from configuration.
  $display = entity_load('entity_display', $entity_type . '.' . $bundle . '.' . $view_mode);

  // If not found, create a fresh display object. We do not preemptively create
  // new entity_display configuration entries for each existing entity type and
  // bundle whenever a new view mode becomes available. Instead, configuration
  // entries are only created when a display object is explicitly configured
  // and saved.
  if (!$display) {
    $display = entity_create('entity_display', array(
      'targetEntityType' => $entity_type,
      'bundle' => $bundle,
719
      'mode' => $view_mode,
720
      'status' => TRUE,
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
    ));
  }

  return $display;
}

/**
 * Returns the entity_display object used to render an entity.
 *
 * Depending on the configuration of the view mode for the bundle, this can be
 * either the display object associated to the view mode, or the 'default'
 * display.
 *
 * This function should only be used internally when rendering an entity. When
 * assigning suggested display options for a component in a given view mode,
 * entity_get_display() should be used instead, in order to avoid inadvertently
 * modifying the output of other view modes that might happen to use the
 * 'default' display too. Those options will then be effectively applied only
 * if the view mode is configured to use them.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity being rendered.
 * @param string $view_mode
 *  The view mode being rendered.
 *
746
 * @return \Drupal\entity\Entity\EntityDisplay
747 748
 *   The display object that should be used to render the entity.
 *
749
 * @see entity_get_display().
750 751 752 753
 */
function entity_get_render_display(EntityInterface $entity, $view_mode) {
  $entity_type = $entity->entityType();
  $bundle = $entity->bundle();
754 755 756 757 758 759 760 761 762 763 764 765 766 767
  $render_view_mode = 'default';

  // Look at the default display and display for the view mode, and fallback to
  // the former if the latter does not exist is disabled.
  if ($view_mode != 'default') {
    $ids = array(
      'default' => $entity_type . '.' . $bundle . '.default',
      $view_mode => $entity_type . '.' . $bundle . '.' . $view_mode,
    );
    $entity_displays = entity_load_multiple('entity_display', $ids);
    if (isset($entity_displays[$ids[$view_mode]]) && $entity_displays[$ids[$view_mode]]->status()) {
      $render_view_mode = $view_mode;
    }
  }
768 769

  $display = entity_get_display($entity_type, $bundle, $render_view_mode);
770
  $display->originalMode = $view_mode;
771 772

  return $display;
773
}
774

775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
/**
 * Returns the entity_form_display object associated to a bundle and form mode.
 *
 * The function reads the entity_form_display object from the current
 * configuration, or returns a ready-to-use empty one if configuration entry
 * exists yet for this bundle and form mode. This streamlines manipulation of
 * EntityFormDisplay objects by always returning a consistent object that
 * reflects the current state of the configuration.
 *
 * Example usage:
 * - Set the 'body' field to be displayed with the 'text_textarea_with_summary'
 *   widget and the 'field_image' field to be hidden on article nodes in the
 *  'default' form mode.
 * @code
 * entity_get_form_display('node', 'article', 'default')
 *   ->setComponent('body', array(
 *     'type' => 'text_textarea_with_summary',
 *     'weight' => 1,
 *   ))
 *   ->setComponent('field_image', array(
 *     'type' => 'hidden',
 *   ))
 *   ->save();
 * @endcode
 *
 * @param string $entity_type
 *   The entity type.
 * @param string $bundle
 *   The bundle.
 * @param string $form_mode
 *   The form mode.
 *
807
 * @return \Drupal\entity\Entity\EntityFormDisplay
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
 *   The EntityFormDisplay object associated to the form mode.
 */
function entity_get_form_display($entity_type, $bundle, $form_mode) {
  // Try loading the entity from configuration.
  $entity_form_display = entity_load('entity_form_display', $entity_type . '.' . $bundle . '.' . $form_mode);

  // If not found, create a fresh entity object. We do not preemptively create
  // new EntityFormDisplay configuration entries for each existing entity type
  // and bundle whenever a new form mode becomes available. Instead,
  // configuration entries are only created when a EntityFormDisplay object is
  // explicitly configured and saved.
  if (!$entity_form_display) {
    $entity_form_display = entity_create('entity_form_display', array(
      'targetEntityType' => $entity_type,
      'bundle' => $bundle,
      'mode' => $form_mode,
824
      'status' => TRUE,
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
    ));
  }

  return $entity_form_display;
}

/**
 * Returns the entity_form_display object used to render an entity form.
 *
 * This function should only be used internally when rendering an entity form.
 * When assigning suggested form display options for a component in a given form
 * mode, entity_get_form_display() should be used instead, in order to avoid
 * inadvertently modifying the output of other form modes that might happen to
 * use the 'default' form display too. Those options will then be effectively
 * applied only if the form mode is configured to use them.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity for which the form is being rendered.
 * @param string $form_mode
 *   The form mode being rendered.
 *
846
 * @return \Drupal\entity\Entity\EntityFormDisplay
847 848 849 850 851 852 853
 *   The form display object that should be used to render the entity form.
 *
 * @see entity_get_form_display().
 */
function entity_get_render_form_display(EntityInterface $entity, $form_mode) {
  $entity_type = $entity->entityType();
  $bundle = $entity->bundle();
854 855 856 857 858 859 860 861 862 863 864 865 866 867
  $render_form_mode = 'default';

  // Look at the default form display and form display for the view mode, and
  // fallback to the former if the latter does not exist is disabled.
  if ($form_mode != 'default') {
    $ids = array(
      'default' => $entity_type . '.' . $bundle . '.default',
      $form_mode => $entity_type . '.' . $bundle . '.' . $form_mode,
    );
    $entity_form_displays = entity_load_multiple('entity_form_display', $ids);
    if (isset($entity_form_displays[$ids[$form_mode]]) && $entity_form_displays[$ids[$form_mode]]->status()) {
      $render_form_mode = $form_mode;
    }
  }
868 869

  $form_display = entity_get_form_display($entity_type, $bundle, $render_form_mode);
870 871 872 873 874
  $form_display->originalMode = $form_mode;

  return $form_display;
}

875 876 877 878 879 880 881 882 883 884 885 886 887 888
/**
 * Generic access callback for entity pages.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity for which access is being checked.
 * @param string $operation
 *   (optional) The operation being performed on the entity. Defaults to 'view'.
 *
 * @return bool
 *   TRUE if the access is granted. FALSE if access is denied.
 */
function entity_page_access(EntityInterface $entity, $operation = 'view') {
  return $entity->access($operation);
}
889 890 891 892 893 894

/**
 * Generic access callback for create entity pages.
 *
 * @param string $entity_type
 *   The entity type.
895 896
 * @param string $bundle
 *   (optional) The bundle of the entity. Required if the entity supports
897
 *   bundles, defaults to NULL otherwise.
898 899 900 901
 *
 * @return bool
 *   TRUE if the access is granted. FALSE if access is denied.
 */
902
function entity_page_create_access($entity_type, $bundle = NULL) {
903
  return \Drupal::entityManager()->getAccessController($entity_type)->createAccess($bundle);
904
}