http://qs1969.pair.com?node_id=410951


in reply to Yet another "why CGI-Application" question

I would like to create a mix between what dragonchild calls "clannish" and "socialist" (see Re: Re: Why CGI::Application?). One directory per functional area, and within that, one script per run mode.

*sighs* I was afraid that post was going to come back and haunt me. It was mostly tongue-in-cheek, attempting to get from "The Monolithic Script" to a C::A solution in a few easy steps. Don't read too much into it.

As for answering your question(s) ... hmmm ... In no particular order:

Now, for an example. This example assumes you understand that basic concepts of OO theory. (You don't have to understand Perl OO programming - just OO theory.)

The idea is that we have three functional areas to our application.

A few further, somewhat arbitrary, requirements:

Stop and think about how you'd do this in a bunch of CGI scripts. You'd have to at least have

Now, this is no different that with C::A - you will have to have all those same functions. And, frankly, the code will be almost the same, line for line. But, there's a difference - with the CGI script method you're proposing, you will need to make sure you call all those functions in the right order in every single file. If you want to change that order, you will need to change every single CGI script. Every single one. That's a lot of work!

With C::A, you put that kind of code in one place, and only one place. Then, C::A guarantees that the code you specify will be called before the runmode. This way, by the time you get into the runmode, you know a whole bunch of stuff has already happened. For example, you know that

And, when you are done, you will also be guaranteed than any cleanup work will be done for you.

Every. Single. Time.

So, how do you get C::A to do all this magic for you? By using the power of subclassing. When I use C::A, I create a child-class, generally called Generic::Application. This is my personal C::A, modified and customized to meet my personal needs. I'll generally have 2-3 things in it:

This class will not have anything in cgiapp_prerun() or cgiapp_postrun(). This is just to provide some common functionality.

Next, I'll create Specific::Application which will be a child of Generic::Application. This will be the base class for the specific web application I'm working on. In here will be the cgiapp_prerun() and cgiapp_postrun() that will generally do things like

Each of those things may or may not be in separate methods.

Note, we haven't actually written any runmodes yet. This is all just infrastructure work - code we'll need later on down the road.

Now, remember back to our requirements - we need three areas. That sounds like we need three child classes. Specific::Application::Public, Specific::Application::Members, and Specific::Application::Admin. Each of these will also have a very basic .cgi file in the cgi-bin directory, corresponding to the last part of the classname.

Now, Specific::Application assumes that every page requires a login. We can then override that in Specific::Application::Public to say that runmodes in this class do not require a login. That's the more secure way of doing things. The admin stuff can be handled by the ::Admin class requiring that the session generated by authentication contain a certain flag set to true, indicating this is an admin user. All of this happens in the cgiapp_prerun() methods in the various classes. The same goes for cookies, databases, and the like.

Every runmode will look something like:

sub runmode { my $self = shift; my $session = $self->param( 'session' ); my $dbh = $self->param( 'dbh' ); # Do stuff here return $self->print( $template_name, $format, %parameters_to_pass_to_template_object, ); }

Everything else is handled for you. In fact, most of your developers will never need to know how things work - just that they do. Does that help?

Being right, does not endow the right to be rude; politeness costs nothing.
Being unknowing, is not the same as being stupid.
Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.