How to refactor moin into simpler parts using model view controller pattern. This is based on WikiTemplateLanguage which is based on MoinMoinIdeas/WikiApplicationServerPage.
First draft - -- NirSoffer 2004-08-11 04:25:55
Contents
Goals
As MoinMoin grows and get more features, it also become more complicated and hard to modify.
- Make modifying the user interface easy, have all code related to the user interface in few files
Separate the html from the logic. Put the html in templates and use the code to fill the template with data. See WikiTemplateLanguage
- Make the role of each object clear, and simplify existing code.
- Create easy to understand and document execution model
There is a catch: the simple execution model is based on MoinMoinIdeas/WikiApplicationServerPage which is kind of moin voodoo.
Model view controller
Models
Here is a quick mapping of the different classes we have today, and some new.
Model objects manage data about the site, wiki, user, languages etc. They answer to the controller objects. They don't know anything about how the wiki is displayed to the user.
Classes: Request, User, Page, Storage, Wiki, Farm, Parser, Cache, Languages, Security.
Major changed: model classes will NOT print any HTML, or know anything about html/xml/any other format.
Views
View objects define how thing look, and ask their controllers for data when they need it. They don't know anything about the wiki itself.
Classes: Formatter, Templates, Processors, View(new).
Major change: theme code will be separated to templates and templates controllers. Most of the html and text (translations) will be in the templates, some will be at the controllers.
New View object will be responsible for a lot of stuff that request is doing today: print html headers, cache and redirect output, keep state for the current page content, like the current heading number, the TableOfContents etc. For example, if you format an included page, the formatter will use the state saved in the view, not in itself. So each new formatter can continue from the point the previous formatter stopped.
Controllers
Controllers take data from the model when the view ask for it, or take data from the view and change the model.
Classes: TemplateController(new), Action(new), Macro.
Major change: Action is a class, and responsible for both the content and the user interface for the content.
New TemplateController is a helper for the template. Simple macro-like calls in the template will be translated to calls to model objects and processing of data. These controllers are the logic of the view layer. For more details see WikiTemplateLanguage
Execution Model
- Get request - runtime create request object
- Dispatch - what the user want to do?
- Validate - does the user has acl rights? page exists?
Create Action object - like PageViewAction
- Render View with a template
The first 3 parts are done today in request and should be similar.
Actions
Actions are the main part of this model. Everything you do is an action: viewing a page, editing, deleting etc.
- Action is a class
- The action is responsible to display the content area
- The action is responsible to display user interface for the content area
- The template controller ask the action for data during rendering
- Action might have a template to render it contents, or use a wiki widget.
Example: many action are types of searches, and return list of pages. All these can use a SearchResultTemplate. They will act as a data source to the template and the template will render the data in a standard way. Then we can make a really good template with on the fly sorting of search results on the client using DOM and Javascript - and all actions will enjoy this automatically.
Here a small example, how all searches might use one template. The template can ask the action for a page name for each page, and for a description. Actions that want simple list of pages, will not define getDescription. Action that does want to be more verbose, will define a getDescription, which returns text around the match for a search.
Action and templates execution
Some actions need to collect data before the template is executed, some will run only when the template will ask them for the content. For example, a LikePages action will process the search terms before the template is executed, because the title might be "Search Error".
There are only two active objects in the system: the request and the templates. All other objects are passive - waiting to be asked for someting.
View
A view is an object that send the formated data to the client. The view is created with a template, (see WikiTemplateLanguage). The template is compiled code containing calls that write static data, like "<html>\n", or dynamic data like request.user.name.
The template is the foundation of this model (see WikiTemplateLanguage) - all the rendering and processing is done while the template is running other objects. Its like the current system executing a single page, but it the whole view, not only the content view. From <html> until </html> its a exec of one template, which exec other templates and pages.
Each template contain the macro content which invoke the current action getContent(), which render a text_python template for the content or maybe return the content.
The view might cache its content and send the html to the browser only when its finished. This might be needed for stuff like table of contents, which can be made only after the last heading has been rendered, but have to be render before the page content.
Example code path
Here are some examples of the code path during execution. I show some details, the real code path is much longer, and contain all kind of small nasty details, as one can find in request, wikiutil sendTitle, sendFooter, and page sendPage.
GET FrontPage
The user ask for FrontPage
- Get request, dispatch, validate - page exits
Create action PageViewAction
- Render View with html template
- template print html header, which contain a call "action.getTitle"
action returns the title "FrontPage"
- template continue to render html for the user interface
- template call to action.getContent()
action executes the cached FrontPage, or if dirty, refresh the cache and execute the page.
- template call action.getToolbar()
action execute a page editing toolbar, with EditText, AttachFile etc.
- template sends the rest the html
- template print html header, which contain a call "action.getTitle"
GET Non existing page
The user ask for BackPage
- Get request, dispatch, validate - page does not exits
Create action CreatePageAction
- Render View with html template
- template print html header, which contain a call "action.getTitle()"
- action returns the title "Create a new page"
- template continue to render html for the user interface
- template call to action.getContent()
action returns the content for a create page - The text "BackPage does not exits yet. Do you want to create it?" a list of similar existing pages, and a list of templates.
- template print the returned content
- template call action.getToolbar()
- action does nothing, no toolbar for a page that does not exists yet.
- template sends the rest the html
- template print html header, which contain a call "action.getTitle()"
Error in action processing
If the action get some error, it executes an ErrorPage template instead of the content. Rest of the template rendering is the same.
Fatal Error
In case of a fatal error, a stack trace is printed, maybe with partial view content.