The main task of the framework is to provide an easy-to-use interface to different (not object oriented) persistence mechanisms (whether they're relational databases or XML files).
For this purpose the framework defines the PersistentObject class, which provides operations for changing, saving and deleting data. This class and its subclasses are the data's object oriented representation (domain classes or content types in an CMS context), which is used by application developers. The transformation into relational presentations is carried out by specialized subclasses of PersistenceMapper, which for instance implement the appropriate SQL commands. The domain objects (instances of the domain classes) use these classes transparently to the programmer.
PersistenceMapper classes make use of the DataConverter classes in order to convert data between application and persistent storage. In this way for instance the date format of the database can be converted to the preferred format of the application.
If a direct access to the persistence layer is necessary - for example when loading objects - the PersistenceFacade is used, which delegates the request to the appropriate mapper.
For relational database storages wCMF uses the ADOdb Database Library for PHP as abstraction layer.
At present the framework defines two specialized domain classes, Node and Table, of which the Node class is the application development's central component. Since data is predominantly organized hierarchical, this class provides a generic data container, which allows for the building of tree structures. Node objects can contain different attributes. This makes the definition of different domain classes possible (which merely differ in their attributes: headline, text, image, link etc. - not in their functionality). Appropriate mapper classes are NodeRDBMapper, NodeXMLDBMapper a.o.
The class NodeIterator is responsible for traversing trees composed of nodes. This class implements a depth-first algorithm (the traversing follows the structure to the deepest node first before it continues with the neighboring). Subclasses can implement further algorithms.
The extension of node classes with additional operations follows the visitor pattern. Subclasses of Visitor for instance add behaviour like save (CommitVisitor), graphical display (LayoutVisitor) oder output (OutputVisitor).
For handling lots of different domain objects an unique identification is crucial. In order to achieve this, so-called Object Identifier (OID) are used. Various strategies are possible to obtain these identifiers
The output format of the nodes (e.g. when using the OutputVisitor) is specified in the corresponding OutputStrategy. Examples are the XMLOutputStrategy for converting data to XML format for use in Flash movies for instance or further processing via XSLT, TreeViewOutputStrategy for creating HTML Treeviews or DotOutputStrategy for use with dot, which generates a graphic representation of the data.
The user interface of a wCMF application is based on the Model-View-Controller (MVC) pattern. According to this pattern the application instanciates a specific controller for each action, which loads the data (model) required for that action and - where applicable - presents the data to the user via the corresponding view. Upon execution of a controller the next action will be determined. This could either depend on the result of the action (successful, failed etc.) or explicitly be specified by the user (save, delete etc.). The application flow is defined by stringing together controller-action pairs.
The ActionMapper - configured via a configuration file (see Configuration) - controls the application flow. It creates controller objekts, which execute actions like save changes, add elements, delete elements or display data - where applicable - with the help of views. For execution the Controller baseclass defines an algorithm, which is implemented by specialized subclasses.
The model, which the controllers work with, is constituted of the domain classes - in most cases a tree structure of Node objects.
The framework uses the Smarty Template Engine to create the views. This means, that a view is defined by a Smarty template (*.tpl file), which is displayed by an instance of the class View. Before the data is displayed the controller extracts it from the model and assigns it to the view instance.
Permissions for controller(|domain class|OID)-context-action triplets (see Configuration) are configured based on roles (defined in the data storage). Several users can be assigned to one role and each user can be assigned to different roles. The assignment of rights is made in the configuration file. Here permissions can be explicitly granted or denied. During the application flow authentification/ authorization is accomplished by the RightsManager together with a representation of the current user (as an instance of the AuthUser class, which is created upon successful login and added to the session data).
To run the wCMF in a web browser a PHP script is necessary as entry point. This is similar to a main method, which instanciates the initial application objects and hands the control over to these objects.
In our case this script is main.php. It receives parameters (controller, context, action, data) over a HTTP request. These parameters could for instance origin from the previous view. They are made available to the ActionMapper in form of an Request instance using the method ActionMapper::processAction. The ActionMapper then takes over the control of the application flow and returns after finishing its task or displaying a view, respectively. Display of a view always interrupts the application's flow and allows the user to interact. The view sends the data obtained during the interaction (e.g. form data) as HTTP Request back to the script main.php.
For each call of the method ActionMapper::processAction the ActionMapper on his part instanciates an appropriate controller object, which is supplied with data by Controller::initialize and executed by Controller::execute. The Controller baseclass provides in its method execute the algorithm for validating the data - and if applicable - initializing the view. Concrete controller classes execute their specific tasks in the method Controller::executeKernel. If no view is assigned to a controller, the execute method returns true. The execution result is stored in the Response instance, which again is converted into a Request instance and passed to the next call of the ActionMapper's processAction method. Thus it's possible to cascade different controllers to compose complex tasks out of several simple. Otherwise the controller assigns the model to the view, which is then displayed by the view with its template (here view.tpl).
Request and Response instances are interpreted using IFormat implementations. This allows the framework to realise different formats for sending and receiving data. Known formats are HTML, JSON and SOAP.
The configuration of the controllers, views and actions is done in the configuration file (see Configuration).