codem - blog

Archive for February, 2009

providing patches in feature-based web development

A while back, I did a presentation to the Sydney PHP Group on feature based web development using Bazaar, a distributed version control system. At the time is was quite interesting to see the number of attendees who a) didn’t know about or use version control or b) were using CVS (the instant coffee of version control).

If you are doing web development amongst a team and want a really solid branching system without headache inducing conflict/merge issues then Bazaar is a really valuable tool. One of the best things about patching in Bazaar is the send command:

$ bzr help send
Purpose: Mail or create a merge-directive for submitting changes.
Usage:   bzr send [SUBMIT_BRANCH] [PUBLIC_BRANCH]

The send command enables you by default to mail a patch file to the patch manager, who can then test and merge it into a centralised mainline branch. If you don’t want to mail patches they can be uploaded to the remote server in one go, even though send doesn’t as yet support saving to remote locations.
The trick is to provide ‘-’ (stdout) as the output file then pipe it to ssh for upload to your remote directives location.

bzr send -o - sftp://me@someserver/path/to/remote/branch | ssh me@someserver "cat > /path/to/directives/my.patch"

After bzr does it’s stuff and you’ve logged in to the remote server, a patch file is available (my.patch) that can be applied, tested and either reverted or committed using bzr merge, pull, commit and revert.

Tip 1: if you don’t have SSH access to your server try the bzr upload plugin
Tip 2: storing your public ssh key on the remote server will allow you to perform the send without password prompts.

Centrik foundations 1: client side integration

In the lead-up to the release of Centrik, our internally developed web application framework, we’ve decided to produce a series highlighting the foundation concepts that it’s built on. The first of these will look at how Centrik can trigger behaviours in client side Javascript.

In developing Centrik, we’ve aimed to give developers that extra degree of integration with third party libraries and applications without causing excessive bloat by trying to integrate every different API under the sun. We didn’t want to bundle one Javascript toolkit (or develop our own — who wants to reinvent the wheel) but rather provide a simple translation layer between Centrik and the Javascript toolkit of your choice.
To that end we’ve implemented an ultra-simple signals and slots connector, as a JQuery plugin, to handle transfer of data from the server to the client at document load/ready time. The connector is designed to be generic enough so that it will work with any object oriented Javascript toolkit.

At the fundamental level, this means you can extend your Centrik application using your favourite toolkit, not ours.

What are signals and slots?

These aren’t a new idea, they’ve been used in quite a few frameworks and toolkits over the past few years. The Qt framework summarises it like this:

In GUI programming, when we change one widget, we often want another widget to be notified. More generally, we want objects of any kind to be able to communicate with one another. For example, if a user clicks a Close button, we probably want the window’s close() function to be called.

Our desired outcomes for Centrik are

  1. server side code can trigger signals when the page is loaded/ready, causing their slots to be hit
  2. server side code can bind standard Javascript events to DOM elements, when the DOM is loaded
  3. the Javascript produced by Centrik is loaded quickly and conforms to accepted Javascript coding standards and relevant performance related best practices
  4. the server side code that triggers signals should be easy to write and understand

The parts of our signals and slots connector are:

  1. a signaller to emit signals and
  2. a connector, to bind a signal to a slot

We’ve made the method calling pattern pretty simple:

jQuery.centrik_signal_slot.connect(signalobject, signal, slotobject, slot, priority);

The parameters for connect() are as follows:

  1. signalobject: this can be the id of a DOM element, a Javascript object, the window or the document object
  2. signal: the method on the signalobject that when called will emit the signal that causes the slot to be called. In the case of the signalobject being a DOM element or the window/document, this is a DOM event.
  3. slotobject: the object that is called when the signal is fired. In the case of the signalobject being a DOM element or the window/document,this is null.
  4. slot: the method called when a signal is fired. In the case of the signalobject being a DOM element or the window/document, this is most likely an anonymous function
  5. priority: this parameter, not yet supported, will allow a finer degree of control over the ordering of the slot requests, remembering that one signal can emit to many slots.

Integrating the method calling pattern into Centrik is also quite simple, you just need to provide the connector arguments as an array. For instance here is the built-in Centrik form validation handler adding a validation queue request to the document stream, that is emitted at document.ready()

$args = array(
	'signalo' => "document",
	'signalm' => "'" . CENTRIK_STREAM_CONTEXT_DOMCONTENTLOADED . "'",
	'sloto' => "null",
	'slotm' => "function() {"
		. " jQuery.centrik_form_validator.queue(" . json_encode(array('frmid'=> $form->GetId(), 'frmdata'=>$form->GetJavaScript())) . ");"
		. " }",
	'priority' => 0,
);
$this->stream->Add($args, $form->GetId(), CENTRIK_STREAM_TYPE_JS_SIGNAL);

Centrik then appends this to the document stream just prior to the document being sent to the client:

//iterate $signals as $signal
$connections .= CENTRIK_JAVASCRIPT_SIGNAL_OBJECT . "." . CENTRIK_JAVASCRIPT_SIGNAL_METHOD . "({$signal['signalo']}, {$signal['signalm']}, {$signal['sloto']}, {$signal['slotm']}, {$priority});\n";
//append new connection to document stream

Noting that both the Centrik signal object and method can be configured in Centrik, in case you wish to extend the connector.

As you can see, this is a powerful method of connecting data aggregated on the server side to client side Javascript methods at DOM ready time. Use cases includes building sets of map markers, setting form validation triggers or triggering DOM events based on server side variable values… in fact anything where you want to transfer data to Javascript.

That about wraps it up for Centrik integration with Javascript – simple and a small footprint! Our next foundations post will discuss Centrik form validation, where we use the same code to validate the form on the server and the client.