Working with the Entity API

Last updated on
19 February 2024

This documentation needs work. See "Help improve this page" in the sidebar.

This page covers the generic entity API methods.

  • Entity::create()
  • Entity::load()
  • Entity::save()
  • Entity::id()
  • Entity::bundle()
  • Entity::isNew()
  • Entity::label()

More specific API methods will be covered in specific chapters. (@todo Add a link to those pages once created.)

Some online guides still use\Drupal::entityManager(), but it is deprecated in Drupal 8.x and removed in Drupal 9.x. \Drupal::entityTypeManager() must be instead used.

Check if an object is an entity or a content entity

// Make sure that an object is an entity.
if ($entity instanceof \Drupal\Core\Entity\EntityInterface) {
}

// Make sure it's a content entity.
if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface) {
}
// or:
if ($entity->getEntityType()->getGroup() == 'content') {
}

// Get the entity type or the entity type ID.
$entity->getEntityType();
$entity->getEntityTypeId();

// Make sure it's a node.
if ($entity instanceof \Drupal\node\NodeInterface) {
}

// Using entityType() works better when the needed entity type is dynamic.
$needed_type = 'node';
if ($entity->getEntityTypeId() == $needed_type) {
}

Get information from entity methods

A number of generic methods are available to get information from an entity, for example the ID, bundle, and the revision ID. The documentation for the EntityInterface class lists some of those methods.

// Get the ID.
$entity->id();

// Get the bundle.
$entity->bundle();

// Check if the entity is new.
$entity->isNew();

// Get the label of an entity. Replacement for entity_label().
$entity->label();

// Get the URL object for an entity.
$entity->toUrl();

// Get internal path, path alias if exists, for an entity.
$entity->toUrl()->toString();

// Create a duplicate that can be saved as a new entity.
$duplicate = $entity->createDuplicate();

Create an entity object

// Use the entity type manager (recommended).
$node = \Drupal::entityTypeManager()->getStorage('node')->create(['type' => 'article', 'title' => 'Another node']);


// You can use the static create() method if you know the entity class.
$node = Node::create([
  'type' => 'article',
  'title' => 'The node title',
]);

Setting defaults from the field type annotation are only added for the missing top level keys; no deep merge is performed.

Avoid using the static Entity::create() method in object oriented code. Instead, use dependency injection to inject the entity type manager and create the entity with $this->entityTypeManager->getStorage($entity_type)->create(). This ensures that the code is properly decoupled and can be unit-tested.

For discoverability within an IDE, you can assign the entity storage interface to a property as well.  For example, $this->nodeStorage = $this->entityTypeManager->getStorage('node'); To create an entity, you can then use $this->nodeStorage->create().

Load an entity from the database

To update an entity, load it and then save it with your changes.

// Using the storage controller (recommended).
$entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load(1);

// Use the static method
$node = Node::load(1);

// Load multiple entities, also exists as entity_load_multiple().
$entities = \Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple([1, 2, 3]);

// Load entities by their property values.
$entities = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => 'article']);

Avoid using the static Entity::load() method in object oriented code. Instead use dependency injection to inject the entity type manager and load the entity with $this->entityTypeManager->getStorage($entity_type)->load($entity_id). This ensures that the code is properly decoupled and can be unit tested.

Save an entity object

// To save an entity.
$entity->save();

That works for both new and existing entities. The entity itself keeps track whether it's new or not. By default, for content entities, that depends on whether it has an ID or not. To save an entity that has an ID as a new entity (for example, when importing entities), the enforceIsNew() method can be used.

// The following will attempt to insert a new node with the ID 5, this will fail if that node already exists.
$node->nid->value = 5;
$node->enforceIsNew(TRUE);
$node->save();

Delete an entity from the database

// Delete a single entity.
$entity = \Drupal::entityTypeManager()->getStorage('node')->load(1);
$entity->delete();

// Delete multiple entities at once.
\Drupal::entityTypeManager()->getStorage($entity_type)->delete([$id1 => $entity1, $id2 => $entity2]);

Query the database for entities matching some conditions

$nodeStorage = \Drupal::entityTypeManager()->getStorage('node');
    
$ids = $nodeStorage->getQuery()
  ->condition('status', 1)
  ->condition('type', 'article') // type = bundle id (machine name)
  //->sort('created', 'ASC') // sorted by time of creation
  //->pager(15) // limit 15 items
  ->accessCheck(TRUE) // or FALSE
  ->execute();

$articles = $nodeStorage->loadMultiple($ids);

Checking if a user account has access to an entity object

The access() method can be used to check who can do what with an entity. The method supports different operations, the standard operations are view, update, delete and create.

Access checks are forwarded to the access controller.

// Check view access of an entity.
// This defaults to check access for the currently logged in user.
if ($entity->access('view')) {
  // The entity can be viewed.
}

// Check if a given user can delete an entity.
if ($entity->access('delete', $account)) {
  // The entity  can be deleted.
}

When checking for the create access, there is usually no entity yet. Creating one just to check if someone would be able to create it is a costly operation. Therefore, create access for those should be checked directly on the access controller.

\Drupal::entityTypeManager()->getAccessControlHandler('node')->createAccess('article');

If there is already an entity, $entity->access('create') works too, which just forwards to the createAccess() method, the same way other operations forward to the access() method on the access controller.

Help improve this page

Page status: Needs work

You can: