Rewriting corfield.org using Mach II

Back in November 2002, I rewrote this site using Fusebox. At the time, I said "I'm not going to rewrite my site just to get away from Fusebox" but on December 31st, 2003, I did just that, rewriting the site using Mach II. Given my advocacy of Mach II, it seemed the natural thing to do. [11/19/2004: Converted the site to Fusebox 4.1 - read about that experience!]

How long did it take you? About four hours in total.

What version of Mach II did you use? Initially, a pre-release 0.3.4 version from Alan Richmond. I've since upgraded to 0.3.5 and as of this writing Alan just provided me with 0.3.6. [13/1/2004: I upgraded the site to 0.3.6] Public beta coming soon, hopefully!

But (some of) the URLs still have fuseaction=circuit.fuse in them! Yes, I didn't want to break anyone's bookmarks. I initially set the Mach II eventParameter property to fuseaction and just reused the old compound fuseaction names as event names in mach-ii.xml. I've started using event= now but modified index.php to allow both forms - see below.

What about the display fuses? The only change I made was to replace:

<? $title = "the page title"; ?>

at the top of each display fuse with the following (required for Mach II since the pages execute in a different context):

<? $GLOBALS['title'] = "the page title"; ?>

That's the PHP equivalent of <cfset request.title = "..." /> by the way. That took a few seconds with Dreamweaver's regular expression find'n'replace! All the dsp_xxx.php filenames remained, as did the directory structure.

Didn't you have any action fuses? Only two, in fact. One to send email (from the contact page) and one to construct the bookstore object (which loads and parses an XML file describing the recommended books on my bookstore page). I created a listener class for each original circuit that had action fuses, with a method for each fuse. My former home circuit now has a SendMail.php listener with an email() method, my former bookstore circuit now has a MakeBookStore.php listener with a parseBookList() method. The conversion was pretty much mechanical with just the addition of the configure() method in each case which needed to set $this->__dispatch_map[] (which is a PHP-specific implementation detail of Mach II).

Ah, but you used Fusebox 3's nested layouts, didn't you? Yes, and they were surprisingly easy to convert to Mach II! Each nested layout from Fusebox 3 became a layout view in Mach II, almost unchanged (replacing $Fusebox['layout'] with $GLOBALS['content']). Then I declared an event handler to render the layout view and made sure that each event handler that needed a nested layout ended by announcing the appropriate layout event, e.g., ColdFusion-related events end with:

<announce event="coldfusionLayout" />

That event's handler executes:

<event-arg name="section" value="coldfusion" />
<view-page name="technicalView" contentKey="GLOBALS['content']" />
<view-page name="defaultView" />

The technicalView wraps the current value of GLOBALS['content'] in the original Fusebox 3 nested layout. Yes, it is explicit but it is easy enough to maintain.

Surely there was some tedious legwork to do? Well, yes, the mach-ii.xml file was a pain in the ass to create the first time around. About 350 lines of fairly repetitive event handler and page view declarations that probably took me the best part of two hours to write, making sure I got all the event names correct and the paths to former display fuses. That experience makes me wish for tools to manage the mach-ii.xml file (something I've started working on!).

And you maintained every URL on the site? Er, not quite. If you read my experience converting the site to Fusebox, you'll remember I took a shortcut with the C++ section and made fuseaction=circuit.fuse map directly to dsp_fuse.php without trapping the fuseaction directly? Well, that came back to bite me since Mach II doesn't let you match partial event names. So I bit the bullet and broke those old URLs by doing what I should've done in the first place, namely using fuseaction=cplusplus.section/section/xxx to access dsp_xxx.php. In the Mach II version, the event handler for cplusplus.section renders a view that does this:

include('dsp_'.$GLOBALS['event']->getArg('section').'.php');

(remember that $GLOBALS['event'] is the PHP equivalent of ColdFusion's request.event and -> is the PHP equivalent of ColdFusion's . operator).

How come some URLs have fuseaction= and others have event=? I kept fuseaction= to preserve people's bookmarks and initially I set eventParameter to fuseaction. I prefer event= so today I've changed eventParameter to event and added two lines to my index.php:

if (isset($_GET['fuseaction'])) $_GET['event'] = $_GET['fuseaction'];
if (isset($_POST['fuseaction'])) $_POST['event'] = $_POST['fuseaction'];

This says: if a GET/POST variable called fuseaction is defined, copy it into the matching variable called event. This allows fuseaction= as a synonym for event= so I can switch over to using event= without breaking anyone's bookmarks.

Do you think the conversion could be done completely automatically? Probably but I'm not Steve Nelson so I'm not about to attempt to write a convertor (he has a convertor which takes Fusebox 3 ColdFusion applications and outputs Fusebox 4 applications). I think that - in general - converting to Mach II is a good opportunity to rewrite and rewrite your action fuses into well-designed OO code that cannot be done entirely automatically. And I don't have a large legacy of Fusebox 3 code to worry about either...