Entity adapter
Part of the Entity ecosystem · 227 projects
Entity Adapter attaches domain-specific behavior to entities without subclassing them, overriding entity classes, or collecting helper functions in a .module file.
An adapter is a plain PHP class that declares which class it adapts and which interface it exposes:
#[AsEntityAdapter(entity: UserInterface::class, interface: UserWithGroupsInterface::class)]
final class UserWithGroups implements UserWithGroupsInterface, ObjectAdapterInterface {
public function getGroups(): array {
return array_column($this->user->get('field_groups')->getValue(), 'value');
}
}
Calling code asks for the interface instead of reaching into the entity:
$groups = $this->adapterManager
->adapt($user, UserWithGroupsInterface::class)
->getGroups();
Callers depend on UserWithGroupsInterface. They do not need to know which field holds the groups, which bundle carries it, or how the value is derived. Change that in the adapter and the callers stay untouched.
How it works
Adapters are discovered at container compile time from the src/Entity/Adapter/ directory of every module. There is no plugin manager, no annotation discovery, and no registration hook. A new adapter is picked up on the next cache rebuild.
- Adapters are autowired services, so they can inject anything else in the container.
- Each adapt() call returns a fresh instance, so an adapter can hold per-object state safely.
- The entity argument accepts a class or an interface and is matched with instanceof. Registering against NodeInterface covers every node class.
- Any object works, not only content entities. Menu link content, config entities, and plain value objects are all valid subjects.
- A class can expose as many interfaces as you need, one adapter per interface.
When it helps
Use it when the same question gets asked about an entity in several places: "does this member have a visible detail page", "which groups can edit this node", "what is this paragraph's spacing class". Each answer becomes one named interface with one implementation, instead of a computed field, a preprocess function, and a Twig condition that drift apart.
Requirements
Drupal 11 and PHP 8.3. No dependencies outside core.
Depends on
Dependencies of the latest stable release
No dependencies recorded for this project.
Required by
Tracked projects that depend on this one
No tracked projects depend on this one yet.
More in the Entity ecosystem
Most installed first