Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Refining the CGI process through structure and templates

by boo_radley (Parson)
on Apr 16, 2001 at 20:03 UTC ( #72853=perlquestion: print w/replies, xml ) Need Help??
boo_radley has asked for the wisdom of the Perl Monks concerning the following question:

I've dabbled with a few ways of doing web applications now. From the cookbook methods, to CGI::Application, each one has certain limitations and problems.

In an idle moment, the following list was developed :
A good CGI framework should provide

  1. Template handling -- go TT2! Keeping templates divorced from code allows me to to farm out HTML and probably SQL, not to mention benefits of maintenance, etc.
  2. Data Validation/ Business Rules Validation -- Submitting a form should optionally invoke any validation I see fit.
  3. Pre/Post handling -- Allow things to occur before an HTML page is displayed, and allow them to happen after an HTML form is submitted. This step (i.e. post handling) should be separate from data validation to allow for database transactions, session management, etc.
  4. Parameter Management -- Each page reserves which parameters should be stateful. Parameters not on the list will not be preserved between invocations.
  5. Error-handling -- If validation fails, or if pre/post fails, do something specific to the page.
  6. Flow control -- once I've gotten a whiteboard sketch of how a site should run, it shouldn't take much to implement the same flow programmatically.
OK, that's a tall order. So what's the answer? I think it looks something like this

my %pages = ( page_one => {description =>"Sign on", nextpage =>"greeting", prevpage => undef, validator =>\&signon_validate, errorhandler =>\&signon_err, template =>'path\template.html', postsubmit =>\&signon_psub, params =>["username","password]}, );
Now, the only thing that I'm not happy with are the prevpage and nextpage. I think this method of flow control is pretty limiting -- I have some ideas for improvements; removing those keys, and adding something like traverse_list which would be an array of other pages, and traverse_sub which would determine which one you'd hit.

Right now, I've got a basic engine (which is ugly, and unrefined) that does what I want with the existing structure. I can take user input, query databases, write out, update databases and so on.
BUT. Before I continue, I want to sanity check things. Is this duplication of effort? I know there's at least 3 other CGI website management modules out there, but I don't think they do the same thing (maybe CGI::Application, since it's meant to be subclassed into oblivion). Secondly, does this approach make sense? I'd really appreciate any input before I begin the arduous quest of modularizing all of this only to be told "this does exactly what foo::bar does, only ugly."

Replies are listed 'Best First'.
Re: Refining the CGI process through structure and templates
by Corion (Pope) on Apr 16, 2001 at 20:14 UTC

    I have sought similar and similarly found no all-in-one solution for my stuff. What I did come up with is HTML::FormValidator, which does some HTML form validation, but the validation isn't fully to my taste because I want synchronous JavaScript and Perl validation, or rather, JavaScript regular expression validation to save some round trips, which is fed from the Perl code / a database.

    The one thing I've come up with which I like better than your approach is dividing the single pages into unlinked single pages and having an external structure that defines the order of my pages, like so :

    my @pageorder = qw(welcome address notify done); my %pages = { "welcome" => \&page_welcome; "address" => \&page_address; "notify" => \&page_notify; "done" => \&page_done; }; my %validators = { "welcome" => \&validate_welcome; "address" => \&validate_address; "notify" => \&validate_notify; "done" => \&validate_done; };

    but as you see, my layout is still mostly linear. Having some tree-like paths would be interesting and with my approach, the navigation component can be abstracted, but I haven't found a nice and good way to implement the chosen path (calling all possible validators isn't an option in a non-linear graph anymore :-) ).

      I like HTML::FormValidator, too. There is a review of it available.


Re (tilly) 1: Refining the CGI process through structure and templates
by tilly (Archbishop) on Apr 16, 2001 at 20:52 UTC
    I have not played with this problem, so I don't know what is out there. However given the kinds of problems that you want to solve, I would suggest taking a close look at POE and its documentation.

    Not because it solves the problem you want (it doesn't), but because the entire "state machine" philosophy it uses is (at a guess) going to be a good fit for your problem and is similar to the direction you are heading. Therefore seeing a mature implementation of those ideas in another context is likely to shorten the path between you and some key design ideas you will find helpful.

    Remember that the most interesting innovations tend to happen when someone finds a way of taking person A's well-developed theories and apply them to person B's problem...

More refining
by boo_radley (Parson) on Apr 17, 2001 at 17:53 UTC
    OK, so I went home, and worked on this some more...
    Here's the current structure :
    PAGENAME=> {description =>$desc, traverse_list =>{pagename_1 => 1, pagename_2 => 0, ...}, traverse_sub =>\&sub, validator =>\&sub, errorhandler =>\&sub, template =>$filepath, postsubmit =>\&sub, params =>[$param1, $param2...]}
    description is a plain string used as an identifier for the page. It currently provides data for the template's <TITLE> tag. This is probably not so hot.

    traverse_list is an anonymous hash which stores which pages the current page could link to. The key should be a PAGENAME, and the value of the key determines if the postsubmit subroutine should be called when moving to that page.

    traverse_sub is a sub ref which determines which page should be displayed next. It returns a string, which should match one of the keys in traverse_list. It is passed 2 variables, $vars and $errorcode. $vars is a hash ref used to populate the template. $errorcode is generated by the page's errorhandler.

    validator is a sub ref used to validate data or business rules. I envision it as returning an integer code, or a bitmap.

    errorhandler is a sub ref. It's little experimental -- I picture it being called if postsubmit fails horribly. I was planning to eval postsubmit and call errorhandler if it died, but I'm thinking of expanding its scope. *shrug*

    template is a string containing the path to this page's TT2 encoded HTML template.

    postsubmit is a reference to a subroutine called after validation. Like traverse_sub, it's passed $vars and $errorcode. If you need to hit a DB, or process user input in some fashion, this is place to do it.

    params defines a list of html parameters which will "be sticky" (is that the right term), and be passed as hidden HTML input fields.

    In my CST, I will polish the engine and post it. I appreciate the replies and /msgs I've gotten so far, and am trying to incorporate them into the changes I'm making; please let me know if you've got more.

Re: Refining the CGI process through structure and templates
by michellem (Friar) on Apr 17, 2001 at 00:21 UTC
    This is a great framework - I've been working hard at cobbling together an engine to do SQL database editing/output - and I've ended up with a similar framework, although not put together quite so neatly. I probably don't use all of the modules I should be - but I looked for anything that would do it all together, and didn't find it (doesn't mean it's not out there.)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://72853]
Approved by root
[stevieb]: cheers beech. twas totally my mistake, and I got bit. When things work for so long without issue, one becomes complacent (ie. replace we/one with I ;) I've been copy/pasting that around for a few years without a hiccup, so when...
[stevieb]: choroba pointed that out, I was just, you know, *sigh*. In effect, I was lucky and fortunate
[stevieb]: Kind of like my regex-fu went out the window, but only while looking at that specific file ;)

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2017-07-25 23:35 GMT
Find Nodes?
    Voting Booth?
    I came, I saw, I ...

    Results (383 votes). Check out past polls.