Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Dedicated entity bundle classes in Drupal 9.3

Parent Feed: 

Drupal 9.3 brought a very cool new developer feature to the Drupal entity API: bundle classes. So let me give you a brief explanation of how this works and what are some of the changes you can take advantage of.

Background

As you know, content entities come with a class which can have specific methods that manipulate the data in the fields of the entity. However, these methods can only interact with base fields as that is the maximum context the class can or should be aware of. For example, if the entity type gets 3 bundles with configurable fields on them, it’s not a good idea to codify those fields in the class as the fields may not be available on all bundles.

We can create custom entity types without bundles which have a specific interface with methods that we can type hint and rely on. Sure. But for multi-bundle entities we have no solution.

From Drupal 9.3 this changes with the introduction of individual classes for entity bundles. Which…is…awesome.

Essentially, this works exactly as it sounds. We can now create a bundle with configuration fields and a class that maps to it. This class can then implement a specific interface and can interact with fields defined on that bundle. And the resulting entity objects are being seamlessly passed through the system, type hinted and relied on in a much more OOP way than before. In other words, instead of:

if ($entity->bundle() === 'page') {
  $value = $entity->get('field_subtitle')->value;
}

…we can now do this:

if ($entity instanceof PageInterface) {
  $value = $entity->getSubtitle();
}

Another great use case for this is simplifying templating work for entity bundle templates (or those that need to print entity values). It becomes easier to access values via the magic get methods, without the need for a preprocessor to get the value out of a field first:

{{ node.getSubtitle() }}

How do we create bundle classes?

There are two main things we need to do in order to define a bundle specific entity class.

First, we need to create the class that extends from the main entity class. For example, \Drupal\my_module\Entity\Article extending from \Drupal\node\Entity\Node. If it doesn’t extend from the entity class, Drupal will throw a BundleClassInheritanceException. The bundle class can implement its own interfaces, have base classes used across multiple bundles and use various traits as needed.

Second, this class needs to be defined on the entity bundle it applies to. For entities that belong to us, we need to implement hook_entity_bundle_info() like so:

use \Drupal\my_module\Entity\Brand;

function hook_entity_bundle_info() {
  $bundles['my_entity']['my_bundle']['class'] = Brand::class;
  return $bundles;
}

For entities coming from other modules, like Node for instance, we use the alter hook:

use \Drupal\my_module\Entity\Article;

function my_module_entity_bundle_info_alter(array &$bundles) {
  $bundles['node']['article']['class'] = Article::class;
}

One thing to note is that the same exact class should not be used for multiple bundles, lest you get an AmbiguousBundleClassException. If you want to reuse logic across bundles, consider a base class or trait which individual bundle classes can share.

And that’s pretty much the whole thing to be aware of. There are minor API changes under the hood, particularly driven by the fact that the entity storage can load multiple entities at once which may or may not use the same bundle classes and need individual instantiating. But other than that, things should keep working as they did with minimal potential impact for custom code that deals with the entity storage and loading.

You can read the full change record here: https://www.drupal.org/node/3191609.

Hope this helps.

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web