Table of Contents

Case Converter Tutorial

This tutorial is meant as a first introduction to WACT. We will create a tiny application that accepts a text value as input and will convert that text to all lower case or all upper case text.

Hello World

Lets start by creating a simple html page for our application. We will include the form elements in our page.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>Case Converter</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    </head>
    <body>
        <h1 align="center">Case Converter</h1>
        <form method="POST">
            <label for="text">Enter text to convert:</label><br />
            <textarea name="text" id="text" rows="5" cols="70"></textarea><br />
            <input name="upper" type="submit" value="Convert To UPPER Case" />
            <input name="lower" type="submit" value="Convert To lower Case" />
        </form>
    </body>
</html>

Create a new directory in your web server’s document root and save this html as index.tpl.html.

It is common in WACT for file names to have two extensions. The extension at the end indicates the type of the file for your operating system, so editing programs can choose the correct syntax highlighting and double clicking on the file works as expected. In this case, our file type is html. The inner extension identifies the file as a specific kind of file to WACT. Here, tpl indicates to certain WACT tools that this file is a template.

Now we need to create a php file to display this template. This program is the template equivalent of hello world.

<?php
 
require_once 'wact/controller/controller.inc.php';
require_once 'wact/template/loader.inc.php';
 
class CaseConverter extends WactController {
 
    function setup() {
        $loader = new WactTemplateLoader();
        $this->setView($loader->load('index.tpl.html'));
    }
 
}
 
$front = new CaseConverter();
$front->start();
 
?>

Save this file as index.php in the same directory as index.tpl.html.

We start out by defining a controller class, CaseConverter to represent our application. We don’t need this to display a template, but we will use it to structure our application later on. CaseConverter is a Front Controller that acts as the single point of entry into our application.

The setUp method is a template method which is called when a new instance of a WactController object is created. setUp is where we define the structure of our application.

In this example, our only structure is the template that we want to display. In order to load our template, we need an instance of a WactTemplateLoader. We use the default settings for WactTemplateLoader, which searches for templates in the php include_path and caches the compiled templates into /tmp/wact. These settings can be changed if necessary.

Once we have our template loader, we can use it to get a view that represents our template. We’ll associate the view with our controller with setView. Once this is done, the controller will automatically display the view at the appropriate time. That time is when the start method is called on the controller.

Composing Views

WACT uses the CompositeView pattern. That means that view objects are arranged in a nested hierarchy. This closely parallels the organization of an HTML page and the DOM. WACT uses the TemplateView pattern. This means that templates in WACT are also composite views. The object returned by the load method in our example is an instance of WactView.

However, there is only one object in our hierarchy. Unlike the DOM, WACT will not create an object for each tag in your template. Unless you tell it otherwise, WACT treats the text in a template as plain text. So, lets tell it otherwise.

Since we want to work with the form embedded in our template, lets tell WACT to treat the form as a sub-view. We can do this by changing the form tag

    <form method="POST">

to

    <form wact:id="converter" method="POST">

The wact:id attribute tells WACT to treat the <form> tag and its contents as a sub-view. That subview is identified by the name “converter”. We call this the server id. The standard html id attribute is called the client id. In WACT, the server id is not output with the template. If you run the program after this change, you will see that the wact:id attribute is not in the output of our program. Yet, we can now use that converter id to manipulate the form in our template.

Forms are a special kind of tag in WACT. When we told WACT to make a subview from the <form> tag, WACT automatically recognized the other elements of the form and made sub-views out of them, too. This includes the <textarea> and <input> tags. You can now manipulate these tags in the template as well.

To address a particular sub view, you must know its name. But what are the names of the subviews that didn’t have wact:id attributes? In the case of our text area, WACT uses the id attribute as the server id. For the two <input> tags, we didn’t specify an id. For these, WACT generates a name. These tags are known as anonymous tags, but they are still view tags.

So what can we do with subviews? In this example, we will change the rows attribute of our <textarea> tag at runtime.

    $loader = new WactTemplateLoader();
    $view = $loader->load('index.tpl.html');
    $view->getChild('text')->setAttribute('rows', 10);
    $this->setView($view);

If you run the program with this change, you will see that the <textarea> is now taller.

If you want to visualize the view hierarchy, the view debugger can display a nested representation of a view.

    $loader = new WactTemplateLoader();
    require_once 'wact/view/debugger.inc.php';
    WactViewDebugger::dump($view);
    $this->setView($view);

Adding the wact:id attribute to our <form> tag is the only change to the template that we will need to do in this tutorial.

Propagating Form Values

If you enter some text into our form at this point and click one of the buttons, the form will redisplay, but the text will be erased. We are going to want the value that you enter into the form to be automatically carried forward between requests.

Since the form will be submitting a value to our program in the from of the POST variable text, we need to tell our controller to expect this input and to connect that input with the template that we are going to display. In our setUp method we can do this with the following line of code:

    $this->defineInput(new WactPostParameter('text'))->bindToModel();

This tells WACT to expect input as the result of POSTing a form with an element named ‘text’. The bindToModel method completes the round trip by placing the input value in a WactResponseModel object. The view that corresponds to the text area tag knows that it can read the value from the response model.

After this change, if you enter text into the textarea and click on a button, the page will reload, but your text will not be lost.

This is possible because WACT maintains a relationship between the input parameter defined on the controller and the View inside the form that is associated with the controller by setView. There are two elements of data required for this link to work. The first is the name of the input parameter. The name attribute of the form tag must match the name of the request parameter defined in the controller.

explain model locations, bindings

Ready, set, Action!

Now we need to do something when the one of the convert buttons is pressed.

We’ve already seen how Views in WACT form a hierarchy. Controllers in WACT are also hierarchical and can be composed as well. Typically, the controller objects will parallel the objects in the view. Since we want to have the upper and lower buttons perform an action when pressed, we’ll create a sub controller for each button. Add this to the setUp method:

    $this['upper'] = new WactController();
    $this['lower'] = new WactController();

What will each of these buttons do? We’ll register an execute event handler with each of our child controllers. In setUp:

    $this['upper']->registerExecuteListener(new WactCallback($this, 'toUpper'));
    $this['lower']->registerExecuteListener(new WactCallback($this, 'toLower'));

WactCallback is a wrapper class for PHP‘s callback pseudo type. When one of these child controllers is activated, the approriate method will be called. Each of these methods has a specific signature which must be used. Lets add them:

    function toLower($source, $request, $responseModel) {
        $responseModel->text = strtolower($responseModel->text);
    }
 
    function toUpper($source, $request, $responseModel) {
        $responseModel->text = strtoupper($responseModel->text);
    }

The $source parameter is the controller that triggered the event. In this example, the child controllers will trigger the event, but the event handling methods are defined on the parent controller. This is why we cannot use $this inside toLower or toUpper.

The $request parameter allows us to read input values that are defined with defineInput. Since we did a bindToModel on our parameter, we will not need $request for this application.

The $responseModel parameter is a special data holder that is created by the controller and will automatically be passed to the view before it is rendered. This is where input values are stored when input parameters are bound to the model. We can access those values as properties. We’ll do so here to change the case of the text stored in our textarea.

Now we’ve created our child controllers and added our actions. We need to tell the controller how to associate each child with each button. The names we picked for our child controllers were no accident. They correspond to the name attributes on our <input> tags in our template. We need one more line of code to tell WACT that these child controllers should be associated with the input received from the <input> tags when the form is submitted. This is done with a dispatcher.

    $this->setDispatcher(new WactButtonDispatcher());

There are several kinds of dispatchers in WACT. The WactButtonDispatcher tells WACT that the child controllers should be treated like buttons in a form. Thus when you press the button, the proper child controller will be selected and its execute event will be triggered.

If you run the program right now, you will find that our case converter application is functionally complete.

We’ll make one more simplification. Wact provides a shortcut for creating child controllers with execute listeners. Instead of

    $this['upper'] = new WactController();
    $this['lower'] = new WactController();
    $this['upper']->registerExecuteListener(new WactCallback($this, 'toUpper'));
    $this['lower']->registerExecuteListener(new WactCallback($this, 'toLower'));

we can use

    $this['upper'] = new WactCommandController(new WactCallback($this, 'toUpper'));
    $this['lower'] = new WactCommandController(new WactCallback($this, 'toLower'));

If you are interested in the structure of the controllers, there is also a controller debugger available.

$front = new CaseConverter();
require_once 'wact/controller/debugger.inc.php';
WactControllerDebugger::dump($front);
$front->start();

Final program

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>Case Converter</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    </head>
    <body>
        <h1 align="center">Case Converter</h1>
        <form wact:id="converter" method="POST">
            <label for="text">Enter text to convert:</label><br />
            <textarea name="text" id="text" rows="5" cols="70"></textarea><br />
            <input name="upper" type="submit" value="Convert To UPPER Case" />
            <input name="lower" type="submit" value="Convert To lower Case" />
        </form>
    </body>
</html>
<?php
 
require_once 'wact/controller/controller.inc.php';
require_once 'wact/template/loader.inc.php';
 
class CaseConverter extends WactController {
 
    function setup() {
        $loader = new WactTemplateLoader();
        $this->setView($loader->load('index.tpl.html'));
     
        $this->defineInput(new WactPostParameter('text'))->bindToModel();
 
        $this->setDispatcher(new WactButtonDispatcher());
 
        $this['upper'] = new WactCommandController(new WactCallback($this, 'toUpper'));
        $this['lower'] = new WactCommandController(new WactCallback($this, 'toLower'));
 
    }
 
    function toLower($source, $request, $responseModel) {
		$responseModel->text = strtolower($responseModel->text);
	}
 
    function toUpper($source, $request, $responseModel) {
		$responseModel->text = strtoupper($responseModel->text);
	}
 
}
 
$front = new CaseConverter();
$front->start();
 
?>