Remote Scripting (AJAX) framework

Spare time to spend on interesting projects is not plentiful nowadays. Even so I have managed to put quite a few hours into a small web application framework. My goal is to make it easier to develop web applications that heavily depend on client server communication. I really want to get rid of the painfully boring and repetetive task of validating form data and sending it to a backend in PHP where the data has to be validated again. The framework is based on XMLHttpRequest for the communication between the client and the server. This kind of communication is commonly known as Remote Scripting. Some people (not me) likes to use the new, more catchy, acronym AJAX. Anyway, this is a sneak peak on how the framework will be used.

Introduction

First I had a look at JPSpan and other similar implementations. Impressive as JPSpan is, I thought it a bit too much for me. I don’t need, or want, transparancy between javascript and PHP classes. To be honest, I really don’t like hiding the communication between client and server as it mostly creates problems. Pretending that the network isn’t there usually gives birth to architectures with a huge amount of method calls over the network. It is better to work with data on the client side, validate it and then send it to the server for the real work. However I did like the serialization into a streamlined XML format and thus I have adapted that in my solution.

The framework which has the wonderfully dry working name of SSRS is getting more and more complicated. I started working on a simple synchronous http communication between javascript and PHP. Now I am ending up with a framework for binding form fields to method calls with automatic validation of data. Still I think it is going to be really useful when production ready.

The HTML form

What is it then and what you do you do with it you ask? To show it off a bit I’ll give you a simple example. The below form is an extremely simple user form. It features a readonly field for the unique user id which of course will be empty when we create new users. When I use this form to create a new user I don’t want the page to reload. It is unecessary slow. But I still want the User_id field populated when the user has been saved.

<form id="User" onsubmit="return saveUser();">
<fieldset>
    <legend>User details</legend>

    <label id="lbl_User_id">Userid</label>
    <input type="text" readonly="1" id="User_id" />

    <label id="lbl_User_login">User login</label>
    <input type="text" id="User_login" />

    <label id="lbl_User_email">Email</label>
    <input type="text" id="User_email" />
    <a href="#" onclick="return saveUser();">Save</a>
</fieldset>
</form>

I have added an onsubmit handler and a link that both call the javascript function saveUser(). I could just as well have used a normal submit button.

The PHP class

To handle users I have created a User class implemented in PHP. The class have a save() method that takes id, login and email as parameters. The id is not mandatory. To be able to return more data than just a value, result data is always returned as key value pairs in an array. When errors or problems are encountered exceptions are thrown which automatically will be passed to the client as javascript exceptions.

class User
{
  public function save($id, $login, $email)
  {
    if ($id == null || $id == 0)
      {
        error_log("Creating new user");
        // Validate data
        // Save user
        // Retrieve the new numerical user id in $id
        $id = 1; // For the example
        return Array('id' => $id);
      }
    throw new Exception("Updating a user is not implemented");
  }
}

Tying them together

So what do I as a developer need to do to connect these two loose ends? Before we create the saveUser() function mentioned above we need to setup the form against SSRS. A few lines of javascript in an onload handler or an explicitly called init function is needed.

var g_user = null;
var frm = null;

frm = new Array(
	new Array('User_id', 'number', '', '', false, '', ''),
	new Array('User_login', 'string', 'A unique login',
		'Login not valid or not unique', true, 4, 8, ''),
	new Array('User_email', 'email', 'Email address is required',
		'Email is not valid', true));

g_user = new RemoteObject('postHandler.php', 'User');
g_user.bindFields(frm);
g_user.bindParams('save', 'User_id', 'User_login', 'User_email');

What the above essentially does is:

  1. Create the client object and tell it what server class to use and which URI to communicate with. The postHandler.php is the backend implementation.
  2. Create a structure that describes field data types, help and error messages, max/min length, etc.
  3. Bind the form to the client object and bind form fields as parameters to method calls.

The framework can handle strings, numbers, decimals, emails, string lists and more. For each datatype it is possible to set various constraints. For some datatypes it is also possible to specify your own regular expression to use as validation.

When this is done we can create the actual saveUser() function.

function saveUser()
{
  var result;
  try
    {
      result = g_user.execute('save');
      document.getElementById('User_id').value = result.item(0);
    }
  catch(ex)
    {
      alert(ex.message);
    }
  return false;
}

That is all. As we have bound the form to the g_user object all the fields are validated prior to being sent to the server. The error messages specified for the fields above will be displayed if needed. Any exception on the server side will also be displayed in the same way. As the fields User_id, User_login and User_email are bound to the save method they will automatically be handed over the PHP method save() in the User class.

Conclusion

The data being sent between client and server is encoded in a simple streamlined XML format and is always validated against a DTD to ensure the data is encoded correctly. This does not mean that you don’t need to check the data on the server side but it does add an extra layer of data security. It is also a lot simpler to validate the parameters in a method, where it should be done, than filtering $_GET or $_POST arrays before calling PHP functions or methods.

The benefits of using a framework like this is that it lets the developer concentrate on the functionality. Another benefit is that it does not interfere with your choice of template engine. I have a few things left to iron out before I release the code.

Javascript, PHP

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Leave Comment

(required)

(required)