:: Table of Contents ::
 
Subchapter 5.1: Modules and Actions
5.1.1 Introduction

So far, we have seen how to invoke the Harmoni application services and use their broad functionality. In order to be able to use those services though we need to set up a web application framework which will make these services available to the end user.

The Harmoni architecture is comprised of a set of modules and actions. The modules specify what kind of action you want to take, and the actions tell the web application what to do. That is to say, the actions have the code of what you want to do. Currently, actions can be flat PHP files, entire PHP classes or even specific methods inside PHP classes. The modules can be seen as the "containers" of the actions. So, in the case of the PHP files and classes, the module is the folder that contains them and in the case of a method inside a PHP class, the module is the PHP class itself. Those actions will be manipulated through the Harmoni "ActionHandler"

5.1.2 Flat PHP Files

The first case we will examine is the case of the actions being flat PHP files and modules being the folders that contain them. Now, in order to create a Harmoni application of any sort you need to instantiate a Harmoni object via the harmoni.inc.php include file. For instance, you need to write something like:

require_once("/path/to/harmoni/harmoni.inc.php");

Let's say that the user has an "index.php" file in some directory and two files called welcome.act.php and hello.act.php in the directory "/main/modules/apps/" which is in the same directory as "index.php". The files welcome.act.php and hello.act.php are the actions of our application. They are contained in the module "apps/". A very fundamental use of our actions through the index.php file is shown below:

Example
<?
//Just some definitions for simplicity
define("MYDIR",dirname(__FILE__));
define("MYPATH",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__)));
define("MYURL",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__))."/index.php");

require_once(
"/path/to/harmoni/harmoni.inc.php");
require_once(
"/path/to/harmoni/core/actionHandler/actionSources/FlatFileActionSource.class.php");//include the appropriate file


$harmoni =& new Harmoni();

//set the default(whenever this file is called) module "apps"
$harmoni->config->set("defaultModule","apps");

//set the default action "welcome"
$harmoni->config->set("defaultAction","welcome");

//specify what kind of action we want (FlatFile), give the location of the modules
//and specify what extension our action files have (if not specified, Harmoni will
//simply use ".php")
$flatfileactionsource =& new FlatFileActionSource(MYDIR."/main/modules",".act.php");

//Now add the new action source created above.
//This case it is a flatfileactionsource
$harmoni->ActionHandler->addActionSource($flatfileactionsource);

//now call the execute method of the $harmoni object
$harmoni->execute();

?>


This constitutes our index.php file. Every time it is called, it is going to search for the file "welcome" action ("welcome.act.php" file) in the module "apps" (folder "main/modules/apps/") and it will do what the action says. So let's see what the "welcome.act.php" (default action) might look like:

Example
<?

print
"Welcome my friend!<br>";
print
"<a href=".MYURL."?module=apps&action=hello>click here to receive a \"hello\".</a>"

?>

So, everytime we call the file "index.php" from our browser the result will be:

Welcome my friend!
click here to receive a "hello".

And when you click the link, the file "main/modules/apps/hello.act.php would be called, and that would be something like:

Example
<?

print
"hello";
?>

So, we see that our application is made of modules which are made of actions. And every time the user clicks on any type of choice, the appropriate action is called. The URL that comes our of this action though looks really ugly and complicated and since everyone in Harmoni believes that "the simpler the better" we use the following trick to polish off the URL:

The Harmoni object understands the pair of module-action as "module.action" so we can make the following changes to the code and have the exact same result with a better looking URL:

Example
//index.php

<?
//Just some definitions for simplicity
define("MYDIR",dirname(__FILE__));
define("MYPATH",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__)));
define("MYURL",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__))."/index.php");

require_once(
"/path/to/harmoni/harmoni.inc.php");
require_once(
"/path/to/harmoni/core/actionHandler/actionSources/FlatFileActionSource.class.php");//include the appropriate file



$harmoni =& new Harmoni();

//set the default(whenever this file is called) module "apps"
$harmoni->config->set("defaultModule","apps");

//set the default action "welcome"
$harmoni->config->set("defaultAction","welcome");

//we create a function that will be used to give harmoni the module and the action as
// "module.action" while it receives them as " module/action/"
function callback_action(&$harmoni) {
        return
$harmoni->pathInfoParts[0] . "." . $harmoni->pathInfoParts[1];
    }

//set the call back function of Harmoni to be the function
//created above.
$harmoni->setActionCallbackFunction( "callback_action" );


//specify what kind of action we want (FlatFile), give the location of the modules
//and specify what extension our action files have (if not specified, Harmoni will
//simply use ".php")
$flatfileactionsource =& new FlatFileActionSource(MYDIR."/main/modules",".act.php");

//Now add the new action source created above.
//This case it is a flatfileactionsource
$harmoni->ActionHandler->addActionSource($flatfileactionsource);

$harmoni->execute();

?>

Example
// main/modules/apps/welcome.act.php

<?


print
"<a href=".MYURL."/apps/hello/>click here to receive a \"hello\".</a>"

?>

And now the url looks like: "..previous path/index.php/apps/hello/ instead of "...previous path/index.php?modules=apps&action=hello "

The two lines used in the code to set the harmoni settings:

$harmoni->config->set("outputHTML",false);
$harmoni->config->set("useAuthentication",false);

are used to disable the theme requirement, which is being discussed later on, and to disable the authentication, since when a harmoni object is created, authentication is by default set to true.

5.1.3 Methods within PHP classes

Now that we have seen how to operate with actions as PHP Files and modules as folders, we will take a look at having modules as PHP classes, and actions as methods inside those classes. The concept remains the same as in the previous case. But now, instead of having a folder(module) inside the modules folder, we have a PHP class file and the action is no longer a file but just a method inside that class. Now, let's modify the previous example:

Example
//index.php

<?
//Just some definitions for simplicity
define("MYDIR",dirname(__FILE__));
define("MYPATH",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__)));
define("MYURL",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__))."/index.php");

require_once(
"/path/to/harmoni/harmoni.inc.php");
require_once(
"/path/to/harmoni/core/actionHandler/actionSources/FlatFileActionSource.class.php");
require_once(
"/path/to/harmoni/core/actionHandler/actionSources/ClassMethodsActionSource.class.php");//include the other action source file


$harmoni =& new Harmoni();

//set the default(whenever this file is called) module "apps"
$harmoni->config->set("defaultModule","apps");

//set the default action "welcome"
$harmoni->config->set("defaultAction","welcome");

//we create a function that will be used to give harmoni the module and the action as
// "module.action" while it receives them as " module/action/"
function callback_action(&$harmoni) {
return
$harmoni->pathInfoParts[0] . "." . $harmoni->pathInfoParts[1];
}

//set the call back function of Harmoni to be the function
//created above.
$harmoni->setActionCallbackFunction( "callback_action" );


//specify what kind of action we want (FlatFile), give the location of the modules
//and specify what extension our action files have (if not specified, Harmoni will
//simply use ".php")
$flatfileactionsource =& new FlatFileActionSource(MYDIR."/main/modules",".act.php");


//create a new action object, in this case a "ClassMethodActionSource"
//and specify where the modules (classes) are and what extensions they have
$classmethodactionsource =& new ClassMethodsActionSource(MYDIR."/main/modules",".class.php");




//Now add the new action source created above.
//This case it is a flatfileactionsource
$harmoni->ActionHandler->addActionSource($flatfileactionsource);
//...as well as the new classmethodactionsource
$harmoni->ActionHandler->addActionSource($classmethodactionsource);

$harmoni->execute();

?>


So the "index.php" file still points at the same module-action pair ("apps/welcome") but if we change the "apps/welcome.act.php" file to:

Example
// main/modules/apps/welcome.act.php

<?


print
"<a href=".MYURL."/welcome2/test/>click here to see what you called.</a>"

?>

..and inside the folder "main/modules" (the folder defined when constructed the ClassMethodActionSource object) we create the class "welcome2.class. php" with a method called "test":

Example
<?php


class welcome2{

//..other methods and variables here
function test(&$harmoni){

print
"you just called the method \"test\" inside the class \"welcome2\" <br>";

}

//..other methods here

}


?>

After clicking the link in the "welcome.act.php" loaded in "index.php" we will get in our browser:

you just called the method "test" inside the class "welcome2"

NOTE
There are two things you have to be careful about. Firstly, you have to make sure the name of the class and the name of the file that contains the class are identical and then you have to design the method you call inside the class so that it takes a parameter. The ActionHandler will automatically pass its Harmoni object as a parameter to the method you specified to be the action.

The example we just gave is somewhat trivial. The method we created just prints something on the screen. The methods defined as actions might as well alter the functionality of our program. They could return a layout (see the Layout System), or they could alter the settings of our Harmoni object since the Harmoni object is always passed as a reference to the method by the actionHandler. For example the previous class could be changed to something like:

Example
<?php


class welcome2{

//..other methods and variables here
function test(&$harmoni){

print
"you just called the method \"test\" inside the class \"welcome2\" <br>";

//set the character set that Harmoni uses
if($harmoni->config->set("charset","utf-8"))
    print
"The character set of the Harmoni object has been set to \"utf-8\"";

}

//..other methods here

}


?>
5.1.4 PHP classes

Ok, now that we have presented the flatfile actions and the classmethod actions, what is left is the case that the action is an entire PHP class and its module is the folder that contains that class. Even though the action is the whole class but what is going to be executed is a method named "execute". So, when designing this class, the user has to make sure that the class has an "execute" method that gets a parameter by reference since the actionHandler, when called, will pass its Harmoni object to it.

Let's see our example modified to demonstrate the use of PHP classes as actions:

Example
//index.php

<?php
//Just some definitions for simplicity
define("MYDIR",dirname(__FILE__));
define("MYPATH",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__)));
define("MYURL",str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__))."/index.php");

require_once(
"/path/to/harmoni/harmoni.inc.php");
require_once(
"harmoni/core/actionHandler/actionSources/FlatFileActionSource.class.php");
require_once(
"harmoni/core/actionHandler/actionSources/ClassMethodsActionSource.class.php");
require_once(
"harmoni/core/actionHandler/actionSources/ClassesActionSource.class.php");//include all action source files


$harmoni =& new Harmoni();

//set the default(whenever this file is called) module "apps"
$harmoni->config->set("defaultModule","apps");

//set the default action "welcome"
$harmoni->config->set("defaultAction","welcome");

//we create a function that will be used to give harmoni the module and the action as
// "module.action" while it receives them as " module/action/"
function callback_action(&$harmoni) {
return
$harmoni->pathInfoParts[0] . "." . $harmoni->pathInfoParts[1];
}

//set the call back function of Harmoni to be the function
//created above.
$harmoni->setActionCallbackFunction( "callback_action" );


//specify what kind of action we want (FlatFile), give the location of the modules
//and specify what extension our action files have (if not specified, Harmoni will
//simply use ".php")
$flatfileactionsource =& new FlatFileActionSource(MYDIR."/main/modules",".act.php");

//create a new action object, in this case a "ClassMethodActionSource"
//and specify where the modules (classes) are and what extensions they have
$classmethodactionsource =& new ClassMethodsActionSource(MYDIR."/main/modules",".class.php");

//add the last action object, a "ClassesActionSouce", specify where the modules(folders) are
//and what extensions the actions (classes) have
$classesactionsource =& new ClassesActionSource(MYDIR."/main/modules",".phpclass.php");
$harmoni->ActionHandler->addActionSource(new ClassesActionSource(MYDIR."/main/modules",".phpclass.php"));
//so the folder with the ClassesActionSource modules is inside the directory "main/modules"
//and the actions have extension ".phpclass.php"


//Now add the new action source created above.
//This case it is a flatfileactionsource
$harmoni->ActionHandler->addActionSource($flatfileactionsource);
//...as well as the new classmethodactionsource
$harmoni->ActionHandler->addActionSource($classmethodactionsource);
//..and the last one
$harmoni->ActionHandler->addActionSource($classesactionsource);

$harmoni->execute();

?>

All we did was add a new ActionSource(ClassesActionSource) to the actionHandler. Our default action remains the same, but the welcome.act.php file should be changed to:

Example
// main/modules/apps/welcome.act.php

<?php

//we are calling the "classaction" action with module "apps"
print "<a href=".MYURL."/apps/classaction/>click here to see what you called.</a>"

?>

The action that will be called after the click of the link will be the action "classaction" with module "apps". This action will be a class inside the folder "apps/". So let's see that classaction:

Example
// main/modules/apps/classaction.phpclass.php

<?php


class classaction{


//..other methods and variables here
function execute(&$harmoni){

print
"you just called the method \"execute\" inside the class \"".get_class($this). "\"<br>";

}

//..other methods here

}


?>

And the method "execute" in the class "classaction" is executed by the ActionHandler. The result after clicking the link in the default page will be:

you just called the method "execute" inside the class "classaction"

Now, the user might think "well, we are still calling a method inside a class, what is the difference with the actions being methods within a class?" The answer is simple: "When your action is a class, you can use the functionality of the class to extend the capabilities of your action. For example, your class action is able to extend other classes. And thus, contrary to the action being merely a method, now you can extend another class (which might be an action itself) and be able to use methods from that other class." So, for example, the class "classaction" can be changed to the following:

Example
// main/modules/apps/classaction.phpclass.php

<?php

require_once("/path/to/otherclass.php");

class
classaction extends otherclass{


//..other methods and variables here
function execute(&$harmoni){

print
"you just called the method \"execute\" inside the class \"".get_class($this). "\"<br>";

//call a method from the class we extended
$this->methodfromotherclass($harmoni);

}

//..other methods here

}


?>

So, by extending our former "classaction" we can extend its capabilities. Check out the PHPDoc of the ActionHandler for other uses of the Module- Action pair