3

I have a design question:

I have several models that lend themselves to inheritance very well.

I have an animal object that has attributes that are shared between the dog, cat, and hamster objects very nicely. However, the source of the dog, cat, and hamster are all from different APIs.

So what I started doing was to build my module around each of the APIs, with the necessary 'fields' effectively hardcoded in the module animal. I knew that this horrifically violates the DRY principle; but am from the D6 (barely D7 era and hadn't really been introduced to entity types). This was using custom tables, and custom 'models'. This also means that I have to create the views, and all the other stuff associated with it myself.

So then I realized that I could actually use entity types for this. The core animal module exposes only what it needs to (a small set of fields). And the dog, cat, and hamster modules all extend the animal entity type thus giving me access to all the shared data without having to repeat myself and the added bonus of having views, handlers and the other stuff for almost free (a bit of boilerplate that is copy and paste...).

My questions are thus:

  1. Is this thinking right, that content entity types are the way to go?
  2. I know what I gain, but what do I lose by doing this?
  3. Is this a good approach, i.e. is it fair to extend a base entity type?
  4. Is it better to create bundles for each of the dog, cat, hamster or just use the extending of the animal content type?
  5. When do you use a bundle vs extending a content type?
  • You don't have to extend a content type. You can create your own through ContentEntityBase. Drupal Console will generate all of this for you though. – Kevin Jul 25 '17 at 17:14
  • I see. @Kevin, how will my dog, cat, or hamster have the shared fields from animal if they aren't extending animal? Am I missing something? – lilott8 Jul 25 '17 at 17:56
6

Yes, using content entity types for this seems like a good idea.

In regards to entity types vs. bundles, which one is better for you depends on your exact requirement (I only noticed after already writing most of this that you already mentioned and specifically asked about entity types vs. bundles, so might be too much explanation, but too lazy to rewrite now :)).

Entity types

You create separate content entity types. Whether you use inheritance for sharing the base field definitions or for example a trait is up to you. The inheritance only exists in code, the data itself knows no hierarchy, it is stored in separate tables.

But yes, sharing code there is perfectly valid. Drupal 8.4 for example adds a base class for publishable entity types: EditorialContentEntityBase, see https://www.drupal.org/node/2870643.

The advantage of this is that you can build each entity type with exactly the base fields that you need, which results in an optimized storage (1-4 base field tables, depending on whether you need revisions and/or translation support and separate tables for multi-value fields). However, the main drawback is that there is no API, neither views nor entity query that allows you to list different types of animals in a list. If that's a requirement, then this might be a no-go.

Bundles

You create a single animal entity type and different bundles for the different types of animals. This is like the node entity type and bundles. They share the same base fields and storage, additional type-specific fields can be added as configurable fields or maybe also per-bundle base fields (I honestly have no idea how well that actually work - and I'm supposed to be one of the maintainers of the entity system). This is the opposite of the above, it's easy to create lists with different animals but you might end up with a considerable amount of per-field tables if you have a lot of fields on your dogs/cats etc.

In regards to downsides, content entities are pretty heavy, they have a complex structure based on typed data and are therefore slower than plain custom objects. Their storage, while extensible, is also limited in various ways, you can only load full entities and there is no support for bulk update for example (but you can implement some things in a custom storage handler). But you get a ton of features for that, the mentioned views integration, widgets/formatters, cache handling/invalidation, revision and translation support and so on.

| improve this answer | |
  • Thank you. It seems that bundles aren't the way to go. Some of the types will have 20-30 fields per type. So using bundles sounds like it would explode my database into a disgusting mess. The speed requirement isn't going to be a big issue, especially not with respect to the benefits afforded. Thank you for explaining this clearly. I couldn't find good documentation that addresses the "when to use content types vs custom" question. – lilott8 Jul 25 '17 at 21:29
  • You are aware that by disregarding the API, you lose access to almost all the benefits of Drupal, right? – Kevin Jul 26 '17 at 2:00
  • @Kevin , can clarify your statement. I don't understand in what way(s) I/@Berdir disregard the API. Using the custom model would disregard the API, but using entities or bundles is well within the API. – lilott8 Jul 26 '17 at 2:46
  • Follow-up: When I extend, all the fields defined in animal appear on both the animal table and the dog table. But I think the problem in my case is that I have dependencies between a dog and a cat. – lilott8 Jul 26 '17 at 4:25
  • @lilott8 not sure what you mean. My understanding is that animal would not be an entity type itself, and there is no animal table. Animal would just be a base class without any entity annotation. So both the dog and the cat table will both have all fields from the animal base class. That's the only thing that works. – Berdir Jul 26 '17 at 6:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.