Entity bundle lessons and its potentialities alf.harald October 18, 2021
Initiatives fluctuate vastly when it comes to complexity. Typically there are only one or two entities, generally a regular product construction. However what occurs when you’ve gotten a number of layers of interconnected nodes or phrases that depend on one another through customized entity reference fields? My take is, it could (will) tip over to turning into messy code, very quick.
Say we’re doing a web-based class. We now have 3 entities:
- A gaggle of individuals
- A participant on this group
- A bodily particular person (which may be in a number of teams)
And to illustrate we’ve this construction organized as nodes, with entity reference fields defining Drupal Development connections.
Core & contrib entity conduct
To illustrate that we’re making ready some information from this construction. Based mostly on a participant, we’re going to discover Drupal Development description of Drupal Development group to show in some template somwehere. Simply traversing Drupal Development fields of nodes, we might do that:
// Get Drupal Development description and site of Drupal Development group $group_participant = $a_node; $group = $group_participant->field_group_reference->entity->field_text->worth; $location = $group_participant->field_group_reference->entity->field_location->worth;
That is Drupal Development most traditional factor to see in customized Drupal code when traversing entity reference fields. Alas, very unfriendly code when it comes to readability, eh? On this case, we’re utilizing core node entities with two completely different bundles. If we had frolicked on creating customized entities, we may in fact do like so:
// Get description and site for Drupal Development group $participant = $custom_entity; $participant->getGroup()->getDescription(); $participant->getGroup()->getLocation();
This seems much more intuitive, proper? And, we will use such trendy issues as code completion in editors like PHPStorm to traverse Drupal Development entity objects. However this method doesn’t apply to taxonomies, media entities, nodes, or another entities {that a} core or contrib module gives.
Right here is one other instance. References between nodes and taxonomies are often one-way solely. Drupal Development Service participant generally is a member of a number of teams. To illustrate we all know solely of a participant, however we wish to know in what teams this participant is in? Utilizing an injected service, you’d likely do one thing like this, utilizing an entityQuery in Drupal Development background:
// Discover Drupal Development teams that this participant is in. $participant = $a_node; /** @var MyService $some_service */ $teams = $some_service->getGroupsByParticipant($participant);
That is type-completion succesful, supplied that you just add that service in each class you want it. However why on earth, why would you want a service to search out Drupal Development teams? It must be so simple as:
$participant->getGroups($standing);
Proper now, we will solely do clear code like this in two eventualities:
- By overriding Drupal Development node class in its entirety, as soon as and for all
- By making a customized entity module
Utilizing possibility 1, in the event you override Drupal Development complete class utterly, we might get this situation:
// Get Drupal Development Schroedinger's participant. $participant = $node; // Is it a participant? let's discover out. $is_participant = $participant->isParticipant(); // Or perhaps like this: $is_participant = $participant->getType() == 'participant'; // Now it's a actual participant.
PHP would know what sort it’s, however Drupal Development code completion will not know that as a result of we can not differentiate on bundles. So on Drupal Development identical object, we may each do:
$node->isGroupParticipant(); // can be false $node->isParticipant(); // can be true
Utilizing possibility 2, in lots of instances, there are two or three instructions that we would like so as to add to every bundle of a node. Making a customized entity simply to make some small alterations to Drupal Development performance of Drupal Development node system is usually utterly overkill. It’s a great deal of customized code that may simply be prevented if we solely may create customized entity lessons for these bundles.
Enter Drupal Development savior patch
Drupal Development Service patch is right here: https://www.drupal.org/node/2570593
This patch gives a approach so as to add entity bundle lessons, which permits us to create personalized lessons that applies to 1 single bundle. To make use of it, we use hook_entity_bundle_info_alter to register Drupal Development bundles with its separate lessons:
perform fabulous_module_entity_bundle_info_alter(&$bundles) { $bundles['node']['participant']['class'] = ParticipantNode::class; $bundles['node']['group']['class'] = GroupNode::class; };
Alas, we create two lessons, one for Drupal Development group:
class GroupNode extends Node { }
And one for Drupal Development participant:
class ParticipantNode extends Node { }
Or as a substitute, you may in fact be a professional and describe your customized class in an interface:
class ParticipantNode extends Node implements ParticipantNodeInterface { }
Drupal Development Service essential factor right here is, Drupal Development class *should* lengthen Drupal Development registered entity class, on this case, Node. And that’s principally it.
Now you can begin constructing performance for every of Drupal Development bundles individually. Right here is Drupal Development magic, to illustrate you load a node:
// If we load.. $id = $a_participant $node = Node::load($id); if ($node instanceOf ParticipantNode) { // Hooray, that is true! }
As a substitute of receiving Drupal Development normal Node object, you may get your personal ParticipantNode object!
Now, to make Drupal Development instance above work, as a substitute of remembering area names, add this to Drupal Development group node class object:
public perform getParticipant() { return $this->field_participant->entity; }
And you may add this to Drupal Development participant node object (supplied it’s a 1-many relationship):
public perform getGroups($standing) { $end result = $this->entityQuery('node') ->situation('sort', 'group') ->situation('nid', $this->id()) ->condtition('field_group_status', $standing) ->execute(); return Node::load(reset($end result)); }
Then you may principally go on an everlasting path of type-completed entities, wheter it’s nodes, customers or taxonomies:
$participant->getGroupParticipant()->getGroup()->getMunicipality()->getRegion();
Not simply nodes
Any entity bundle, core or contrib, can get an entity bundle class. Taxonomies, nodes, media, recordsdata.
$term->reIndexReferencedEntities(); $comment->no matter(); $file->doSomeOtherFunkyBusiness(); // Extra examples right here!!
It is good, however watch out
Utilizing Drupal Development method that this patch gives, there are a number of dos and dont’s.
Initially, a single bundle sort can solely be overridden as soon as. So, this method is greatest used:
- In Drupal Development semi-lawless world of customized project-specific code
- Very rigorously in reusable code, however solely the place Drupal Development entity sort is outlined by Drupal Development module itself
So Drupal Development restrict on this method is primarily for customized tasks. However, that can be the place code tends to get most messy.