[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cgiapp
Subject:    RE: :Application question
From:       Jesse Erlbaum <jesse () VM ! COM>
Date:       2000-08-16 17:19:24
[Download RAW message or body]

Hey Andrew!


Scroll down for my reply --


Andrew Phillips [mailto:Andrew.Philips@pwgsc.gc.ca], writes:
> Subject: RE: :Application question
> 
> 
> (Sorry this is Outlook formatted...  I hate this thing :)
> 
> First of all, here's an example of what I'm currently doing.  
> The _whatever
> methods should really be somewhere else, idealy as an extension to
> CGI::Application, but for now they are where they are...  
> I'll just put the
> meat in here...  
> 
> --- Snip ---
> 
> sub maintainUsers {
> 	my $self = shift;
> 
> 	$self->_saveMode;
> 
> 	# Need to log in to use this
> 	return $self->loginMenu if (! $self->param('User'));
> 
> 	# Start a new web app
> 	my $app = new MaintainUsers(PARAMS=>{DB=>$self->param('DB'),
> User=>$self->param('User'), State=>$self->param('State'),
> ModesHonered=>$self->param('ModesHonered'),
> BackOut=>{Param=>$self->mode_param, Mode=>"Main Menu"},
> Lang=>$self->param('Lang')});
> 	$app->run;
> 	exit 0;
> }
> 
> sub _makeScriptStateURL {
> 	my $self = shift;
> 	my $q = $self->query;
> 
> 	my $scriptURL = $q->url(-relative=>1);
> 
> 	my $scriptURLArgs;
> 	foreach (@{$self->param('State')}) {
> 		$scriptURLArgs .= $scriptURLArgs ? "&" : "?";
> 		$scriptURLArgs .= $q->escape($_->{Name}) . "=" .
> $q->escape($_->{Value});
> 	}	
> 
> 	$scriptURL .= $scriptURLArgs;
> 
> 	return $scriptURL;
> }
> 
> sub _addToState {
> 	my $self = shift;
> 	my ($name, $value) = @_;
> 
> 	push(@{$self->param('State')}, {Name=>$name, Value=>$value});
> }
> 
> sub _saveMode {
> 	my $self = shift;
> 
> 	$self->_addToState($self->mode_param,
> $self->query->param($self->mode_param));
> }
> 
> --- Snip ---
> 
> In the setup method of the web app, I have to do things like 
> re-authenticate
> the user, handle changes to the user's requested language, 
> and other little
> start up things...  
> 
> Anyways, at some point the user does something to get 
> &maintainUsers to get
> called.  MaintainUsers is shared between several web 
> applications, as it
> should be consistant between them.  The param('DB') that it 
> passes is the
> object for the backend of the application that handles all 
> the "details" :)
> 
> 
> Doing this in seperate CGI's would not work as cleanly as 
> this, as there
> would be no easy way to get back to the main CGI, short of 
> having the URL
> coded in there somewhere (or passed as an argument to the 
> script).  It would
> also involve a bunch of redirections which is just a bad idea.
> 
> My current applications work like this, and work GREAT!
> 
> The only drawback I have with doing it this way is that there 
> is an exit
> inside the method, which idealy, should not be there.
> 
> As for the state stuff, if you pass param('State') to the 
> HTML::Template,
> you can do this:  
> <tmpl_loop name=State><input type=hidden name="<tmpl_var escape=HTML
> name=Name>" value="<tmpl_var escape=HTML name=Value>"></tmpl_loop>
> 
> Maybe I'm just too OO oriented.


I don't think you are being TOO object-oriented.  In fact, I think more
focus on code reuse and encapsulation would help to create an even more
straight-forward implementation.  Remember -- OO doesn't end with your code,
or even at the Perl interpreter!  The greatest benefits of
object-orientation are conceptual; taking advantage of other people's code,
even if it is in other languages or applications.

I see a lot of things in your code and in your description of your
application behavior which seem to duplicate functionality already in your
web server, in HTML or elsewhere.  For instance, you describe a system which
passes around a "User" value.  Your web server already has a facility for
passing around user identity!  The REMOTE_USER facility not only exists, but
by reusing this functionality you get the added benefit of other parts of
the server (such as the logging facility) being functionally enhanced by
having access to this user information.

In another place, you are duplicating functionality found in CGI.pm and
HTML:

> 	my $scriptURLArgs;
> 	foreach (@{$self->param('State')}) {
> 		$scriptURLArgs .= $scriptURLArgs ? "&" : "?";
> 		$scriptURLArgs .= $q->escape($_->{Name}) . "=" .
> $q->escape($_->{Value});
> 	}

This function appears to have the same behavior as CGI.pm's self_url()
method.  In fact, $CGI->self_url() makes use of HTML form variables, where
your code does not.  It appears that you are writing extra code to duplicate
the existing and ubiquitous functionality of HTML forms!

Instead of writing all this code just to create a link, why not keep the
form state in the HTML form (via $CGI->hidden()), and reuse all the existing
functionality in the browser and CGI.pm?  If you want a link back to a
calling application, why not just provide the link?  URL-encode it, and pass
it in via form data!  When the user wants to get back, just send them back
via a link, or a HTTP redirect (an absolutely valid and correct feature for
doing what you're trying to do!).

By taking advantage of all the services which exist, you will greatly
benefit from code reuse.  My own philosophy is to "Go With The Flow"
regarding working within the architecture of the system (in this case, the
web server) in which my applications run.  It is easy to get on a path where
you start re-implementing things which already work very well.  I always
believe that the hardest task for a good programmer is knowing when *NOT* to
program!

Take advantage of the file system!  Take advantage of HTML form data!  Spend
your time and expertise working on the interesting parts of the problem --
not re-implementing things which already exist and work well.


There are two other things you mentioned you want to do, which are very
insightful and important:

1. Share Code between CGI::Applications.
2. Share Data between CGI::Applications.

An example of Code Sharing might be implementing application-level security
for a suite of CGI::Applications.  This could be implemented by creating a
Perl module (the "Security" module) which is used by all the
CGI::Applications.  At the start of each run-mode function, a call to a
method provided via the security module would ensure that the current user
has access to do a particular thing at a particular time.  This security
module would NOT be a CGI::Application -- it would be a utility class which
might even provide methods used by non-CGI applications.

An example of Data Sharing might be system wide configuration.  Once again,
a Perl module could be created which contains a set of methods which return
this configuration data (the "Configuration" module).  The data could be
stored as constants in the module, or stored in a relational database -- it
doesn't matter.  Because of object-oriented encapsulation, the calling code
doesn't need to know how this data is stored!  This Perl module would be
used by your CGI::Applications, and methods of the Configuration module
would be called as needed by your applications.

In general, you should be using the same basic techniques for CGI-based
applications as you would for console applications or any other sort of
application.  Perl modules encourage encapsulation and code reuse, and
heartily recommend their use!


TTYL,

-Jesse-




--

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  Jesse Erlbaum ....................... CTO
  jesse@vm.com ............. Vanguard Media
  v: 212.242.5317 x115 ...... New York City
+-+-+-+-+-+- http://www.vm.com/ +-+-+-+-+-+-+


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic