Let's now examine entities and fields and see how they make use of the TypedData API for modeling the data they store and manage. This will also help you better understand how data is organized when you are debugging entities and their fields.
The main place where data is stored and modeled is fields. As we saw, we have two types: base fields and configurable fields. However, when it comes to TypedData, they do not differ very much. They both use the FieldItemList DataType plugin (either directly or a subclass). In terms of definitions, base fields use BaseFieldDefinition instances while configurable fields use FieldConfig instances. The latter are slightly more complicated because they are actually configuration entities themselves (to store the field configuration), but that implement down the line the DataDefinitionInterface. So, they combine the two tasks. Moreover, base fields can also use BaseFieldOverride definition instances which are essentially also configuration entities and are used for storing alterations made through the UI to the fields defined as base fields. Just like the FieldConfig definitions, these extend the FieldConfigBase class, because they share the same exportable characteristics.
In addition to fields, entities themselves have a TypedData plugin that can be used to wrap entities and expose them to the API directly—the EntityAdapter. These use an EntityDataDefinition instance which basically includes all the individual field definitions. Using plugin derivatives, each entity types dynamically gets an EntityAdapter plugin instance.
Let's now examine a simple base field and understand the usage of the TypedData API in the context of fields. The BaseFieldDefinition class extends ListDataDefinition which is responsible for defining multiple items of data in a list. Each item in the list is an instance of DataDefinitionInterface as well, so you can see the same kind of hierarchy as we had with our license plate example. But why is one field a list of items?
You probably know that when you create a field, you can choose how many items this one field can hold—its cardinality. You typically choose one, but can choose many. The same is true with all types of fields. Regardless of the cardinality you choose, the data is modeled as a list. If the field has a cardinality of one, the list will only have one item. It is as simple as that. So, if base field definitions are lists of definitions, what are the individual item definitions? The answer is implementations of FieldItemDataDefinition.
In terms of DataType plugins, as I mentioned, we have the FieldItemList class which implements the ListInterface I mentioned earlier as one of the more complex data types. The individual items inside are subclasses of FieldItemBase (which extends the Map DataType we encountered earlier). So, we have the same kind of data structure. But just to make matters slightly more complicated, another plugin type comes into play here—FieldType. The individual field items are actually instances of this plugin type (which extend FieldItemBase and down the line a DataType plugin of some kind). So, for instance, a text field will use the StringItemFieldType plugin, which inherits a bunch of functionality from the Map DataType. So, you can see how the TypedData API is at a very low level and things can be built on top of it.
So now, if we combine what we learned and look at a base field, we see the following: a FieldItemList data type using a BaseFieldDefinition (or BaseFieldOverride) data definition. Inside, each item is a FieldItemBase implementation (a FieldType plugin extending some sort of DataType plugin) using a FieldItemDataDefinition. So, not that complicated after all. We will put this knowledge to good use in the final section of this chapter when we see how we can interact with entities and field data. I am not throwing all these notions at you just for the sake of it.
The configurable fields work almost exactly the same way, except that the definition corresponding to the FieldItemList is an instance of FieldConfig (which is also a configuration entity that stores the settings for this field, and which is similar to the BaseFieldOverride). However, it is also a type of list definition with the individual list items being the same as with the base fields.