mtwin.web.handler
mtwin.web.Handler
Introduction
A web handler is a class, which, given an URL, can decide which action the server application has to execute.
For instance, the url http://www.domain.com/index.n/user/10/view may be understood as : view the User object which id is 10.
To achieve this the server defines a main Handler, this handler will bound 'user' to another handler which in turn will understand how to deal with User objects.
In our example :
MainApplicationHandler
- bind path 'user' -> UserHandler
The UserHandler will provide a method to retrieve a User by its id (10) and will bound the action 'view' to one of its method :
UserHandler (handle User objects)
- implements findObject(id:Int)
- bind path 'view' -> doViewUser(u:User)
The mtwin.web.Handler contains some rights restriction features which reduce dramatically the amount of code required to produce clean and secure web applications.
First example
/** Main web application class. **/ class MyWebApplication { // mtwin.web.Request represents the current http request with url, parameters, etc... static var request : mtwin.web.Request; // for this example we will use mtwin.templo XHTML template engine static var template : mtwin.templo.Loader; // this is some dynamic template context for templo static var context : Dynamic; public static function main(){ mtwin.templo.Loader.BASE_DIR = "/home/project/tpl/"; mtwin.templo.Loader.TMP_DIR = "/tmp/"; context = Reflect.empty(); template = null; request = new mtwin.web.Request(); // creates the main application handler var handler = new MyHandler(); // little check to avoid index.n in path var level = if (r.getPathInfoPart(0) == "index.n") 1 else 0; // start processing the request starting from specified path info part handler.execute(request, level); // if the templo template is defined, we execute it if (template != null){ neko.Web.setHeader("Context-Type", "text/html; charset=UTF-8"); neko.Lib.print(template.execute(context)); } } } class MyHandler extends mtwin.web.Handler<Void> { public function new(){ super(); // (url = /) default, prepare the home.mtt template, no action associated free("default", "home.mtt"); // (url = /getTime) prepare the template getTime.mtt then execute doGetTime free("getTime", "getTime.mtt", doGetTime); // (url = /redirectToDefault) calls doRedirectToDefault free("redirectToDefault", doRedirectToDefault); // (url = /foo/*) delegate to FooHandler free("foo", handler(new FooHandler())); } public function doGetTime(){ App.context.now = Date.now(); } public function doRedirectToDefault(){ neko.Web.redirect("/index.n"); } // mtwin.web.Handler is template independant, we implements this method so // our application will be able to prepare requested templates override function prepareTemplate( t:String ){ App.template = new mtwin.templo.Loader(t); } } class SubHandler extends mtwin.web.Handler<Void> { public function new(){ super(); // (url = /foo/doFoo), prepare the foo.mtt template then execute doFoo() free("doFoo", "foo.mtt", doFoo); } function doFoo(){ // do something } // same as above override function prepareTemplate( t:String ){ App.template = new mtwin.templo.Loader(t); } }
Methods your Handlers may implement
prepareTemplate( tname:String ) : Void
Tells the application what template is going to be used, any template system may be used in this method.
isLogged() : Bool
Returns true if the current user is logged.
isAdmin() : Bool
Returns true if the current user is one of the website administrators.
isModerator() : Bool
Returns true if the current user is one of the website moderators.
isOwner(obj:T) : Bool
Returns true if the current user owns the specified object.
findObject(id:Int, lock:Bool) : T
Loads an object (may be from a database), the lock parameter may be used to tell if the object must be locked for modification or if the object has just to be retrieved in ReadOnly mode (default is lock=true).
Action declarators
In the following action declarators :
- If template is specified, the method prepareTemplate(template) will be called, thus, your template must implements the prepareTemplate() method.
- If callback is specified, this callback will be called, it may be a regular Void->Void method contained in your handler or some sofisticated wrapper created using Handler wrapper.
free(name, ?template, ?callback)
Any user may call this action.
logged(name, ?template, ?callback)
Requires isLogged() to be implemented and to return true for this user.
admin(name, ?template, ?callback)
Requires isAdmin() to be implemented and to return true for this user.
moderator(name, ?template, ?callback)
Requires isModerator() to be implemented and to return true for this user.
Method wrappers
object(objectCallback, ?lock)
Requires findObject() to be implemented, lock may be false|true or using Handler statics : ReadOnly|ReadWrite.
class DocumentHandler extends mtwin.web.Handler<Document> { public function new(){ super(); free("objectDefault", object(doView, ReadOnly)); } override function findObject( id:Int, lock:Bool ) : Document { return Document.manager.get(id,lock); } function doView( d:Document ){ neko.Lib.print(d.html); } }
owner(objectCallback)
Requires isOwner() and findObject() to be implemented.
class DocumentHandler extends mtwin.web.Handler<Document> { public function new(){ super(); // owner of documents may edit them logged("edit", object(owner(doEdit), ReadWrite)); } override function isLogged() : Bool { return App.user.id != null; } override function findObject( id:Int, lock:Bool ) : Document { return Document.manager.get(id,lock); } override function isOwner( d:Document ) : Bool { return d.authorId == App.user.id; } function doEdit( d:Document ){ //... } }
handler(Handler)
Delagates action to a sub Handler.
class OtherHandler extends mtwin.web.Handler<Void> { } class MyHandler extends mtwin.web.Handler<Void> { public function new(){ // /other/* are redirected to OtherHandler free("other", handler(new OtherHandler())); // /user/* are redirected to UserHandler free("user", handler(new UserHandler()); // /help calls the doHelp method free("help", doHelp); } function doHelp(){ //... } }
Examples
Please take the time to browse the hxBlog (especially the Actions.hx file) to get a full working example.