@berdir has written a very rich and concise documentation of Drupal's Entity API. The documentation reviews the main aspects of the well-known "Entity API", covering CRUD operations, field manipulation in entities, revisions, translations, entity models in PHP and Twig, and the internal functioning of content entities.
https://berdir.github.io/entities-explained/#/5/11
Below, we summarize the main points for developers already using the Entity API. These cover:
- The names of generic properties and methods;
- Methods on content entities;
- Use of the loadByProperties() function;
- Revisions;
- Entity translation;
- The bundle class.
Names of generic properties and methods
$node->get('title')->value = $node->get('title')->get('value')->getValue()≠
$node->get('title')->getValue()-------------------------
// ->entity on entity reference fields is the target.
$user->get('roles')->entity == $role;
// ->getEntity() is the host/parent entity.
$user->get('roles')->getEntity() == $user;Magic methods on content entities
// __get()/__set() support non-fields, get() does not:
$node->foo = 'bar';
// throws an exception:
$node->set('foo', 'bar');
// Various "API"s in rely on this behavior at the moment:
$entity->original, $entity->view, $entity->_referringItem;For more information: https://www.drupal.org/project/drupal/issues/3281720
Using the loadByProperties() function
To load entities, it is strongly recommended to avoid using the loadByProperties() function, which, according to its definition, does not perform access control on the entity.
Matt Glaman suggests clarifying in Drupal's official documentation when and how the loadByProperties() function should be used. This information would be particularly helpful for developers upgrading from Drupal 7 to Drupal 8/9.
https://twitter.com/nmdmatt/status/1514002594083098629 and https://mglaman.dev/blog/avoid-using-loadbyproperties-load-entities
In any case, starting from Drupal 9.2.X, it is preferable to use Entity Queries (\Drupal::entityQuery(ENTITY_TYPE)), which allow access control to be specified (https://www.drupal.org/node/3201242).
Revisions
@berdir’s documentation specifies that:
- The contents of entities can be revisionable;
- An entity always has a default revision;
- An entity can be saved as a new revision;
- A new revision can be either the new default revision or not, in which case it is a pending revision (draft).
// Get the current revision ID.
$entity->getRevisionId();
// Is/was the default revision or is latest revision.
$entity->isDefaultRevision();
$entity->wasDefaultRevision();
$entity->isLatestRevision();
// Set a new non-default revision.
$entity->setNewRevision(TRUE);
$entity->isDefaultRevision(FALSE);
$entity->save();In Drupal's back office, creating new revisions on each save is enforced. In code, by default, unless you change the Sync parameter, the behavior is the same:
$entity-> setSyncing(TRUE), in this case, you save the current revision (being edited).
An interesting topic to explore would be enabling the creation of “Workspaces”. This interface could allow you to view the whole site in a state where entities are at a specific revision version. It would then be appropriate to allow all these latest revisions to be published at once.
Note - Best method to get a translation, falling back to the default content if the former isn't available:
$er = \Drupal::service('entity.repository');
$translation = $er->getTranslationFromContext($entity, 'de');Revisions and their translations
@berdir’s documentation also states that:
- Each revision contains all existing translations and their values;
- Revisions track the languages that have been modified within them;
- When merging changes, only one translation can be modified in a given revision;
- New pending translation revisions are based on the default revision of the published language.
The bundle class
@berdir’s tutorial shows that:
- The bundle class allows defining a unique class for each entity bundle to be used in place of the default entity class;
- The bundle class is useful for distributing business logic, including in twig templates;
- The bundle class must extend the entity class;
- Drush 11 comes with a generator to create the base structure and required hook.
For more information: https://www.drupal.org/node/3191609
Finally, since we're all in the same boat, here are the main links to resources available for the Entity API:
https://www.drupal.org/docs/drupal-apis/entity-api
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Entity!entity.api.php/group/entity_api