Architecture
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.
Model
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.
wCMF defines 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.
Object Identifier
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.
Presentation
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.
wCMF's 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.
Action Key
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:
- Note
- 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.
ActionMapper
uses 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.
View
determines 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.
PermissionManager
uses 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.
Examples:
The following examples are taken from the ActionMapping
configuration section, which defines which Controller
to execute for a given action key (see Internal routing).
Always execute SaveController
when action update is requested, no matter which state the application is in:
Always execute AuthorController
when the application context is author as long as no action is specified: