In my AJAX introduction post I talked about SAJAX and JPspan this posts walks you through installing JPSpan and writing the same simple Hello World app as we did in the SAJAX post.
Setting up JPSpan
- Download JPSpan: http://prdownloads.sourceforge.net/jpspan/
- Extract and copy the extracted folder to somewhere in your include path
- Your good to go
Create the JPSpan server component
JPSpan provides a lot more functionality then SAJAX, the biggest difference you notice on the javascript side of thing is that you have mapped objects, on the php side the biggest difference is that you have a server page and a client page.
The default JPSpan server is called JPSpan_Server_PostOffice, it can be used to map entire classes to javascript, or you can pick and choose. If you were using the server on a large site you might want to add a get flag called class to limit which classes get included and registered to limit the overhead, but I haven’t had any performance problems just letting 4 or 5 integration specific classes be registered all the time.
Note: the JPSpan examples set a constant called JPSPAN_INCLUDE_COMPRESS, that strips javascript whitespace, the code that does this performs horribly, so make sure not to turn it on
<?php
// Hello World class goes here will show that next
// Including this sets up the JPSPAN constant
require_once ‘JPSpan/JPSpan.php’;
// Load the PostOffice server
require_once JPSPAN . ‘Server/PostOffice.php’;
// Create the PostOffice server
$S = & new JPSpan_Server_PostOffice();
// Register your class with it…
$S->addHandler(new HelloWorld());
// This allows the JavaScript to be seen by
// just adding ?client to the end of the
// server’s URL
if (isset($_SERVER['QUERY_STRING']) &&
strcasecmp($_SERVER['QUERY_STRING'], ‘client’)==0) {
// Compress the output Javascript (e.g. strip whitespace)
// turn this off it has performance problems
define(‘JPSPAN_INCLUDE_COMPRESS’,false);
// Display the Javascript client
$S->displayClient();
} else {
// This is where the real serving happens…
// Include error handler
// PHP errors, warnings and notices serialized to JS
require_once JPSPAN . ‘ErrorHandler.php’;
// Start serving requests…
$S->serve();
}
?>
App code
The app code is really quite simple, just like in the SAJAX case, here I just copied and pasted it into a class and put the session setup code in the constructor. You can do anything you would with a normal class here, but remember, this class is being recreated for each call from the javascript side, so if you want to keep class members between calls you’ll need to put the class instance in the session.
class HelloWorld {
function HelloWorld() {
if (!isset($_SESSION['strings'])) {
$_SESSION['strings'] = array(‘Hello’,‘World’,‘Hello World’);
}
}
function addString($string) {
$_SESSION['strings'][] = $string;
return $this->stringCount();
}
function randomString() {
$index = rand(0,count($_SESSION['strings'])-1);
return $_SESSION['strings'][$index];
}
function stringCount() {
return count($_SESSION['strings']);
}
}
HTML code to display it
There is greater seperation between html and php when using jpspan, you include auto generated tieing code, this should allow for easier client side caching with a little header work, which is useful if your just using the code to add an autocomplete widget to a current site.
JPSpan can be used asynchronously (using callbacks) or synchronously (directly returning), generally you want to use things asynchronously since sync calls can cause the ui to freeze while your waiting for feedback. Sometimes this is actually what you want, but you’ll want to post some sort of please wait message if your transfering much of anything. More detail are given in a JPSpan tutorial on the projects wiki. In this example were using all async calls to match the SAJAX HelloWorld app.
<html>
<head>
<title>JPSpan Hello World</title>
<script type=’text/javascript’ src=’server.php?client’></script>
<script>
// create a javascript class to hold or callback methods
var hwCallback = {
randomstring: function(result) {
document.getElementById(‘canvas’).innerHTML += ‘
‘+result+”;
},
stringcount: function(result) {
document.getElementById(‘count’).innerHTML = result;
},
addstring: function(result) {
document.getElementById(‘count’).innerHTML = result;
}
}
// create our remote object
// note the lowercase mapping, this is because in php4 php classes and functions have no case
// in the server you can register each function adding the case back
var remoteHW = new helloworld(hwCallback);
function setup() {
remoteHW.countstring();
}
function do_addString() {
remoteHW.addstring(document.getElementById(’string’).value);
document.getElementById(’string’).value = ”;
}
</script>
</head>
<body onLoad="remoteHW.stringcount()">
<input type="button" name="check" value="Show Random String" onclick="remoteHW.randomstring(); return false;"/>
<div>Number of Random Strings: <span id="count"></span></div>
<div id="canvas" style="border: solid 1px black; margin: 1em; padding: 1em;"></div>
<div>
Add new String:
<input type="text" name="string" id="string" size="20"/>
<input type="button" name="check" value="Add new String" onclick="do_addString(); return false;"/>
</div>
</body>
</html>
If you were paying attention to the app code you might have noticed one minor difference between this JPSpan version and the SAJAX version. Addstring returns the count in this version, SAJAX automatically handles multiple async calls at once JPSpan doesn’t seem to so all that extra remote call gives JPSpan a problem.
This project is the first time i’ve used SAJAX and I think its ability to handle multiple outstanding calls is a big benifit. There is nothing to stop JPSpan from adding this ability but it has had a release lately so im guessing it will need someone to step up to the plate and write some actual code to get it done.
View Hello world app, server.php source, index.php source
In my next post i’ll investigate how well SAJAX and JPSpan handle passing complex data types.