http://qs321.pair.com?node_id=478922

I've never been a huge advocate of OO; I use objects when it's convenient. However, the more code I write, the more I begin to realise that I should be using objects a lot more. A recent solution to a problem I had re-enforced this for me. Although this is probably pretty obvious to a lot of Monks, I thought I'd share my story with you, in case someone finds it useful.

The Problem

I've got a mod_perl application that uses HTML::Template throughout. At the time I wrote it, there wasn't any off-the-shelf framework that I really liked (I'd probably use Catalyst now), and since it was a fairly simple app, I rolled my own.

This just consisted of a Handler that created my own Request object, and passed this to every 'crontroller' function. It included an Apache::Session object, database connection, etc.

The problem was, I needed to add an item to the main menu (displayed on every page) for administrator users only. Previously, there hadn't even been an administrator user, but I did have a 'top.html' template, included by every other template with the menu.

I wrote some code to read the administrator flag from the DB, and store it in the session - nothing tricky there.

Wrapping HTML::Template

I didn't like the thought of passing an adminstrator flag every time I made a call to HTML::Template's param(), so I obviously needed to wrap it.

Luckily, HTML::Template is OO, so all I needed to do was sub-class it. This was pretty straight forward:
package MyApp::HTML::Template; use base qw(HTML::Template); sub new { my $class = shift; my %params = @_; return $class->SUPER::new( %params, die_on_bad_params => 0, ); }
At the same time, I figured I'd default that pesky die_on_bad_params to off, since I hardly ever use it.

Then all I had to do was change every call to HTML::Template->new() to MyApp::HTML::Template->new() - a simple find & replace.

Passing the Flag

Ok, so I had a wrapper for every call to HTML::Template, but now I needed the flag to be passed in to each template. Again, I didn't want to do this every time I called param(), so I obviously needed to override it.

sub param { my $self = shift; my %params = @_; $self->SUPER::param(%params); }

Great, but now I had a problem. The Request object wasn't accessable from my wrapper class - it's out of scope of course. And I didn't want to pass *that* in every time.

After a bit of thinking, I realised I just needed to make my Request class a singleton. This was as simple as inheriting from Apache::Singleton (this module was necessary rather than Class::Singleton, so that the singleton is destroyed at the end of the mod_perl request).

Then, from the param method, I can simply call MyApp::Request->instance() and I'll have the request object with the flag I need, which can then be passed to param().

Conclusion

I've often been suspicious of the 'use objects unless you have a really good reason not to' attitude, but as I learn more, I find that even if there doesn't seem to be a really good reason to use OO at the time you write something, when it comes to maintenance, OO can often make your life a lot easier.

Update: Fixed a spelling error
Update 2: Updated constructor, as per [id://jeffa]'s suggestion.