Quick start with the Harfang framework

Summary

This tutorial will cover the basic functions of the Harfang framework and give a step-by-step guide to a little demo application. This tutorial was written using the 0.1 release of Harfang. You can use the development version from Github, but functionality may vary.

The tutorial

1. Install Harfang from haxelib

First, you need to install the framework by using the "haxelib" command in a terminal.

haxelib install Harfang

2. Create the project hierarchy

Create a directory structure like the following one:

> demo
     > out
     > server
     |      > component
     |      > demo
     |      |    > controller

The "out" directory will contain the Haxe compiler's output. A "res" folder may also appear after compilation.

The "server" package contains all server-side code. This package is mandatory for the compilation to succeed as it will contain the application's configuration.

The "server.component" package is the suggested place in which you put any helper classes and is also the suggested place in which you put your own implementations of the framework interfaces, should you not use the default ones.

The "server.demo" package contains the "demo" server module. Each module represents an independent MVC container. For example, you Web application may have a Blog module containing the business logic related to blogs, its controllers and its views. Your whole application could be contained in one single module - it's up to you. In our case, the "demo" module is our whole application.

3. Create the "demo" module

Inside the "server.demo" package, create the "Demo.hx" file, containing the Demo class. Here is the code for the file:

package server.demo;

import harfang.module.AbstractModule;

import server.demo.controller.IndexController;
import server.demo.controller.ParameterController;

/**
 * Test demo application
 */
class Demo extends AbstractModule {

    /**
     * Constructs the Demo server module
     */
    public function new() {
        super();

        // Specify the URL mappings for the module
        this.addURLMapping(~/^\/demo\/$/, IndexController, "handleARequest");
        this.addURLMapping(~/^\/demo\/([a-zA-Z]+)\/$/, ParameterController, "handleARequest");
        this.addURLMapping(~/^\/demo\/([a-zA-Z]+)\/([0-9]+)\/$/, ParameterController, "handleAnotherRequest");
    }
}

The Demo class explained

The Demo class extends the "AbstractModule" class - it is the default implementation for the framework's "Module" interface. Although it doesn't appear in the generated documentation since it's a private method, the AbstractModule class provides a shortcut "addURLMapping" method to add URL mappings in your module. This method takes 3 parameters : a regular expression that represents the URL you want to match, a Controller class and its mapped method.

In this example, 3 URLs can be dispatched. "/demo/" will go to the IndexController's "handleARequest" method.

The other 2 URLs are more special - they contain parameters. The default implementation of an URL Mapping, ERegURLMapping (which is used by the AbstractModule class), makes use of the regular expression's groups to intercept parameters that will be given to the mapped controller method.

For example, "/demo/asd/" will match the second URL mapping (^\/demo\/([a-zA-Z]+)\/$). The [a-zA-Z]+ group will be extracted and sent to the ParameterController as the first parameter of its handleARequest method.

Lastly, "/demo/asd/9/" will match the third URL mapping (^\/demo\/([a-zA-Z]+)\/([0-9]+)\/$). Both the [a-zA-Z]+ and [0-9]+ groups will be extracted and sent to the ParameterController as the 2 parameters of its handleAnotherRequest method.

4. Create the demo module's controllers

First, create the "IndexController.hx" file in the "server.demo.controller" package. Here are the contents of the IndexController class:

package server.demo.controller;

#if php
import php.Lib;
#elseif neko
import neko.Lib;
#else
#error "Unsupported platform"
#end

import harfang.controller.AbstractController;

/**
 * Index controller of the application - show the demo's index
 */
class IndexController extends AbstractController {

    /**
     * Handler for the index page, renders the index view
     */
    public function handleARequest() : Void {
        // Output the result
        Lib.print("Hello world!");
    }
}

Next, create the "ParameterController.hx" file in the "server.demo.controller" package. Here are the contents of the ParameterController class:

package server.demo.controller;

#if php
import php.Lib;
#elseif neko
import neko.Lib;
#else
#error "Unsupported platform"
#end

import harfang.controller.AbstractController;

/**
 * Very similar to the IndexController class, but this one shows how parameters
 * are received
 */
class ParameterController extends AbstractController {

    /**
     * Same as in the index, with one parameter
     */
    public function handleARequest(parameter:String):Void {
        Lib.print("Got this parameter : " + parameter);
    }

    /**
     * Same as in the index, with two parameters
     */
    public function handleAnotherRequest(parameter1:String, parameter2:String):Void {
        Lib.print("Got these parameters : " + parameter1 + " and " + parameter2);
    }
}

The controller classes explained

As you can see, both classes extend the AbstractController class, which is the default implementation of the Controller interface. This is where your requests ends up. You can do pretty much anything from there - you are not forced to output any result.

If you recall the URL mappings inside the Demo module, there are some parameters that are sent to the ParameterController's methods. All the parameters are sent as String - since the EReg class' "matched" method always returns strings no matter what is contained in the regular expression's groups, the framework doesn't try to cast the results by himself. It just sends the parameters "as-is".

Controllers are instantiated only if the URL dispatcher has to call it. This is why you specify the controller classes in the Demo module instead of creating instances.

5. Creating the application's configuration

Create the "UserConfiguration.hx" file inside the "server" package. Here are the contents of the UserConfiguration class :

package server;

import harfang.configuration.AbstractServerConfiguration;

import server.demo.Demo;

/**
 * This contains the user's configuration. Refer to the ServerConfiguration
 * interface to see the available methods
 */
class UserConfiguration extends AbstractServerConfiguration {

    /**
     * Constructor (initialize your parameters here)
     */
    public function new() {
        super();
        this.addModule(new Demo());
    }

}

This class is mandatory. It must exist in order for the code to compile. The UserConfiguration extends the AbstractServerConfiguration class, which is the default implementation of the ServerConfiguration interface. It was named "UserConfiguration" to avoid confusion with ServerConfiguration interface.

The UserConfiguration interface contains the modules of your application and can also handle events defined in the ServerConfiguration interface. By default, none of the events (like onClose, onDispatch, onHTTPError) do anything. They are implemented as empty methods in AbstractServerConfiguration in order to prevent bloat for the users who don't do anything with these events. You can always override the default implementations in your classes (or build your own implementation of the ServerConfiguration interface).

The AbstractServerConfiguration class also provides the "addModule" shortcut method (which doesn't appear in the generated doc since it's private). This method is used to store your modules in the configuration. In our case, we only add our "Demo" module.

6. Deploying the application on Apache with PHP

By now, your project structure should look like this :

> demo
     > out
     > server
     |      > component
     |      > demo
     |      |    > controller
     |      |    |          IndexController.hx
     |      |    |          ParameterController.hx
     |      |    Demo.hx
     |      UserConfiguration.hx

Now that we have all the parts in place, we need to compile the application and deploy it on a server. We will use PHP in this example. We take into account that you already have a server on which you can deploy your application. Make sure you have URL rewriting enabled.

Compilation

Create the "compile-php.hxml" file at the root of your project. Here are the contents of the compilation file:

-php out/
-lib Harfang
-main harfang.server.ServerMain

The "lib" and "main" part are mandatory for the application to work. You won't get far without an entry point!

Now, compile the project using this command:

haxe compile-php.hxml

Server setup

Once the compilation is done, create a "demo" folder inside your Web server's webroot (on a default Linux install, it's usually "/var/www/html") and copy the contents of the compiler's output folder (the "out" folder) to the server's "demo" folder. If you deploy your application elsewhere, don't forget to modify the URL mappings accordingly.

Next, in the "demo" folder inside your webroot, create a .htaccess file with the following contents:

<IfModule mod_rewrite.c>
        RewriteEngine on
        RewriteRule  ^(?!nohandle|medias).*$ index.php [NC]
</IfModule>

Notice the "(?!nohandle|medias)" group - these are the URLs that won't be handled by your application. In this example, any URL starting by "nohandle" and "medias" won't be redirected to the application's index.php. This can be useful to server multimedia files like pictures, music or simply prevent some URLs to be handled by your application. For example, "/medias/image.jpg" won't be handled by Harfang, but "/blabla/" will.

Handling errors

If the URL dispatcher is unable to find a match within the modules' URL mappings, it will throw a 404 error to the UserConfiguration instance. Now how you handle HTTP errors inside your application is your own business. You could override the "onHTTPError" method inside the UserConfiguration and output a message or even render a template. Just be careful - "onHTTPError" will be called for both 404 and 500 messages.

7. Enjoy

Start your Web server and go to where you deployed your application (in our case, the /demo folder.) If you Web server is installed locally, access the application from "127.0.0.1/demo/". Try the different URLs (127.0.0.1/demo/aa, 127.0.0.1/demo/bb/2 and so on). Try out different URL mappings, handling some events... Make sure to check out the framework's API.

This concludes the tutorial. As you can see, the resulting application is very, very basic. It's meant to give you the basis to build your own applications. But some issues, like how to handle authentication and responding to errors will be addressed in separate documents. Remember : the framework is only a set of interfaces. There are multiple ways of addressing different use cases and none of them is absolutely right. So use this documentation only as a guideline and let the framework help you build your applications - not restrain you in a single way of doing things.

version #19416, modified 2013-06-02 22:11:38 by njuneau