Doing Dynamic data can be very challenging - so when we developed the EAV (entity/attribute/value) system in 2sxc we created a system which has Ghost Content Types. Here's why, and how it works. This is a level 300 information - not for beginners.
A Standard EAV won't do
Dynamic Data always seems very simple, especially when looking at common implementation like Form-and-List which are basically just an over-normalized data schema (entity X has the attribute Y containing value Z). But this model is too simple - the entire system becomes a hybrid of sometimes-dynamic sometimes-SQL which leads to large problems and inconsistencies- and will quickly hit limits of what it can do.
Most developers will begin with such a model - and often cannot get out of it any more. The inventor of List and Forms told me in 2012, that the best thing would have been to start all over. The problem is that the original concept seems simple and intuitive - so every developers first 5 generic data models work that way. A common indicator for such an implementation are the fact that configuration of the system itself - like how to define an input-field - is done in a SQL database instead of inside the dynamic data.
Learning from Magento, Umbraco and SharePoint
When we started work on 2sxc in 2012 we had already developed more than many generic data models for various other applications and had always hit a point where things started to hurt or got very confusing. And we wanted to do it much better. We knew that we can't be smarter than everybody else, we researched successful and failed implementations and tried to merge what had worked.
One of the concepts we ended up implementing were Ghost or Shadow Content Types to allow reuse of content-type definitions across isolated systems…
Show me some Ghosts
The quickest way to see some ghost content-types is by going into admin-mode, enable the advanced UI (Ctrl+Click) and then change the Scope to "System" which will show you some ghosted content-types of the current app. It's described in more detail in the blog Understanding Content Type Scopes.
Isolated Systems - Necessary for Encasulating Functionality
Here's the core problem: in a generic CMS like DNN any kind of functionality you create needs some kind of boundaries. These boundaries define what's part of this functionality and what is not. It's the only way to ensure that an export/import can work, and that certain actions don't have a side-effect. In 2sxc 1.0 this was not possible, everything was "in the same package". In 2sxc 3.0 we introduced Apps - which defined such limits and allowed this.
But it introduced the problem: how can the core system know that a content-type definition must be exported, and when not? How can a system be self-contained, but still refer to external stuff and do this in a reliable way? Here we looked at the data model in SharePoint and our solution works as follows:
- Each app is self contained - entities (content-items) can only be based on a content-type which exists in the app
- BUT: a content-type in the app can say that it's definition comes from somewhere else. So our content-types can say "I'm the content-type @String, and items in this app use my type. But if you want to know what fields I have, you must check out the definition of this other content-type…"
Implementation of Definition-Inheritance
Since the content-type definition is only important for certain parts of the application (loading from the DB, edit-UI, export/import) this was fairly easy to implement. Basically every Content-Type has a field "UsesConfigurationOf..." (see image). This causes all affected systems to use the other definition instead. The following example shows the @String being defined in the root app 1 and then the @String in the App #12 using the definition of this initial @String content-type:
Automatically Create Ghosts In Every New App and Zone
In addition to that, there is a field called "AlwaysShareConfiguration". This tells the EAV-System that each newly generated App must receive a Ghost-entry for this content-type. This ensures that all apps have the same system types.
Creating your own Ghost/Shared Content-Types
There are some use cases where this is a good idea - but you need to know what you're doing. I'll explain it in a follow-up blog.
Love from Japan,
Daniel