Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

oliver (7451)

oliver
  (email not shown publicly)
http://users.ox.ac.uk/~oliver/

Data network admin for the University of Oxford. PAUSE ID "OLIVER".

Journal of oliver (7451)

Wednesday August 06, 2008
12:01 PM

DBIx::Class, Catalyst, CRUD, AJAX (and other buzzwords)

[ #37112 ]

I teach a Perl course about once a year for folks in my organization, and one question the students always ask is, "I need a quick and simple web interface to this database we have, what should I use?" And there was no answer (until now, I suppose).

Okay, there are a few things which do a similar job in Perl; a couple of abandonware Catalyst applications, or frameworks which require you to write templates, but what I mean is the whole shebang - Database to ORM to Templates to Web Page, all from one installation. Closest thing I know of is Rose::DBx::Garden::Catalyst, but even that seemed to require too much effort for a lazybones like me.

So about a year ago a chap called Andy Payne who was working at Dragonstaff produced the ListBuilder, a framework using Catalyst, DBIx::Class, Template::Toolkit, and the ExtJS Javascript library to churn out nice looking functionable CRUD interfaces to database tables. I spent a fun evening hacking with it 'til around 3 in the morning.

My eyes were opened to the real possibility, that the whole interface should be generated from information which DBIx::Class already knows; there's no need for us to be explaining things twice. I booked a few days off work and we now have CatalystX::ListFramework::Builder (LFB).

LFB needs only a few lines of configuration (database connection parameters), and then also needs you to have DBIx::Class schema classes available which describe your database, but those can be automagically generated by the excellent DBIx::Class::Schema::Loader module.

Out the other end of the sausage machine comes a Javascript-rich list-based, paged view of a database table, supporting search, delete, create and edit. LFB handles one-to-one and one-to-many relations, showing related data and allowing creation and linking of related rows when editing.

If you like the look of the module and want to know something, please do drop me a line; equally if there's a missing feature you desperately need we can probably arrange to have you buy some of my time. In the rest of this article I'll explain a little about how LFB works.

Your complete Catalyst application looks like this:

package ListFrameworkUser;
use Catalyst qw(ConfigLoader +CatalystX::ListFramework::Builder);

__PACKAGE__->setup;
1;

You can take my word for it that the config really is trivial (an example is on the CPAN documentation page), with just database connection parameters and a URL path for the Javascript library. The base class used creates a Catalyst application on the fly in your application's namespace (ListFrameworkBuilder, here) which has all the Models, Views and Controllers needed to run LFB. It does this using a mixture of package-scoped eval(), %INC injection, and overriding a little of Catalyst's core (setup_components in particular, because of eval() vs. Module::Pluggable timing issues).

Once that is done, a begin() handler in Catalyst instructs a Model to introspect DBIx::Class for all the table, column, data type and relation information which it pops into the Catalyst application stash. This is used by Template::Toolkit templates to customize a truck-load of ExtJS Javascript which is sent to the browser as the main page, and which in turn draws the list-based table view.

From that, everything notches up a gear into Web 2.0 land, as the user interface conducts its business over JSON-based AJAX. As mentioned above, you can add, delete, edit and search for records in the paged list-based view, and there are a few more bells and whistles besides that.

What are the current limitations? Well, I have coded along the 80/20 principle so there are some missing features, and some parts are inefficient. For example only single column primary keys are supported, although perhaps this will be improved in the future. Also, I didn't want you to have to install much more besides LFB itself and the ExtJS 2.1 library, so a small number of static PNG icons are served from LFB rather than your web server. These are reasonable compromises given the aim of LFB which is to be a near-zero-conf quick-install web GUI for (probably) your legacy databases.

We're up to release 0.15 as I write this, and most of the recent work has been refactoring, and there is still a long way to go. Certainly, some of the logic used for creating related rows and so on in the database is sub-optimal (but it does support forward and reverse relations - belongs_to, might_have, has_one and has_many, in DBIx::Class parlance). Don't be too critical, but feedback and ideas (and hey, if you like it, some praise!) would be appreciated. I'm already working with a handful of early adopters to refine the UI.

Oh, and last but not least... you want to see a running demo of the system? Well as a reward for reading this whole article try this simple Albums application, at least until the use.perl.org effect brings down my friend Peter's little VM host :-)

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Dude! I just got done with the latest step of the MVC Marathon project: build a control to list results and CRUD. I was totally bummed out that Cat/DBIC had nothing like rails or cakephp or django.

    CatalystX::CRUD is mostly RDBO unless you write a forms processer, and Enzyme is all CDBI.

    I'm soooooo happy to see this post. I never looked at ListFramework because, well, it doesn't sound like CRUD at all. "List"?

    I'll be getting this up and running tonight and working it into the next MVC post.

    • Ok, It's not what I thought it was. :-/

      Is there any way to map this magic to an url, like /admin/? Also, when I tried using the latest Cat that now uses .conf instead of .yml, it dies about not seeing schema_class, even though I'm pointing it to the sample .yml file. After puttin the config in .conf, it then dies about not finding any templates.

      I looked at just the ListFramework, but even that seems to need a fair amount of coding to get working...at in my situation which is comparing what rails/cake/django

      • Hi,

        Firstly, thanks for posting a comment :-) It might be better to take this support stuff off use.perl.org and onto the CPAN forum, if you like.

        Ok, It's not what I thought it was. :-/

        Did you look at the demo app? I'd be interested to know what you _did_ think it'd be, as that might offer up some cool feature(s) for the future.

        Is there any way to map this magic to an url, like /admin/?

        Again, I think the demo app linked in the post shows what the URLs look like. You can use Firebug to see the AJAX calls.

        when I tried using the latest Cat that now uses .conf instead of .yml

        Not sure what you're referring to here - might be best to send me an email with a link to the docs r

        • Yes, I looked at the demo app. It appears from the docs/code/demo that this is a complete app that does only CRUD.

          What's I'm interested in is bolting on CRUD to an existing app that already has DBIC models, and ideally, that would put all of it's stuff under an /admin/ location, while the rest of the app runs in /.

          Are you in #catalyst@irc.perl.org?

          • Okay, good suggestions, I'll see you on IRC then to talk about this further (my nick is 'oliver')
      • when I tried using the latest Cat that now uses .conf instead of .yml, it dies about not seeing schema_class

        I found the error causing this - the interface to one of the Catalyst plugins has changed. I've just uploaded version 0.16 of LFB to the CPAN with a fix.

  • Heh, nice one Oliver. My VPS is still up :)

    Best,
    -Peter

    http://perl.dragonstaff.co.uk [dragonstaff.co.uk]

  • I teach a Perl course about once a year for folks in my organization, and one question the students always ask is, "I need a quick and simple web interface to this database we have, what should I use?" And there was no answer.

    Gantry has been able to do this for a while now:

    A Holiday Gantry Web Application [onlamp.com]

    trwww

    • Yes there are a few other equivalent systems, as I mentioned in the article (the Rose Garden one, in particular, I was familiar with). I must confess to being unaware of Gantry.

      What's interesting, and this is just typical of the Perl community's way of doing things, is that one module inspires use of another.

      For example people want a CRUD-ish system like this, but are put off by the size and power of the Rose Garden, or Gantry. then they install my LFB, and are happy for a while. Then they want to customize

  • InstantCRUD is another scaffolding package (just like Gantry above). It is now very outdated - but I have a new version of it and I am just waiting for a new release of DBIC (since unfortunately the more advanced features rely on some bug fixes). I try to make it lightweight - by offloading the work to more general purpose libraries. There is now really a multitude of CRUD packages - do you see any possibility to collaborate? Maybe by establishing some interfaces? Using common base modules? One thing
    • I think this is a great suggestion!

      Most of my effort on this module has been on the intelligence in the user interface, so the guts are certainly not very pretty nor elegant. But they work.

      At some point it will need refactoring, and there are a few good candidates for generic components. For example Metadata.pm which (heavily) introspects the DBIx::Class schema, and also AJAX.pm which parses web forms and performs DBIx::Class insert/updates. If these two were factored out and had standardized output/inp