OpenWGA 7.10 - OpenWGA Concepts and Features
Design and development » HDBModel frameworkPlanning the document hierarchy
To plan the document hierarchy and declare it for OpenWGA you create a definition file of name hdb-model.xml. This is a file containing XML markup, which defines the hierarchy. It needs to be placed into the system file container of your OpenWGA design under path "files/system".
See the document hierarchy definition file of the example application seen on page Basics:
<storage sid="customers">
<content contentclass="customer"/>
</storage>
<storage sid="projects">
<content contentclass="project">
<storage sid="tasks">
<content contentclass="task"/>
</storage>
<storage sid="bills">
<content contentclass="bill"/>
</storage>
<storage sid="documents">
<content contentclass="document"/>
</storage>
</content>
</storage>
</hdb-model>
As you may find, the hierarchy of tags in this file very closely resembles the hierarchy of documents in the database.
For each root storage of the hierarchy there is a <storage> tag directly below the root tag <hdb-model>. It defines the position of a single storage document which represents a category for content documents. The attribute sid on <storage> tags defines the storage id, which is what you see as title on storage documents.
Inside those <storage> tags you find (single) <content> tags where (multiple) content documents of the given type are allowed below the given storage document. The attribute contentclass on <content> tags gives content a "class", which again determines it for a special purpose. This at first might seem redundant as contents are already categorized by their parent storages, but is both necessary for some, more complex structures, and also handy, for example when querying for content.
Both identifiers in the document definition,storage id and contentclass, can
be customly chosen, but should be non-whitespace strings, consisting of
alphanumeric characters plus the special characters "_" and "-".
The <content> tag may also contain more <storage> tags. These are used to categorize child documents, which are to be located below the given content because they are dependent on it. However unlike storage documents at root a single <storage> tag here will result in one storage document per parent content. Compare this to the example hierarchy shown on page Basics. Each "project" document there has its own "tasks", "bills" and "documents" storage document.
While the given example is a perfectly valid definition file the hdb-model.xml supports numerous more definitions whose purpose will be discussed later in this chapter. A complete reference of the usable tags and attributes can be found in the Definition tags reference for hdb-model.xml.
How HDBModel uses the hierarchy definition
The hierarchy definition will be used by HDBModel to provide everything neccessary for building a real document hierarchy based on the <storage> and <content> tags defined here.
At first HDBModel will automatically create all defined storage documents. Root storage documents will directly be created at the time that the app containing this definition gets connected. So they already are available at the time the connect script of the design runs (which may be used to create the first real content documents programmatically).
Storage documents defined below content documents wil automatically get created when their parent content gets created, so they are immediately available afterwards.
Secondly HDBModel will enforce the defined hierarchy data. It will automatically place a new content document of a given contentclass at the right place in the hierarchy. It will enforce some defaults on content documents, like predefined items with default values.
OpenWGA will read the hdb-model.xml only once an app gets connected. So if you modify hdb-model.xml while your app runs you will need to reconnect it in order to make your changes effective. However HDBModel will automatically detect changes to the model definition and perform a "deep analysis" of the current document data to ensure it matches the changed definition. That way newly defined storages will automatically get created or newly defined default items stored to all matching content documents.
Deciding whether to use child contents
When planning the document hierarchy for your own application there will be some content documents that are dependent to other contents. For these you will have to decide if they should be stored "below" the dependency content (like "task" content below "project" content in the example) or stored in parallel to them (like "project" content to "customer" content).
For defining a relation between your connected contents you do not necessarily need to store them in a parent/child relationship. There are other ways to determine relations as will get discussed in a later chapter. So regarding the given example hierarchy, you could also store tasks "in parallel" to project documents, and define a relation between them:
<hdb-model>
...
<storage sid="projects">
<content contentclass="project">
...
</content>
</storage>
<storage sid="tasks">
<content contentclass="task">
<relation name="project" targetclass="project"/>
</content>
</storage>
...
</hdb-model>
However storing a dependent content below its dependency content as child has some advantages. Choose this storage model if these are desired:
- Deleting the dependency content will automatically delete the dependent content
- Dependent content can be created from the context of the dependency content in a natural way. The user will choose the dependency content implicitly when creating the dependent content within ins context (regarding the example: creating a task from a project). If the dependency is represented by a relation - like above - then the user will need to manually choose the dependency content via some input.
Special document types
Singleton contents
Singleton contents - defined by the tag <singleton-content> in the model - are just like contents in that they carry real data in items and are editable by users. However they also own behaviour similar to storages in that they are automatically created once their parent document exists. Also they only exist once on their hierarchy position, hence the name "singleton".
A typical use case for a singleton content is a document for global app configuration. It often resides below a dedicated storage for system data. For example:
<hdb-model>
<storage sid="customers">
<content contentclass="customer"/>
</storage>
...
<storage sid="system">
<singleton-content cid="settings">
<item name="uimode" default="'flat'"/>
<item name="sendermail"/>
</singleton-content>
</storage>
</hdb-model>
Having a single document at a defined position which is always there from the beginning is ideal for storing app-global settings. As this singleton content is child of a root storage it will directly get created once the application is initialized. It is also possible to have singleton contents below child storages of regular contents or directly below another content itself. These singletons will created along with their parent content, just like the child storages. There will be one singleton for one parent content. However there are rare cases where this is actually useful, as anything that the singleton may carry as data could also be stored on the parent content itself with the same implications. You might want to use singleton contents that way if you have a clearly defined separate dataset which exists for each content but is always used separately, but this is a matter of personal taste.
As you can see the singleton content tag directly gets an "cid" attribute which will set the content id of the created content (see Using the HDBModel unique name and name parts). As this becomes a part of the unique name of this singleton content it is clear how this document can be adressed in WebTML. You just need to combine this id with the storage id of the parent storage:
<tml:case context="name:system.settings" condition="uimode == 'flat'"> ...
For singleton contents this content id will also be used as a content class, so they can be distinguished from regular contents. Be careful not to use a content id which you use as content class for regular content somewhere else.