Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

CGI::Application design strategy

by BUU (Prior)
on Mar 02, 2004 at 09:34 UTC ( #333201=perlquestion: print w/ replies, xml ) Need Help??
BUU has asked for the wisdom of the Perl Monks concerning the following question:

This isn't a perl question, it's more of a design question. Anyways, for example, I have two simple run modes, one called "login" and the other called "login_submit". The "login" mode simply presents the login screen while the "login_submit" mode does the actual processing of the submitted data.

My problem is thus: if I submit 'bad data' to the login_submit form, how do I go back to the 'login' mode AND tell the what he did wrong? If cgi::app had proper mode switching my 'login_submit' mode could just set a param or something in my object and then switch to the login mode, but nope, not allowed to switch run modes.

The only way I see to change modes (aside from the prerun_mode which can only be called from one specific function) is a header-redirect, which is just ugly and inefficient. So whats the easist way of changing modes in mid run?

Comment on CGI::Application design strategy
Replies are listed 'Oldest First'.
Re: CGI::Application design strategy
by Corion (Pope) on Mar 02, 2004 at 09:38 UTC

    I didn't find anything wrong with the run mode switching in CGI::Application, but I didn't do authentication through it.

    You say in your intro, that you have two run modes, "login" and "login_submit", but later on, you mention a third run mode, which I would calll "login_retry". I would redirect the user from a failed login to the login_retry run mode, either internally (by changing the used template) or externally, by sending the correct location: redirect.

Re: CGI::Application design strategy
by esskar (Deacon) on Mar 02, 2004 at 10:30 UTC
    i would definitly go with location-redirect using the "Status: 302 Moved" and the "Location" header-field. There is nothing wrong with that and inefficienty can not be your reason of not doing it!
Re: CGI::Application design strategy
by Ctrl-z (Friar) on Mar 02, 2004 at 10:39 UTC
    Run_modes are like the public interface to your App - they dont need to account for everything your app does. Id be more likely to have just 1 runmode - login - that calls private methods depending on whether the appropriate username/password combo was coming in on the CGI params.
    sub login
    {
        my $self = shift;
        my $q    = $self->query(); # ?
        if($q->param("username") && $q->param("password"))
        {
            $self->_verify_login() ;
        }
        else
        {
            $self->_generate_form();
        }
    
        # ... do template stuff here
    }
    
    For login_retry - id probably just put a <TMPL_IF> in my original form template, and reuse it for the retry.
    <tmpl_if name="BAD_LOGIN"> 
         Sorry please try again...  
    </tmpl_if>
        <form>...</form>
    
    Hope that helps



    time was, I could move my arms like a bird and...
Re: CGI::Application design strategy
by zby (Vicar) on Mar 02, 2004 at 12:21 UTC
    In my app I just call the other mode from inside of my analog of login_submit:
    sub login_submit{ my $self = shift; . . . if(badlogin()){ return $self->login(); } }
    Update: Added 'return' (following rchiav).
      Since your login_submit sub has to return what's to be displayed to the browser, don't you have to do
      if(badlogin()){ return $self->login(); }
      ?
        No, not necessarilly, if $self->login returns to a place where at some later point the output is returned to CGI::A then the return is not strictly necessary.

        Believe me, I know, I got bitten by that one yesterday.

        jdtoronto

        Yeah - you are right. That's how I did that. I can't comment on what jdtoronto wrote.
Re: CGI::Application design strategy
by dragonchild (Archbishop) on Mar 02, 2004 at 12:44 UTC
    I use three runmodes for this purpose.
    • login() presents the login form. It also optionally accepts an error message which it passes off to HTML::Template.
    • validate() is the runmode executed by the login form. If the login is unsuccessful, it returns a call to login() with the appropriate error message. If it is successful, it calls home(). validate() doesn't display anything of its own.
    • home() displays the home page. It's a passthru to HTML::Template, with the appropriate values for the specific user set. (It doesn't do any processing of its own - all the user processing is done in a base class.)

    I hope that helps.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: CGI::Application design strategy
by larsen (Parson) on Mar 02, 2004 at 15:29 UTC
    I'm used to write two runmodes for every panel in my application. In your case, they would be login and login_update. Given a method redirect to set the appropriate headers, the code could be the following (not-so-pseudo-code):
    # Does nothing except printing the form. # Using sessions you can pass to it an error_message, # for example. # sub login + { my $self = shift; + my $tmpl = $self->load_tmpl( 'login' ); + return $tmpl->output(); + } sub login_update + { my $self = shift; + my $q = $self->query; # Fetch username and password from the form # if ( PASSWORD CORRECT ) { $self->redirect( { rm => 'first_panel' } ); } else { # It could store some useful info in a session, # for example the error message. # $self->redirect( { rm => 'login' } ); } return; }
    I use this technique a lot, and it has proven its flexibility and efficiency.
      I realise you say the above is psuedo code but I have to ask. How do you normally represent:
      $self->redirect( { rm => 'first_panel' } );
      In your normal applications? Do you have a template method like the following (this is naturally untested):
      sub redirect { my $self = shift; my $mode = shift; my $new_url = $self->param('app_url') . $mode->{'rm'}; $self->header_type('redirect'); $self->header_props(-url=>$new_url); return "Redirecting to $new_url"; }
      I ask as I have wanted to switch between run modes based on data and have had to stick with these kind of methods. Either that or I call the runmode method directly.

      Just a quick question - I'm sure the answer is yes but I thought I would ask anyhoo.
        The answer is yes. My actual code is pretty similar to yours.
        sub build_redirect { my ($self, $form, $script) = @_; $form ||= {}; + my $q = $self->query; my $uri = URI->new( $script || $q->script_name ); + $uri->query_form(%$form); + return $uri->as_string; } sub redirect { my $self = shift; + $self->header_add( -uri => $self->build_redirect( @_ ) ); + $self->header_type('redirect'); + }

        If you want to switch run modes in mid-stream your current run mode just has to call the runmode that you want.

        There is never any need for a normal CGI::Application based app to use redirect headers to access another runmode unless the resource has actually moved (e.g. has a new URL)

        Here is larsen's example modified updated to remove the redirect.

        # Does nothing except printing the form. # Using sessions you can pass to it an error_message, # for example. # sub login + { my $self = shift; + my $tmpl = $self->load_tmpl( 'login' ); + return $tmpl->output(); + } sub login_update + { my $self = shift; + my $q = $self->query; # Fetch username and password from the form # if ( PASSWORD CORRECT ) { return $self->first_panel; } else { # It could store some useful info in a session, # for example the error message. # return $self->login; } # You have a problem if this return ever actually executed #return; }
        --
        Clayton

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://333201]
Approved by Enlil
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (18)
As of 2015-07-07 16:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (91 votes), past polls