Cody CMS
Fork me on GitHub

Het grote geheel

How does it all fit together?

 [ Take also a look at the page Database ]

 Once your web app is started, it listens for a number incoming http requests, that are distributed over 3 applications / servlets:

  1. "/", "/[language]", "/[language]/*" ➙ Application
  2. "/static/*", "/cody/static/*"  ➙  Static
  3. "/data/*"  ➙ Dynamic

 In short Static serves pages from the directory "static" in your web tree or from the "static" directory in the cody directory. Whereas Dynamic serves content from files stored in the directory named in the config parameter "datapath" (quite often in our setup something like "/usr/local/data/[web app name]/").

The first category of requests go to the function servePage of the Application object.

  Application.prototype.servePage = function(req, res) { ... }

 In this function 3 important things happen: 

1) a Path object is created:

  var path = new cody.Path(req._parsedUrl.pathname,, self.defaultlanguage);

The constructor of Path tries to split the url in separate items


 All empty if not specified in the URL, except for language, which is case of absence is filled with the defaultLanguage specified in the config parameters of your app.


2) a Context is created:

var aContext = self.buildContext( path, req, res );

First thing done here is finding out which page is requested by the user / the url of the http request. 

This Context object is kept around for the whole duration of our request and will also serve as go-between for the controller and the view.

The Content constructor add all string content of the page "/[language]/strings" to the instance variable "strings". To be used for all kind of language dependent text in your views, done with Application.findPage:

  Application.prototype.findPage = function(path) { … }

Pages can be found / requested in 2 ways: /[language]/[item-id] or /[language]/[page-link]

The item-id is generated by the Cody back office (Structure in the Dashboard), the page-link is user specified, can be found under the "SEO" tab of each page and is language specific.

If no path is specified, we try if there is a page matching /[language]/welcome.

If no page is found we try to server the page matching /[language]/notfound


All these url's can be found in your Application object under .urls, an object used as a hashmap containing all pages initialized with each page as:  

  .urls[ "[language]/page-link" ] = page, if a pagelink was defined in the SEO tab +

  .urls[ "[language]/item-id" ]


Once the page found, we see if this pages wants to display its own content or the option (in the Options tab) Show First Subitem was chosen. In which case we swap the found page for the first is its children. This process is repeated recursively.


3) we try to hand over the flow to a controller:


Now that we know which page is going to be served / handled, we can find the template of the connected item. In this template there is a Controller stored and a View.

 The controller is created, it is asked if it requires that the user is logged in (more later), if so and the no login record is found in the current session, the user is redirected to the login page. The current state is saved, so that once the user is successfully logged in, we can continue the request.

 Finally the controller is sent the method "doRequest" with a "finish" function.

   controller.doRequest( function(fn, header) { … } )

This gives you (as a possible writer of your own Controller) the possibility of performing the required taskts, interaction with permanent storages, … etc. Setting up some content in the Context object, so that it can be rendered by your view.

It is very important, once when all the work done, that doRequest calls this "finish" function.

It is in this "finish" function that we will ask the view connected to the template to render the resulting page for the user.

This does not need to be a real html page, it can be a JSON object, XML or even plain text. If you don't want the default view attached to the template, you can change your view be either passing it as a parameter to the "finish" function or setting it in the context.fn instance variable. (see also The power of finish)