Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re^2: Review: CGI::Prototype

by Joost (Canon)
on Dec 02, 2004 at 15:46 UTC ( [id://411809]=note: print w/replies, xml ) Need Help??


in reply to Re: Review: CGI::Prototype
in thread Review: CGI::Prototype

Our app will have to figure out which button was hit and handle the data and output as needed. In C::A, there is really only one place you can put this logic: cgiapp_prerun(). If you have many runmodes that need this sort of functionalilty, your cgiapp_prerun() can start getting rather large.

Why would you not have the runmode method handle this?

I tend to use the runmode more as a vague indidactor of the expected action anyway - it determines the kind of checks that need to be done on the input, then decides which action to perform, and then refers to an output routine. Example:

sub make_report { my $self = shift; if (my $missing = $self->missing_fields()) { # back to submitted form, with missing fields highlighted return $self->make_form($missing); } # make confirmation screen. $self->template( 'confirm.tmpl' => $self->form_values, ); }

This decides the output based on wether or not all data has been filled in correctly, but it isn't really very different if you check for a button instead.

update: after reading this thread again, it seems most some people find it hard to wrap their head around the following:

runmode != page != template

A runmode is just a hint from the calling form about what the input data is about, and what the application should to with it. It does not describe what template should be shown.

Replies are listed 'Best First'.
Re^3: Review: CGI::Prototype
by xdg (Monsignor) on Dec 02, 2004 at 21:22 UTC

    The update here is interesting and may get at the difference of approach between the two modules. (Caveat -- while I know C::A, my exposure to C::P is limited to this thread so far and a quick POD skim, so I may have it wrong. Apologies to the authors if so.) Both modules are effectively just state machines. However, the state-less nature of web-browsing means that tracking state and state transition is a bit more difficult.

    The C::A approach with runmodes takes the approach that the runmode specifies a target -- a desired state, or really, a desired action which is usually to reach a certain state. The application reads the desired action from a parameter and dispatches to a subroutine for that action. The subroutine checks the validity of the action given the input and presents a new state back to the user. (This may be done within the runmode subroutine or as a call to a "display_x" subroutine.) Templates really define a state and logic in the templates specialize the state for special cases (e.g. redisplay a form with errors in red). Plus, templates define the the valid state transitions (runmodes) that can be called from a given state.

    The C::P approach instead uses the information submitted to the application to determine the state the user was just in rather than the target. (Because of the state-less web, it can't assume that the new request originated from the last state displayed.) The state corresponds to a class, which examines the input to determine an appropriate state transition (from among valid state transitions for that state) and then calls a subroutine in a new class (state) to display back to the user. Classes define how to enter a state -- by displaying a template -- and how to exit -- by executing a state transition for a given input.

    Syntax and templating systems aside, this conceptual difference seems to me to be the crux of the issue and preference for use may depend on how a programmer likes to think about it. In C::A, one defines state transitions and uses those to determine a new state to display. In C::P, one defines states and how a user gets from that state to other valid states.

    Polymorphism becomes important in C::P as a way of handling special cases (e.g. a form with errors) without repetitive coding, whereas with C::A, the special case coding would more likely happen procedurally in the templates.

    Hope that helps some people. (Just writing it was helpful to me to bend my mind around how to conceptualize states and transitions for CGI in general.)

    -xdg

    Code posted by xdg on PerlMonks is public domain. It has no warranties, express or implied. Posted code may not have been tested. Use at your own risk.

      I think that's an excellent summary of C::P, and my understanding of C::A as well.

      With C::P, you define a view and its associated controller. (I got this model from Smalltalk many decades ago.) The controller presents the view, which the user interacts with, which the controller then decides what to do next: activating another controller, or staying in the same view. Of course, controllers share a lot of code, and that's where the class hierarchy comes in. And we need a meta controller to handle the stateless nature of the web to select which controller is active, and a piece of meta information (the "state") to help with that.

      Thus, I believe (other than the commitment to Template Toolkit, which can be overridden with a single method override, and the inclusion of a CGI.pm object for field interpretation) that C::P is the most generic framework you can create. So, based on that most generic structure, I have one concrete derivative that deals with using a hidden field (C::P::Hidden), but I suspect there will be others.

      I also have a nice testing tool, which nobody has talked about, C::P::Mecha, which allows WWW::Mechanize to "run" the application, but in the same process without a webserver. This alone is worth the price of the download. {grin}

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Now C::P sounds like Spoon/Spiffy
      So let me see if I've got this. State machines basically follow this cycle, after an initial setup:
      1. Look at your state and look in a table for what to do.
      2. Do stuff, probably depending on input, and figure out what state to go to next.
      3. Transition to the next state
      Now both C::A and C::P maintain state information by telling the browser "when you submit this form back to the server, come back in as state X". This is pretty much driven by the way HTTP works (the other choice is to use session ID variables and database lookups, but that tends to lead to un-web-like applications), so it's not surprising that they look alike in that respect. The difference is where in the state machine cycle the browser comes in. C::A seems from your description to put the browser into the last step; its state machine loop would be:
      1. Look at your state and look in a table for what to do.
      2. Do stuff, probably depending on input, and figure out what state to go to next.
      3. Tell the browser to come back in as the next state.
      4. Wait for the browser
      Whereas C::P seems to be:
      1. Look at your state and look in a table for what to do.
      2. Do stuff, and tell the browser to come back in as the second half of this state.
      3. Wait for browser
      4. Do some more stuff, probably depending on input, and determine what the next state should be.
      5. Transition to the next state
      Now, from just this description I'd expect the two application frameworks to be equivalent in the sense that an application could be switched between them by renaming some states and shuffling a bit of logic. The discussion so far would suggest that there are stronger differences. I'm not sure from this description which approach makes it easier to develop and maintain applications. The C::P approach seems more in line with what I'd want to do in typical data-entry or shopping cart web applications, but I'm wary of dismissing the C::A approach just because it doesn't immediately align with my current thinking. Lots of very useful tools don't align with my first impression of the problem domain.
      -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/

        I don't think that's quite right. In both cases, the logic flow is

        1. Receive a request from the browser
        2. Decide what do do about it
        3. Tell the browser to enter a new state
        4. Wait for the next request from the browser

        The difference is in the nature of (1) and the details of (2). I prefer to think about it this way:

        • C::A wants to know where you want to go, and decides based on that and the data provided where you actually end up.
        • C::P wants to know where you were and decides based on the data provided where you actually go next.

        For me, apart from style preferences, C::P works well where the validity conditions for entering particular states frequently depend on the current state. C::A is useful where the validity conditions for entering a particular state depend solely on the data requirements of the target state.

        If a C::A app always required a parameter for "current state" along with the "run mode" and used that plus other submissions to determine the state entered, it would provide the same functionality as C::P. C::P just enforces that kind of thinking from the beginning.

        -xdg

        Code posted by xdg on PerlMonks is public domain. It has no warranties, express or implied. Posted code may not have been tested. Use at your own risk.

      >Polymorphism becomes important in C::P as a way of handling special cases (e.g. a form with errors) without repetitive coding. Whereas with C::A, the special case coding would more likely happen procedurally in the templates.

      In C::A, when I have common processing I place it in a .pl file and require it in the proper modules. If I were better at OO, I guess I could make it a class and reference it similarly to what you describe for C::P.

      Do you know, is there a significant performance hit for doing everything in a C::P object model compared to C::A's model which (at least the way I use it) is more procedural programming within a basic framework of objects? Would this be a consideration for higher volume sites?

      Mark

runmode != page != template
by Thilosophy (Curate) on Dec 30, 2004 at 07:42 UTC
    A runmode is just a hint from the calling form about what the input data is about, and what the application should to with it. It does not describe what template should be shown.

    Exactly my philosophy when working with C::A. I tried to factor this into a plugin that makes it very easy to just show templates (by using path_info to figure out which template to show and having associated data files for the templates so that they can "render themselves") so that the runmodes can concentrate on doing "the business logic".

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://411809]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (4)
As of 2024-04-19 03:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found