The main architectural concept of wCMF is the well known Model-View-Controller pattern. The following sections describe it's implementation in wCMF and introduce some other key concepts, that are useful to know when using the framework.
An application is usually based on a domain model that represents the real-world concepts of the domain of interest. In object oriented programming this model is implemented using classes. Depending on the application requirements the instances of some of these classes have to be persisted in a storage to keep the contained data. These classes represent the data model. The classes that provide the infrastructure for storing data form the persistence layer.
PersistentObject as base class for persistent domain classes. It mainly implements an unique identifier for each instance (see Object Identifier), tracking of the persistent state, methods for setting and getting values as well as callback methods for lifecycle events. For the composition of object graphs the derived class
Node is used as base class. It implements relation support for persistent objects.
To retrieve persisted objects
PersistenceFacade is used. The actual operations for creating, reading, updating and deleting objects (e.g. SQL commands) are defined in classes implementing the
PersistenceMapper interface (see Data Mapper Pattern). Although not necessary there usually exists one mapper class for each persistent domain class. Mapper classes are introduced to the persistent facade by configuration.
Please refer to the section Persistence for a more detailed description of the persistence layer.
For handling lots of different domain objects an unique identification is crucial. To achieve this, so-called Object Identifiers (OID or object id) are used. Various strategies are possible to obtain these identifiers, e.g. a central registry.
wCMF composes these object ids from the type of the persistent domain class and a number, which is unique for each type (e.g. Author::1). It is important that the object's type can be derived from the object id, because this enables the
PersistenceFacade to determine the
PersistenceMapper for the given object from the configuration. The class
ObjectId implements this concept.
The presentation layer of a wCMF application enables users to interact with the domain model.
Each interaction is initiated by a request and results in a response. In a web application the request data is sent by the user's browser to the server as GET, POST, etc. variables.
Application class transforms the request data into a
Request instance. This instance is then passed to a
ActionMapper instance, which creates the
Response instance and delegates the actual execution of the request to a
Controller instance. Different controllers exist for different actions (e.g.
ListController for listing objects,
SearchController for searching objects).
The controller is determined by matching specific request parameters against a list of so called action keys (see Action Key). As the result of it's execution each controller returns action key parameters in the response data. If these parameters match an existing action key, the associated controller will be executed by passing the current response as input. In this way complex tasks can be executed by chaining several controller calls together.
To support various data representations, a
Format instance is associated with each request and response. The format is automatically determined by the HTTP Content-Type resp. Accept headers.
Format implementations are responsible for de-/serializing the request and response data into the desired format (e.g. JSON or SOAP).
HtmlFormat especially uses a
View instance to render the response data into a HTML page. wCMF's uses Smarty as the default template engine for HTML output.
Please refer to the section Presentation for a more detailed description of the presentation layer.
An important concept of wCMF is that of Action Keys. An action key describes the state of the application together with the action to be performed next. The state, which the application is in, results from the current controller and the context, in which it is executed. Controllers must exist as classes, whereas contexts and actions can be arbitrary strings.
The string representation of an action key is as follows:
- Since question marks (?) are used to separate the parts of an action key, a question mark is not allowed inside the parts itself.
wCMF uses action keys in the following places:
- In routing definitions controller names are assigned to action keys.
ActionMapperuses these definitions to execute the correct controller when the application is in a certain state.
- In view definitions template filenames are assigned to action keys.
Viewdetermines the view template to be displayed for the current application state.
- In permission definitions roles are assigned to action keys. In this case the controller value of the action key is interpreted as resource and can also define an entity type or entity instance.
PermissionManageruses this when checking permissions on a given resource.
Since parts of the action key can be omitted in the definition, an algorithm has to choose, which action key fits a given value triple best. This algorithm is implemented in the method
ActionKey::getBestMatch. It checks action key lists against the following search values until a match is found:
As a rule of thumb the action key which describes the state of the application the most accurate is favored.
SaveController when action update is requested, no matter which state the application is in:
AuthorController when the application context is author as long as no action is specified: