Entity Subclasses
February 03, 2025
I don't know when but Drupal 8 or 9 released entity subclasses. This has been one of the single best improvements to developer experience for me.
Here are the benefits that I see:
Easily navigate getters and setters for fields
Previously with magic method, you could call the field and methods associated with it:
$user = $node->field_user->referencedEntity()[0]
Problems:
- field_user might not exist on the node. Okay, easy fix.
if ($node->hasField('field_user')) {
$user = $node->field_user->referencedEntity()[0]
}
- The field might be empty. Okay, here's the fix:
if ($node->hasField('field_user') && !$node->field_user->isEmpty()) {
$user $user = $node->field_user->referencedEntity()[0]
}
- We don't know entity type is returned. Okay, okay... Easy enough fix again...
if ($node->hasField('field_user') && !$node->field_user->isEmpty()) {
/** @var \Drupal\user\Entity\User $user */
$user = $node->field_user->referencedEntity()[0]
}
Now, let's do that all over the code base...
Or, we could subclass the entity, Let's say this entity is a Blog.
class Blog extends Node implements NodeInterface {
const FIELD_USER = 'field_user'
/**
* Whether or not the blog has a user.
*
* @return bool
* Boolean Indicator.
*/
public function hasUser(): bool {
return !$this->get(FIELD_USER)->isEmpty()
}
/**
* Get the user, if one exists.
*
* @return ?CustomUser
* Custom user, if exists
*/
public function getUser(): ?CustomUser {
return $this->hasUser() ? $this->get(FIELD_USER)->referencedEntity()[0] : NULL;
}
...
}
Here are some benefits:
- Looking for usages of the field, is simply looking for usages of the methods.
- It is extremely DRY. Any time you need to access the information, you have the methods in place.
- For me, I don't use the hasField() method often because I tend to know if my node type has the field, but I do use
$node instanceof Blog
all the time now because it typehints what methods and fields my node or entity has.
Other tacked on benefits:
- Centralizes logic around the entity.
- Less reliance on multiple hooks in disparate modules
- Testing becomes centralized around the entity as well.
To learn more about entity subclasses: https://www.drupal.org/node/3191609
Or ask ChatGPT