The Detox Framework Reference Manual

  1. Introduction
    1. Overview
    2. Design goals
    3. Requirements
      1. System requirements
      2. Technical requirements
    4. Usage scenarios
    5. How URIs are mapped
    6. AutoDetox: Detox code generation tool
  2. The First Detox Application
    1. The database
    2. Creating the model
    3. Creating the controller
    4. Creating the views
    5. Extending the application
  3. Architeture
    1. The Controller class
    2. The ApplicationController class
    3. User-defined controllers
    4. How requests are handled
  4. Object-Relational Mapping
    1. The Detox OR Mapper
    2. Writing your own SQL
  5. About this documentation
  6. License

Introduction

Overview

Detox is a MVC framework built in and for the PHP programming language. Detox aims to ease and speed-up the development process of PHP web applications by providing a clean MVC structure and the basic classes for controllers, models and database connections.

Customize the framework to match your application needs should be an easy task, through some PHP skills are required. Having some basic knowledge of how the MVC design pattern works is also a good thing.

Please notice that Detox is still a work in progress, in its very initial state, and still have lots of loose ends. For the next versions we are focusing on:

  • Make a decent i18n support for code generation/OR Mapping
  • Make a better object relational mapper
  • Make a decent implementation of AutoDetox
  • Simplify the way objects are created
  • Give more flexibility to the way data is sent to the views

And more. Any questions or suggestions should be sent to rspenha@users.sourceforge.net

Also notice that this documentation itself is a work in progress, and corrections and contributions are welcome.

Design goals

Detox was built with speed and performance as a main design goal. We tried to eliminate configuration files and statements by using heavy object orientation and introspection, ensuring that your application will have less files to open and perform includes, wich are a costly operation. The price is that you will have to get your hands in PHP code sometimes. If you dontīt just love PHP programming or are not familiar with the concepts mentioned above, dontīt worry; all code you will need to write is really simple, and most of it can be generated by AutoDetox.

We think that writing simple code in a programming language you already know, like PHP, is better than learning new commands and executing then in a command-line interface (to later end up probably having to put your hands on code anyway). The Detox Framework was built with PHP programmers in mind (or at least people that know a little PHP), and we are sure that your application will be better (and faster) if you automatize just some parts of its development (like the creation of models, controllers and basic views) and write its specific code like login validations and so (if you need to) by yourself, anyway you want or are used to do it.

Simple deployment was also a design goal. Detox do not use any operating system or web server vendor-specific function, and do not depend on any external API or library - so deploying a Detox application is simple as deploying any PHP application (usually something like a copy & paste process).

Two of the main focus of Detox are simplicity and ease of use. Simplicity is being achieved; the core framework is about 20kb and defining a new action to be mapped from a URI (and then presenting a view or doing anything else) is easy as a function definition, sometimes a one-line function. Ease of use is provided by clear standards and good documentation; as Detox is still under a very initial state, it is lacking from both in many cases. We are trying to correct this for the next versions.

Requirements

System requirements

Detox is compatible with PHP4/5 and currently was tested in Apache 2.x, but should be compatible with IIS and other Apache versions, as well as other servers, as it do not use any vendor-specific function. This also applies for operating systems. Testing Detox in multiple environement configurations still an issue; maybe you can help us by telling your experience with Detox in your environement (specially if it was a bad experience).

Detox version 0.2.3 currently supports MySQL databases (tested with MySQL 5.0.45). Other databases can be used, but you will need to write the database wrapper for yourself.

Technical requirements

To use Detox properly you should have some basic skills in PHP, as you will need to write some pieces of code. Detox has some code generation capabilities (with AutoDetox), but you will always need to get your hands in the code to fully build your application. We tried to make the framework as simple as possible so anyone with a little knowledge of PHP and web development in general could work with it with no trouble.

Usage scenarios

Detox can be used to build a variety of web applications, but focus mainly in database-driven web applications. It can be used to build content-management systems, portals, e-commerce systems and so on, from small to large applications. It can easily work with other tools (like mod_rewrite) to extend the framework capabilities and the end-user experience.

Detox can also be used to build non-database-driven websites (like this one), taking advantages of all of its templating system capabilities. The Detox Website was built with a simplified version of Detox and can be downloaded for inspiration on what you can do with the framework.

How URIs are mapped

All requests are handled by the ApplicationController object in the index.php file. All URIs must follow this pattern: ?c=controller&a=action&d=data

You may easily alter the way your URIs look using mod_rewrite or other URI rewriting engine. More information on this should be provided with new versions of this documentation.

AutoDetox

AutoDetox is the standard code generation tool for Detox. It reads a given database and then write the models, views and controllers for it (the code for the sample application below was generated by AutoDetox). AutoDetox aims to speed-up the development process of web applications by taking care of the repetitive work.

To try AutoDetox, run yourhost/autodetox/ in your browser and read the instructions.

Remeber that AutoDetox is in a experimental version, and we do not ensure that it will work properly. Also remember to delete the /autodetox folder before deploying your application, as it may be viewed by anyone and turn into a potential danger for your application.

The First Detox Application

The database

In Detox version 0.2.3 all tables need a primary key called 'id' (case sensitive!), int, auto_increment. We did it this way because it was easy, but it is an ugly limitation and is likely to be removed in future releases (so your database may be designed anyway you want).

The sample application will use a database with a single table. Create the following database:

create database detoxtest;
use detoxtest;
CREATE TABLE users (
	id int auto_increment,
	name varchar(80),
	email varchar(80),
	PRIMARY KEY (id)
);

Then edit the core/db/connector.php file to match your database connection. The file looks like this:

require_once("MySQLConnector.php");

class Connector extends MySQLConnector {

	var $host ='localhost';
	var $user ='root';
	var $password = '';
	var $database = 'detoxtest';

}

Creating the model

The models are placed inside core/models/. The files must be named $classname.php (user.php for table users, article.php for table articles, and so on). Remenber to keep it on singular when writing your controllers!.

This is how user.php should look like:

<?php

require_once("recordable.php");
require_once("factory.php");

class UserFactory extends Factory {

	var $model = "user";

	function build($array) {
		return new User($array);
	}

}

class User extends Recordable {

	var $id;
	var $name;
	var $email;

	function User($array) {
		$this->id = $array["id"];
		$this->name = $array["name"];
		$this->email = $array["email"];
	}

}

?>

It consists of a factory for User instances a definition of the User class. The constructor takes an array as argument and start the object attributes with the values in the array corresponding to the attribute name.

Creating the controller

The controller is responsible for handling the requests and presenting views to the user. The ApplicationController object at index.php receives the request, then call the corresponding controller, that then handle the request. All controllers should inherit from the Controller class.

This is how the controller for user should look like:

require_once("models/user.php");

class UserController extends Controller {

	function UserController() {
		$this->factory = new UserFactory();
		$this->model = "user";
		$this->defaultAction = "list";
	}

}

$appcontrol = new UserController();

defaultAction represents the default action that will be performed when the action is not specified in the URI. If defaultAction is not defined, then the base Controller class default action will be used (pointing to 'index').

Creating the views

One advantage of the Model-View-Controller design pattern is that your application pages can be created as "dumb templates"; pages that just present data and have absolutely no idea about business logic. This can ease the job web designers and ther people responsible for interface implementation as they will not need to face much PHP code while creating the pages.

By default, all data is sent to the views in a variable called $data. This variable can be a object instance from a model or a collection of objects, depending on the situation. This will be clearer as we write the basic views to operate on our user table.

The list view

The code for the list view presented by the user controller when the "list" action is requested (and, in this case, also when no action is requested) is as follows.

To see it in action, go to ?c=user&a=list in your application. As you defined in your UserController, this view will also be presented when no action is requested (in a URI like ?c=user)

<table cellpadding="0" cellspacing="0">
	<tr>
		<th>id</th>
		<th>name</th>
		<th>email</th>
		<th>username</th>
		<th>psw</th><th>Delete</th>
	</tr>
	<?php 
		if ($data) {
			foreach ($data as $obj) {
				echo "<tr>";
				echo "<td>".$obj->id."</td>";
				echo "<td>".$obj->name."</td>";
				echo "<td>".$obj->email."</td>";
				echo "<td>".$obj->username."</td>";
				echo "<td>".$obj->psw."</td>";
				echo "<td><a href=?c=user&a=delete&d=".$obj->id.">delete</a></td></tr>";
				echo "<td><a href=?c=user&a=edit&d=".$obj->id.">edit</a></td>";
			}
		}else {
			echo "<tr><td>No results.</td></tr>";
		}
	?>

The create view

This is the form for creating users. The code is as follows. Notice that the form points to the user controller, calling the new action (the same URI of the page that presents the user creation form). All forms in Detox use the post method. This view is just standard XHTML.

After creating this file, go to ?c=user&a=new to see it in action.

<form id="user" action="?c=user&a=new" method="post">
<fieldset>
<legend>New User</legend>
<ul>
	<li>
		<li>
			<label for="name">name</label>
			<input type="text" id="name" name="name" />
		</li>
		<li>
		<li>
			<label for="email">email</label>
			<input type="text" id="email" name="email" />
		</li>
		<li>
		<li>
			<label for="username">username</label>
			<input type="text" id="username" name="username" />
		</li>
		<li>
		<li>
			<label for="psw">psw</label>
			<input type="text" id="psw" name="psw" />
		</li>
		<li class="buttons">
			<input type="submit" value="Submit" />
		</li>
	</ul>
</fieldset>
</form>
The edit view

This is the form for editing users. The code is as follows. Notice that the form points to the user controller, calling the edit action, with the data refered being the id of the current database record (the same URI of the page that presents this user edit form). This view is just standard XHTML with little PHP code to present the current values for this user record.

<form id="user" action="?c=user&a=edit&d=<?php echo $data->id ?>" method="post">
<fieldset>
<legend>Edit User</legend>
<ul>
	<li>
		<li>
			<label for="name">name</label>
			<input type="text" id="name" name="name" value="<?php echo $data->name ?>" />
		</li>
		<li>
		<li>
			<label for="email">email</label>
			<input type="text" id="email" name="email" value="<?php echo $data->email ?>" />
		</li>
		<li>
		<li>
			<label for="username">username</label>
			<input type="text" id="username" name="username" value="<?php echo $data->username ?>" />
		</li>
		<li>
		<li>
			<label for="psw">psw</label>
			<input type="text" id="psw" name="psw" value="<?php echo $data->psw ?>" />
		</li>
		<li class="buttons">
			<input type="submit" value="Submit" />
		</li>
	</ul>
</fieldset>
</form>

Extending the application

You can define new actions for your controllers. Every action is a function in the controller class. If you want to create an action to map 'something' (in a URI like ?c=user&a=something), add this method to the controller class:

require_once("models/user.php");

class UserController extends Controller {

	function UserController() {
		$this->factory = new UserFactory();
		$this->model = "user";
		$this->defaultAction = "list";
	}

	
	function handle_something() {
		$this->present('some string');
	}
	

}

$appcontrol = new UserController();

If now you access ?c=user&a=something, a screen with your website template with 'some string' written in the content part should appear in your browser. This is a simple way to demonstrate how to create new actions; they can call other functions, start/delete session variables, present views, redirect the user and do anything else your normal PHP code does.

Notice the syntax! The method to handle an action must start with 'handle_', followed by a lowercase version of the action name.

Ex: To handle a login action in the user controller, you should create a method named handle_login, and then access it by ?c=user&a=login.

Detox Architeture

Detox was build using the Model-View-Controller design pattern. This way it decouples presentation from business logic and data models, being the industry standard architeture for web applications. More on the MVC design pattern should be provided with new versions of this documentation.

The Controller class

The Controller class is located in /core/controller.php and is the base class for all controllers in the application. It contains the methods to present views (files or other contents) and handle requests. All controller classes you create should extend this one; if you donīt want to do that, notice that the class you create will need at least to have a method named handle(), as it is called from the ApplicationController when handling the requests.

The ApplicationController class

This is the class responsible for parsing the requests and calling all other controllers. It is defined in /core/application.php and by default only one object from this class exists; the one in the index.php file in your application root folder.

Any code you write inside the ApplicationController constructor will be performed every time a request is performed to your application. This is a simple way to perform tasks like login check and more.

User-defined controllers

Any user-defined controller must be placed in a file on the /core folder. There must be only one controller per file, and an object of the controller should be created after its class definition in a variable named $appcontrol. The ApplicationController object in the index.php file will use by default the controller recorded in $appcontrol to handle the request after dynamically including the controller file.

How requests are handled

All requests for your application must be directed to the index.php file in the root folder of your application. The request is then parsed by the ApplicationController object, that dynamically include the corresponding controller file for your request (if your request was ?c=user, the ApplicationController will call /core/user.php).

The included controller file have a definition of the controller class (UserController, for example) and an instantiation of this class as $appcontrol. The controller instance in $appcontrol is then used by the ApplicationController to handle the action in the request. If the action does not correspond to a method in the controller called in the URI, then a 404 error will happen. A 404 will also happen if the user request a unexisting controller. The 404 page can be customized in /views/404.html.

Object-Relational Mapping

Detox offer some object-relational mapping capabilities for its models with the Recordable class. Any class that you wish to use with Detox object-relational mapper should extend the Recordable class in the /core/models/recordable.php file. These classes will have by default methods to handle create, list, update and delete actions and will use instrospection to check your model object state and record it on the database. These classes also will need views to support these actions (what you are going to show in this views is up to you).

The Detox OR Mapper

While OR mapping can save much development time, the OR mapping functions in Detox are still under heavy development, and may become an independent project. We looked for some PHP OR Mapper, but all of them seemed to be too bloated. OR Mapping is one of the major concerns for the next versions, and for now you can try to use it, but if it do not work properly, just consider about writing the SQL for your models by yourself. It is not a hard task at all; just take a look below.

Writing your own SQL

To write your own SQL for your models, just do not extend the Recordable class while creating your models classes, and write the methods to handle the operations in the database (list, create, edit, delete) by yourself.

In this case you will need to include the core/db/connector.php file in your model file, and create an instance of the Connector before executing any database operation.

To execute the sql, call the executeQuery method of the Connector object you created. Something like this:

$conn = new Connector();
$results = $conn->executeQuery('select * from users');

About this documentation

This reference manual is a work in progress, and is part of an effort to document and give directions to the development of future versions of the Detox framework. Notice that this was not written by a native english speaker and corrections and contributions are welcome; translations are also welcome, but notice that this documentation may suffer big changes for the next versions (as the framework itself).

License

The Detox Framework is free software and can be used, distributed and changed under the terms of the BSD License.

Copyright (c) 2008, Rafael da Silva Rocha 
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.