UPDATE - my ignorance of Catalyst dispatch chaining led to this post. Catalyst certainly has a way to do this, even if it is not obvious to me.

I've spent the last 2 days staring at as many CGI / webapp frameworks as I could:

And basically all of them seem to miss what we see merlyn speaks of in his DESCRIPTION to CGI::Prototype -
being a fan of clean MVC designs, the classes become the controllers ... and CGI::Prototype a sort of "archetypal" controller.
Now, from this point, we are going to look at the CGI::Prototype controller. Then I will discuss the power of such a controller theoretically. Then I will give a concrete example of why it is important that controllers be in a hierarchy of classes.

the CGI::Prototype controller

When you look at the sub below, just notice one line:
$next_page->render;
sub activate { my $self = shift; eval { $self->prototype_enter; $self->app_enter; my $this_page = $self->dispatch; $this_page->control_enter; $this_page->respond_enter; my $next_page = $this_page->respond; $this_page->respond_leave; if ($this_page ne $next_page) { $this_page->control_leave; $next_page->control_enter; } $next_page->render_enter; $next_page->render; $next_page->render_leave; $next_page->control_leave; $self->app_leave; $self->prototype_leave; }; $self->error($@) if $@; # failed something, go to safe mode }

the power of this method

Well, what is obvious about this method is that because every controller is a class, you can refine the behavior of your class by building classes which override/augment/before/after/mixin any of the methods you see above!

I said to focus on $next_page->render because that is what I will demonstrate from a practical perspective. But as you can see any aspect of the HTTP response cycle can be handled in an object-oriented fashion.

I stared in utter confusion at every single framework above. I looked at Catalyst subroutines, Jifty actions, Mason components, and so on. And in each case, they seemed to miss the magick of merlyn's methodic approach to web application control.

With CGI::Prototype, it is very easy to create a "family" of actions and have them derive behavior from each other.

But enough talk. Let me provide a simple concrete example.

object-oriented page manipulation in CGI::Prototype

Let's just take a simple series of pages to process user logins.
  1. The user is presented with a login page
  2. The user's login information is submitted
  3. If it is valid, then present the main page of site. Else, present a page with login failure feedback (invalid fields, etc)

present a login page

We first present the login page. After the controller has run and decided to dispatch to the login page, we eventually get to
->render
which calls the engine method:
package Gimble::Page::Login::Base; use base qw(Gimble::Page::Base); sub engine { my ($self,$tree) = @_; $self->snip_validate($tree); $tree } sub template { require html::login; html::login->new } 1;
And this page is quite simple. It finds the "template file" for logging in. hen it removes all the data validation HTML from it.

the users information is submitted

So after the information is submitted, a processing page will respond with a "validation error page" or "welcome page".

the validation error page

If there was an issue with validating the user data, we can simply inherit the "template" method from Login::Base above. Then our engine renders the validation errors instead of snipping out the validation HTML.

the object-oriented re-use

We had a new rendering action but did not re-specify what template file to use. Because everything in CGI::Protototype is class-based, this was easy.

the login successful page

on a successful login, we still want to snip the validation data... so a $self->SUPER::engine call handles that. Then we do some other things to welcome the user.

Conclusion

This was a simple example of how rendering logic for a family of pages can be achieved in an Object-oriented fashion with CGI::Prototype. The closest thing to CGIP on CPAN is CGI::Application. Having a linear set of subroutines does not afford the same degree of re-use that I have shown here with classes.

Of course there are other logic tasks in a CGI application - dispatch, authentication, authorization, to name a few. But having had experience with many CGI / webapp frameworks, I think merlyn describes exactly how CGI::Prototype fits into the picture perfectly:

Create a CGI application by subclassing
and I think it has the best setup for pluggable expansion into these other tasks as well.

Of course, it needs a Moose rewrite...

A Horror Story

we had a k0der in our IT department. Whats a k0der? It's a person who believes in writing code instead of downloading CPAN modules (he had mappings from 2-letter state names to full state names copy-pasted in 4 or 5 places instead of using Locale::US). It's a person who has not heard of MVC. It's a person who uses if-then instead of object-oriented dispatch for complexity management. It's person who doesnt know about database normalization and brushes you off with a huff when you try to talk to them about it.

Now what happened? I had written a few CGI apps using CGI::Application. Then they turned the k0der loose to do his own. And guess what? He stuck everything for a particular CGI action in each subroutine. Now we have a 300k .pm file.

Now, refactoring this is going to lead to merge conflicts. If he had been forced into the CGI::Prototype mode of "creating an application by subclassing" he would have had to partition his spaghetti brainfuck into separate modules and we could have a developer per module and no merge conflicts to sort out.

CGI::Application was a great step away from the HTML::Mason / Embperl approach to web application flow control. In my opinion, the next improved step is CGI::Prototype, having done my best to understand the merits of other CGI / web app frameworks, be they big or small, popular or unpopular!


In reply to CGI::Prototype leverages objects for web app control by metaperl

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.