Module Description
Use Typed Entity as a namespace for your business logic. It provides a scope to place your business logic, and help you keep your global scope clean of myriads of small functions.

This module provides a simple way to treat you existing entities like typed objects. This will allow you to have a more maintainable and easier to debug codebase.

📖 Read the article (1) 📖 📹 Watch the video 📹 (4.x) 📖 Read the article (2) 📖 Make sure to check the example module to get inspiration on how to implement this on your code base.

Why this, instead of core's bundle classes Starting in Drupal 9.3 you can use custom bundle classes in Drupal core. However this approach falls short in several scenarios.

Read this article for more details.

Usage Whenever you find yourself writing custom code that accesses $node->field_lorem anywhere in your site (let's say a hook for the example) you can benefit from a wrapped entity. A wrapped entity is a custom class that encapsulates the code for a particular content type. The goal is that your hook no longer does $node->field_foo, but instead $article->doTheThingDependingOnFoo().

For each entity type and bundle you need to let the system know that you want a custom class for your entities of a certain type. For that you will register a plugin in your custom module under src/Plugin/TypedRepositories. Like this example:

/** * The repository for articles. * * @TypedRepository( * entity_type_id = "user", * wrappers = @ClassWithVariants( * fallback = "Drupal\my_module\WrappedEntities\User", * ), * description = @Translation("Repository that holds business logic applicable to all users.") * ) */ final class UserRepository extends TypedRepositoryBase {} With that you can start writing and testing Drupal\typed_entity_example\WrappedEntities\User. Now everytime you need to do things with a user in a hook (or elsewhere) you can do:

// You can inject the Repository Manager service in your services as well. $user = typed_entity_repository_manager()->wrap($user_entity); $user->doThatThingTheProjectNeeds(); Variants
We know that often times the business logic depends on content. It does as well in our projects! Typed Entity has the concept of variants for that. Let's change the example above to add the variants key:

/** * The repository for articles. * * @TypedRepository( * entity_type_id = "user", * wrappers = @ClassWithVariants( * fallback = "Drupal\my_module\WrappedEntities\User", * variants = { * "Drupal\my_module\WrappedEntities\ModeratorUser" * } * ), * description = @Translation("Repository that holds business logic applicable to all users.") * ) */ final class UserRepository extends TypedRepositoryBase {} So we can now call syncWithComplicated3rdPartyModerationService and keep that logic encapsulated and testable.

$repository_manager = typed_entity_repository_manager(); $article = $repository_manager->wrap($node); $user = $repository_manager->wrap($user_entity); if ($user implements ModeratorUserInterface && $article implements ModeratableInterface) { $user->syncWithComplicated3rdPartyModerationService($article, ModeratableInterface::PUBLISHED); } How does Typed Entity know when to give you a User or a ModeratorUser? All variants declared in the annotation need to implement VariantInterface, which means that they will have a method called applies(). The first class to return TRUE in that method gets used. If none applies, the fallback is used.

We encourage you to use Renderers
Renderers are a very useful and flexible way of encapsulating business logic for rendering an entity. See this example to learn how to declare a renderer.

/** * The repository for articles. * * @TypedRepository( * entity_type_id = "node", * bundle = "article", * wrappers = @ClassWithVariants( ... ), * renderers = @ClassWithVariants( * fallback = "Drupal\my_module\Render\Article\Base" * variants = { * "Drupal\my_module\Render\Article\Summary", * } * ), * description = @Translation("Repository that holds business logic applicable to all articles.") * ) */ final class ArticleRepository extends TypedRepositoryBase {} You can use the fallback key in your typed repository plugin to use a particular renderer if no other renderer is applicable. You can implement the applies() method in renderers as well, but if your variants are only for the view mode then use the VIEW_MODE constant in your renderer (like this).

When you have (1) declared your renderer, and (2) specified your VIEW_MODE / applies(), you can proceed to implement the renderer methods. In most cases you will:


* Add preprocess logic to prepare the data for the Twig template. Use preprocess().
* Alter the render array for the associated entity. Use viewAlter().
* And more! Check the TypedEntityRendererInterface.

Typed Entity UI Version 4.x of the module comes with the Typed Entity UI submodule. This will simplify debugging any gotchas in typed entity.

Go to the /admin/config/development/typed-entity to explore the definitions in a visual way.



Upgrading from 3.x to 4.x? Make sure to take a look to the Change Records we created to make the upgrade easier.

Project Usage
1607
Creation Date
Changed Date
Security Covered
Covered By Security Advisory
Version Available
Production
Module Summary
This module aims to provide a simple way to treat existing entities like typed objects, leading to a more maintainable and easier to debug codebase.
Data Name
typed_entity

OPENAI CHATBOT

OPENAI CHATBOT

14:25:44
Generic Chatbot
Hi, I'm a Drupal module expert powered by OpenAI, answering your questions about the Drupal module ecosystem. How can I be helpful today? Please note that we will log your question.