Excellent news - there is now a formalised non-profit association to support Drupal. From the full press release:
The Drupal Association exists to provide the logistical and financial foundation necessary to support the Drupal project's exponential growth and to provide the Drupal project with new possibilities regarding infrastructure, marketing and funding. The Drupal Association will not be involved in decisions regarding the development or direction of the Drupal project itself.
This will make it possible for people to donate directly to Drupal (rather than individual developers), help create infrastructure to support the growth of Drupal, organise events and actively promote Drupal. Can't be a bad thing.
I haven't been blogging much recently. I kind of fell out of love with it for a while, and realised I was putting myself under too much pressure to produce stuff. While I have a few readers, I decided it's not worth the effort forcing myself to write stuff, just to keep my blog popular. So I've been kicking back, going to bed early, leaving the computer at work, doing nothing in the evening, watching more DVDs. Plus I was off work for a couple of days with a cold, which took me out of it for a while. That's why it's been a bit quiet round here.
But I'm back in the saddle now, rewriting my PHP course and reviewing open source CRMs for the OpenAdvantage website (SugarCRM has been occupying me for most of the last week: it's a beast [how bloody hard is it to setup email campaigns?!], but I figured it was worth indulging the time, as people keep ringing me up about CRMs - it's this year's CMS). I spent a couple of days just writing a glossary of CRM terms to get my head around it (which will be part of my review eventually). Any suggestions for open source CRMs I should consider for my review, put 'em in the comments. Here's my current short list (NB some of these aren't CRMs, or just have CRM bits, but I thought alternatives for contact and project management might be handy too):
Some of these aren't even open source (probably) and some will get dismissed flippantly out of hand (I haven't got time to go in-depth on all of them), but there you go.
Next week sees me visiting the House of Commons for the launch of the National Open Centre project (yes, it's a Drupal site). Funding is still being sorted out, but we're hopeful it will come off. The launch "party" will be the official start of the project (without funding, but we're going ahead anyway). I'm still working full time at OpenAdvantage, and it will be interesting to see how (if) we morph into the NOC, and what my duties will be then. Like OpenAdvantage, it's tricky to predict until you get into it, but I'm sure it will be interesting: open source and open standards, but at a policy level, is the aim, but how that will translate into day-to-day work I'm not sure.
I don't normally advertise OpenAdvantage events on this website, but I'm really proud of the one we've organised for the 28th February on Open Source Content Management. We've put together four speakers from UK small businesses (three from the West Midlands), each talking about a prominent open source CMS:
The idea of the seminars is to give a warts and all account of how open source CMS can be used within a business, not from a sales angle but from a technical/business one. The seminar is FREE to anyone based in the West Midlands region. I think it's going to be a really interesting morning, and I'd encourage you to sign up now.
Everyone seems to be rabbiting on about Yahoo! Pipes. It's an impressive Web 2.0 Ajax GUI for building "mashups". You basically get a series of components you can plug together to build a feed-producing web application. These can be grouped in terms of functionality roughly like this:
It's quite a limited tool set (for example, the transformations possible are quite limited - you can't generate HTML or XML other than RSS-style feeds, do any advanced path-based querying, or seemingly use any old HTML page as an input). But it is very powerful if you're a non-programmer who doesn't have access to this stuff through raw coding.
As to the interface: apart from a few display bugs on Firefox, it works remarkably well, and has some extraordinary touches (like the rendering of the pipes themselves) which make it feel very desktop-like. Here's a screenshot:

As a coder, I abhor GUIs for writing applications, and actually find them conceptually difficult to approach (I'm not a visual person). It took me a while to work out how to actually run a "pipe" (the name for an application you've built) (double-click on the Pipe Output component and it displays in the debug window) or run them from a plain URL (click on "Back To My Pipes" - "kicking off my boots/going back to my pipes" - to see the list, click on a name, then click on "Run"). Plus the interface got a bit cluttered, and some things didn't quite seem to work (for example, if you're using a filter, it will allow you to filter on the XML elements in the output document - so you need to provide both filter conditions for the elements of RSS feed items and for the elements of Atom feed items if your filter is supposed to work on both).
Here's the public URL for the pipe above (which shows you items from my RSS feed matching some word): http://pipes.yahoo.com/pipes/Lqqx2yy42xGybXUdJxOy0Q. Or you can call it with a querystring to supply the search term: items with Drupal in title or body. Or get the results as RSS. (One gripe here: I'd like to just take the original URLs and append &_render=rss, but this doesn't give you what you want. As it is, I just got the RSS URLs from the main pipe display.) This is actually useful already: it means anyone can just get items from my RSS feed matching some keyword they are interested in.
You can go further and make this more generic, so the user could request any feed and keyword, and the pipe could return matching items: like this pipe I cloned from the above. For example, this link gets entries matching the term "Jokosher" from Jono's feed; this one gets items matching the term "ingredients" from Chloe's feed. In both cases, you can also get an RSS feed for the pipe: here's one for Jono and Jokosher, another for Chloe and ingredients. This makes Pipes even more useful, and turns it into something I could even see myself using: very useful for writing quick filters and aggregators of RSS feeds where your needs are simple. For serious web scraping it's not quite the ticket, but people like me are not necessarily the target market anyway.
It reminds me of trying to write music using PureData: you're plugging outputs into outputs, putting boxes to filter outputs before they reach inputs, etc.. Kind of like a web patch panel for you old-time synth enthusiasts.
To conclude: really nice, great for building simple feed consumers and manglers, and definitely worth a look if you're not a programmer but want to get yourself a piece of Web 2.0.
Since I've upgraded townx.org, I also had to upgrade mooch labs and Rails West Midlands. I've finished this now.
By the way, upgrading from Drupal 4 to Drupal 5 wasn't as straightforward as I'd like. The database upgrades worked for my two simple sites, but I rebuilt the database from scratch for this site, as things didn't quite seem to work when I tried to run update.php. Not sure why. So here was my process:
There were other bits and pieces I've probably missed, but that about sums it up.
I finally got round to swapping to Drupal 5. This has taken me a good three hours work, fiddling with databases, exporting SQL, moving files around, checking stuff out of CVS etc.. The upside is I now have a nice cleaned-up install. There are a few minor differences, but not too many:
Let me know if you come across any issues.
My eyes aren't what they used to be. (I remember when all this was fields...) Consequently, I have the fonts pushed up to a minimum size of 16 inside Firefox, to stop me getting eyestrain. I also have the Google Toolbar and the Web Developer Toolbar switched on all the time. All of which means the amount of space available for web pages is pretty minimal. (My display is 1280×768, as I just use my laptop all day rather than an external monitor: providing I keep the fonts big and the backlight up, it's fine, particularly as the IBM laptops have such great keyboards and I use an external mouse).
All of which preamble leads up to this point: why are there so many websites which break when you turn the font up or have reduced screen real estate? A few examples from today:
I could go on. Please, please stop trying to make everything look like a printed brochure. Just build websites that people can use with their own choice of font and browser window size (fixed-width designs with absolute positioning which don't scale properly are the main culprit). I feel like I've been banging on about this for years, and still nothing changes. Accessibility is not just about people with disabilities: it's also about catering for old timers with fading eyesight (and greying hair). Not everyone uses 8 point fonts on an enormous outdoor-movie-theatre-sized monitor.
(By the way, I know my Drupal theme sometimes screws up, so I'm not innocent. I'm planning an upgrade to Drupal 5 before too long.)
Jokosher is an audio production tool, designed for multi-track recording, which runs under Linux. The primary design goal was ease of use. Jono today called for Jokosher testers, to iron out bugs in Jokosher for version 0.9.
The application has come a long way, and is kind of usable in its current incarnation (not currently suitable for the kind of music I do [electronica], which needs lots of low-level wave editing, sampling and looping, but I'm just putting in bug reports and feature requests). It is impressive what's been achieved so far, and I'd like to see it become more general-purpose, so I can use it for my own audio production. I had got 0.2 working pretty easily, and submitted a few bug reports, then realised the team wouldn't be interested in that, and had probably fixed a load of the bugs. So I decided to bite the bullet and try it out properly from the latest version.
The biggest struggle is getting the thing installed. You're OK if you have a bleeding edge Ubuntu (Feisty) as it is packaged for that, but if you want to help with the testing, you'll need to get the CVS versions of Gstreamer and associated libraries, plus a checkout of Jokosher from Subversion. This turns out to be a bit of a pain, so here are some pointers if you're on an old Ubuntu (like me with Dapper). I won't replicate all the documentation here (there is a fine amount on the Jokosher userdocs website), but I'll try to summarise and provide pointers to the right places:
I got my instructions from http://userdocs.jokosher.org/InstallingCvsGstreamer and http://userdocs.jokosher.org/Installation. But here they are boiled down to the essentials (for Ubuntu Dapper):
# make a directory to put everything into # (Gstreamer CVS, jokosher etc.) mkdir ~/apps/jokosher cd ~/apps/jokosher # pull gstreamer (and associates) from CVS mkdir gstreamer mkdir gstreamer/head cd gstreamer/head cvs -d:pserver:anoncvs@anoncvs.freedesktop.org:/cvs/gstreamer co gstreamer \ gst-plugins-base gst-plugins-good gst-plugins-ugly gst-python gnonlin # pull trunk jokosher from SVN cd ~/apps/jokosher svn checkout http://svn.jokosher.python-hosting.com/JonoEdit/trunk jokosher-trunk # setup dependencies to build everything; NB there are a LOT of these: # this is just a list of the ones which have been identified, but there's a # chance there are others; you'll soon find out if the compilation step fails... sudo apt-get install build-essential automake1.7 libtool libglib2.0-dev \ libxml2 liboil0.3-dev python-dev python-gtk2-dev bison flex libxml2-dev \ libgnomevfs2-dev libasound2-dev libspeex-dev libflac-dev libtag1-dev \ libhal-dev libogg-dev libvorbis-dev libid3tag0-dev libmad0-dev # here's the tricky bit: getting a backport of liboil0.3.8, which # gst-plugins-base needs (Ubuntu Dapper has version 0.3.6 or something); # note that I've done this rather recklessly, and hope it won't cause # horrendous clashes with other installed versions of liboil; # it doesn't complain, anyway wget http://backports.org/debian/pool/main/libo/liboil/liboil0.3_0.3.8-0bpo1_... wget http://backports.org/debian/pool/main/libo/liboil/liboil0.3-dev_0.3.8-0b... sudo dpkg --install liboil0.3_0.3.8-0bpo1_i386.deb sudo dpkg --install liboil0.3-dev_0.3.8-0bpo1_i386.deb # setup a script which will run the CVS gstreamer alongside # any existing gstreamer you've installed cp gstreamer/head/gstreamer/docs/faq/gst-uninstalled ./gst-head # make it executable chmod +x gst-head # edit it: you need to change the line which starts MYGST so # it points to the directory ABOVE the head directory, where # you checked Gstreamer out; in my case: # # MYGST=$HOME/apps/jokosher/gstreamer # create a script in ~/apps/jokosher/gstreamer/head called # build_all.sh to build all your gstreamer bobbins # from source, keeping it inside the ~/apps/jokosher directory; # it looks like this: /* START SCRIPT */ #!/bin/bash # build all the gstreamer stuff for f in gstreamer liboil gst-plugins-base gst-plugins-good gst-plugins-ugly gst-python gnonlin; do cd $f echo "Building $f" make distclean rm -rf po cvs update -PAd ./autogen.sh make # don't do make install here, as this will trash existing libraries cd .. done /* END SCRIPT */ # make it executable chmod +x ~/apps/jokosher/gstreamer/head/build_all.sh # now we're ready to build cd ~/apps/jokosher # setup the build environment so everything points # at the right versions # of gstreamer etc.; # NB calling this drops you into ~/apps/jokosher/gstreamer/head ./gst-head # and once there you can build everything with: ./build_all.sh
That does the building part. To run Jokosher once you've done all that:
cd ~/apps/jokosher ./gst-head ~/apps/jokosher/jokosher-trunk/Jokosher/Jokosher
This worked for me! I'm now ready to try out the delights of bleeding-edge Jokosher.
The BBC are seeking feedback from the public about how their proposed on-demand services should be structured and regulated. There's a document about it on their website which outlines the original proposals, plus how they were toned down by Ofcom to make them more constrained and less useful to licence-fee paying households. I understand people getting jitters about competing unfairly in the marketplace (e.g. entertainment companies which produce CDs and DVDs losing custom because ITV provides downloads). But in the case of the BBC, I'VE ALREADY PAID FOR THE CONTENT (yes, I feel the need to shout). I pay my licence fee, like most other people in the country, and have already funded production of the BBC's programmes. Why should I pay again for a DVD? Why can't I download dramas etc. which I've missed, for free, forever?
It's really important if you live in the UK that you participate in the BBC's Consultation on On-Demand Services. and make your case. I basically went on about the above in my response, plus highlighted that I didn't want DRM, I wanted everything available forever for free, and I wanted it on my Linux laptop. I tried not to sound like a free software maniac and make reasoned arguments with examples. We need as many people as possible to participate in this, otherwise we'll end up with another crippled, inaccessible on-demand service (4od, anyone?). When are the media going to wake up and give people what they want?
No Ruby Tuesday this week, as I've not been Ruby programming. Instead, I've been having a look at the Symfony PHP framework, to see whether it shapes up to Rails. As I've stated previously, Rails is a pain to run on dirt-cheap hosting (though options like Planet Argon are out there, cheap enough, but I haven't tried them yet); plus Ruby is another language to learn for the people I work with at OpenAdvantage, and most of them have got enough to do running small businesses. I wondered whether Symfony is good enough to recommend as an alternative to Rails for programmers who already know PHP.
In short: it is.
It's not perfect, not as concise as Rails, and lacks many of the features. But using it is a damned sight easier than writing a PHP application from scratch. I'm not going to do a thorough feature listing (see the Symfony site for that). Instead, here are some of the notable things about it that improve the life of PHP programmers:
Next, a few specifics and code samples to give an idea of how it works.
I chose a wiki as the project to experiment with, and have spent about a day and a half coding in Symfony. The result (fancifully called Flow My Thoughts, The Policeman Said) is an extremely simple wiki which supports camel-case links, [[]] links and Textile markup.
For the wiki parsing part of it, I borrowed some code from the Drupal freelinking module and from TextilePHP. Along the way I fixed TextilePHP so that it works properly with strict error reporting on (there were lots of references to unset variables and possibly non-existent array indexes which meant I got around 100 error messages the first time I ran it). This means I can write wiki links as well as mix in Textile markup (I am a big fan of Textile). Don't you just love open source?
For the main part of the project I started with the Symfony sandbox download, as this includes all the libraries for Symfony in a tarball. You can also install the dependencies with PEAR, and would want to if using Symfony for several projects. I also went with SQLite for experimenting with.
First off you edit a schema.yml file with details of your data model. This works pretty well, and is a bit like writing a migration. You can either use the sensible Symfony defaults or work with the Propel syntax directly (e.g. if you want specific options or indexes set for fields). My model looks like this:
propel:
page:
_attributes: { phpName: Page }
id:
title: { type: varchar, size: 255, index: unique }
content: longvarchar
created_at:
updated_at:
Nothing too unusual there. Also notice the "magic" Rails-style fields, created_at and updated_at.
To build the model classes from your schema, you run:
php symfony propel-build-all
The symfony file is a Pake build script. The propel-build-all task generates some XML from your YAML files, which gets converted into PHP classes representing your tables. In my case, I got four files: BasePage, BasePagePeer, Page, PagePeer. Then it generates some SQL and builds your database. All very migration-like. However, there's no sense of "up" and "down" in Symfony, and it's probably hard to version the database schema incrementally, like you can in migrations.
As I mentioned above, the PHP classes are chock-full of getter and setter methods. Far more wordy than ActiveRecord's default two-line class definitions, and a consequence of the lack of runtime class extension in PHP. However, only the Base classes (in my case, BasePage and BasePagePeer) are regenerated when you recreate the model using Pake. This means you can add your extensions into the classes which inherit from the Base classes (i.e. Page and PagePeer).
Symfony supports generation of a CRUD interface (i.e. scaffolding) from the model too:
php symfony propel-generate-crud frontend page Page
This actually creates an application called "frontend" inside your app. directory. This is interesting, as it illustrates how Symfony applications can be structured into parent-child relationships, unlike Rails where it's pretty flat.
You can get at your application in development mode by browsing to (e.g.) http://localhost/frontend_dev.php/page. This will use the default views for the CRUD interface.
The scaffolding sits inside the frontend application, and can be used to selectively override the defaults for the application. I added some directories to my page module:
apps
frontend
modules
page
actions
lib
helper
templates
validate
Note here that I can either add helpers for the module, or I can place them under frontend > lib > helper to add them to the whole application. This mirrors the distinction between application level and controller specific helpers in Rails, but is reflected by the directory structure, rather than by file naming. This seems unnecessarily complex, particularly if you're used to Rails. The other directories are fairly obvious, hopefully.
Routing is one area which had me foxed. I wanted to be able to use a URL like this:
http://localhost/wiki/page/NameOfMyPage
to be able to navigate to the page with the title NameOfMyPage. However, I couldn't for the life of me get this to work. In the end I had to settle for:
http://localhost/wiki/page/show/title/NameOfMyPage
Note that the link_to helpers are a bit unwieldy compared to Rails, particularly as you don't have the luxury of symbols and automatic hashes from arguments like you do in Ruby:
echo link_to($page_title, 'page/show?title='.$page->getTitle());
Even though this is only slightly more opaque and verbose than Rails, I think it would wear on me after a while.
The scaffold specifies the actions you'd expect by default: for the page model, they ended up in apps/frontend/modules/page/actions/actions.class.php. Adding my own was simple enough. For example, I wanted to show a page by title. Showing a page by ID was supported by the scaffold already:
public function executeShow() {
$this->page = PagePeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($this->page);
}
Mmmm, not quite as succinct as Rails, I was thinking. You can see the Torque-style (Propel) syntax for retrieving records in the first line of this method definition. Note that the template to render is implicit, and maps to apps/frontend/modules/page/templates/showSuccess.php.
First, I added a new method to the PagePeer, to retrieve a record by title. This is located in lib/models/PagePeer.php, outside the application. The idea is you are likely to have multiple applications supporting a single model. On the other hand, it's probably possible to create models specific to individual applications (maybe even modules):
public static function retrieveByTitle($title) {
$c = new Criteria();
$c->add(self::TITLE, $title);
return self::doSelectOne($c);
}
The Criteria class used here is part of Propel, and it works pretty well (again, very Torque-like). Though again, more verbose than ActiveRecord. (Thanks to Scott Meves' comment which cleaned up the above function.)
Then I added an action to frontend/modules/page/actions/actions.class.php:
public function executeShowByTitle() {
$this->page = PagePeer::retrieveByTitle($this->getRequestParameter('title'));
$this->forward404Unless($this->page);
$this->setTemplate('show');
}
Notice that this reuses the 'show' template (setTemplate() specifies the one to use if different from the inferred template).
I created my own helper to show error messages in apps/frontend/lib/helper/ErrorMessagesHelper.php:
<?php
function error_on($field) {
$error = sfContext::getInstance()->getRequest()->getError($field);
$out = '';
if ($error) {
$out = content_tag('div', $error, array('class' => 'error'));
}
return $out;
}
?>
Notice how I had to go round the houses to get at the error messages on the object. For some reason, error messages aren't stored on the object, but in the request. This makes them pretty hard to get at, and you have to use the Symfony context if you are not explicitly within a view. Also notice that there is a content_tag helper.
I can load this my helper into a template with:
<?php use_helper('ErrorMessages') ?>
Nothing special here. Just HTML with PHP, plus some PHP helpers to make life a bit easier. For example, here's my edit form for pages:
<?php use_helper('Object') ?>
<?php use_helper('ErrorMessages') ?>
<?php echo form_tag('page/update') ?>
<?php echo input_hidden_tag('id', $page->getId()) ?>
<p><strong>Title</strong>
<?php echo object_input_tag($page, 'getTitle', array('size' => 80)) ?>
<?php echo error_on('title') ?>
</p>
<p><strong>Content:</strong><br/>
<?php echo object_textarea_tag($page, 'getContent', array('size' => '80x10')) ?>
<?php echo error_on('content') ?>
</p>
<hr />
<?php echo submit_tag('save') ?>
<?php if ($page->getId()): ?>
<?php echo link_to('delete', 'page/delete?id='.$page->getId(), 'post=true&confirm=Are you sure?') ?>
<?php echo link_to('cancel', 'page/show?id='.$page->getId()) ?>
<?php else: ?>
<?php echo link_to('cancel', 'page/index') ?>
<?php endif; ?>
</form>
I could have used the short PHP <?= ?> syntax to make this less verbose, but went with the most portable syntax. Note that there are equivalents for Rails' form_remote_tag etc..
Validation is set up in YAML files (reminds me of Struts). For example, I wanted to make sure that both title and content are set for a wiki page. To validate an action, you have to add a YAML file named after the action: in may case, I wanted to validate the update action, so I added apps/frontend/modules/page/validate/update.yml:
methods:
post: [title, content]
fillin:
enabled: on
names:
title:
required: yes
required_msg: 'Please enter a title for the page'
content:
required: yes
required_msg: 'Please enter some content for the page'
Again, not as nice as Rails, but more declarative, perhaps. The fillin option has to be enabled for auto-form-population to be turned on.
I haven't mentioned the testing framework which is built into Symfony, as I didn't use. Note also that it supports separate development and production environments, like Rails, but they run concurrently: you access the development environment through a modified URL, rather than by running the application in a different mode. That's quite nice.
Another feature I liked is the console you get in development. This shows you log messages pertinent to the page, the SQL queries run, and general stuff about the environment, presented as an AJAX-ified menu across the top of the app.. I'd love to see something like this in Rails.
I started putting Ajax into the application, but in-place editors don't work very well with wiki pages (you need to be able to click on links in the page when a page is displayed, but the in-place editor turns the whole page into a clickable field which displays an edit form, as in Rails). So I abandoned that. I also experimented with using the TITLE field as the primary key instead of ID (use of ID fields is encouraged in Symfony, as in Rails), but this was hard work, so I went back to IDs. I also didn't get round to authentication.
That's as far as I went with the application, and I'm unlikely to go further. I've attached it to this post for anyone who's interested (licence is GPL).
I put these few samples of Symfony code up to give a flavour of the differences and an impression of how it feels for a Rails programmer. It is not a thorough or complete evaluation. Try it for yourself. I have to say that the tutorial on the Symfony website is pretty good; and you can also get a full book on Symfony from the site (or a print version). (Come on DHH and Dave Thomas, when are we likely to see Agile Web Development for Rails given away? I've already bought it twice.)
Symfony has a lot going for it. It's pretty easy to get up and running. But by contrast with Rails, it is very verbose because of how PHP works. On the plus side, it is similar enough to Rails to make it fairly easy to transition to; and you can run it on normal web space at high speed without having to fork out for special hosting. That last point is very important to my mind. Coupled with the fact that there are lots of PHP programmers out there already, or Java programmers looking for a lightweight framework but scared of Ruby, and I can see it growing at a reasonable pace. I would certainly consider it if I needed to write a scalable web application for myself; I've even considered rewriting Flickrlilli using it, to see if it makes a difference and to get a better comparison. You never know...