Catalyst Decisions

Following on from various text streams on Catalyst ([1], [2], [3], [4]) the next issue is selecting Cataylst plugins.

Personally know Perl from doing glue layer stuff on the command line, so the various web related APIs are all pretty much unknown territory. What’s more had been blissfully passing SQL through DBI (perhaps the nearest thing to DBI in PHP is PDO although PEAR DB was inspired by it I believe) but Catalyst confront’s you with more choice than just DBI.

Anyway – first step is to see what’s available which is probably easiest to do here – many of the packages listed there off unique add-on functionality but others offer competing alternatives. In practically all cases these are wrappers for other libraries in CPAN, packing them in a form that’s easy to use with Catalyst. The two key choices, at least to get started, are for the “Model” and the “View” so it’s a matter of investigating the various Catalyst::Model::* and Catalyst::View::*.

Starting with the latter first, what to use for the View, we’re talking template engines. The Catalyst documentation seems to suggest that Template Toolkit (TT) is the primary choice and if you installed Bundle::Catalyst from CPAN, this will already have pulled in TT along with it’s Catalyst::View::TT wrapper. Template Toolkit was (apparently – lore has it) the inspiration for Smarty and the basic principle is the same – imperative syntax (if/else/etc.) embedded in HTML. While this is not my preferred way to do templating (WACT plug and everything you ever need to know about templating – see here) and even though there is a Catalyst plugin for PHP::Interpreter, I’m all about the obvious / stable choices right now plus TT’s learning curve, from basic experiments, is pretty shallow. That’s not to say TT is the only sane choice – another obvious name I’ve heard of Mason which is being used by Amazon and del.icio.us, among others but gut feeling there is there’s a much sharper learning curve. Open to suggestion here though.

On the Model front, it’s basically a choice between two object relational mapping layers in CPAN – Class::DBI and DBIx (or simply normal SQL through DBI, which I guess no plugin is needed for). Reading around DBIx seems to be the “buzz” but note the “EXPERIMENTAL” warning. At the moment don’t have any strong opinion here – given I’m planning only a very few tables, leaning towards old-fashioned SQL + DBI.

In the name of finding out more, played around with Catalyst::Plugin::CDBI::Sweet – here’s a “Hello World” for interest;

Assuming Ubuntu from now, if you installed Bundle::Catalyst you’ll need to add some more bit’s and pieces and run some commands;

$ sudo apt-get install sqlite3
$ cd
$ sqlite3 example.db
sqlite> CREATE TABLE user ( name VARCHAR(15) PRIMARY KEY );
sqlite> .quit
$ sudo perl -MCPAN -e shell
cpan> install DBD::SQLite
cpan> install Class::DBI::SQLite
cpan> install Catalyst::Model::CDBI
cpan> install Catalyst::Model::CDBI::Sweet
$ catalyst.pl Example
$ cd Example
$ ./script/example_create.pl model User CDBI dbi:SQLite:/home/harryf/example.db < < insert correct path

That's set up a database with a single table (called user containing a single column "name") and the skeleton Catalyst app.

Now in ~Example/lib/Example/Model created a file CDBI.pm containing;


package Example::Model::CDBI;
use base 'Catalyst::Model::CDBI::Sweet';
Example::Model::CDBI->connection('dbi:SQLite:/home/harryf/example.db');

This is a base class for other Model classes to extend, which sets up the connection to the dababase as well as inheriting from Catalyst::Model::CDBI::Sweet which in turn inherits from Class::DBI::Sweet, which inherits again from Class::DBI. The quickest way to get API docs for this classes is on the command line e.g. $ man Class::DBI, rather than surfing.

To provide a Model for my table, placed the following in ~Example/lib/Example/Model/User.pm


package User::Model::Tag;

use strict;
use base 'Example::Model::CDBI';

__PACKAGE__->table('user');
__PACKAGE__->columns( Primary => qw[ name ] );

That’s it – this inherits from the earlier class, picking up everything up to Class::DBI so there’s plenty of methods on hand. To insert some records into the table, created a script ~Example/lib/insert.pl containing;


#!/usr/bin/perl -w
use strict;
use Example::Model::User;

my @names = qw(Joe Mary John Mike);

foreach my $name ( @names ) {
    my $user = Example::Model::User->create({'name'=>$name});
    print "Inserting $namen";
}


This can now be run like;

$ chmod +x insert.pl
$ ./insert.pl

To SELECT the inserted rows again, the follow script in ~Example/lib/select.pl does the job;


#!/usr/bin/perl -w
use strict;
use Example::Model::User;

my $userClass = Example::Model::User->new();
my $iterator = $userClass->retrieve_all;

while ( my $user = $iterator->next ) {
    print $user->{name}."n";
}

That much with Class::DBI at least is pretty easy but there’s a long way from there to real use cases

Looking an ORM’s again get’s me onto another minor rant / WACT plug. It’s amazing is how Jeff seems to be the only person who’s thought of building a database simplification layer (my own term) – uses normal SQL, it’s lightweight and it makes fetching data for common web related problems insanely easy. For example, need an indexed array from the DB to populate a select tag with? How about this one liner;


$countries = DBC::getOneColumnAsArray('SELECT name FROM countries');

That took care of making the connection (if needed), executing the query, looping through the results and returning an indexed array. But hey, it’s just a PHP framework James ;)

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • casual_reader

    After:

    … placed the following in ~Example/lib/Example/Model/User.pm

    Instead of

    package User::Model::Tag;

    did you mean to say


    package Example::Model::User;

    ?