[cgiapp] Some general questions on CGI::App and OO web application design philosophy

Richard Jones ra.jones at dpw.clara.co.uk
Sun Jun 7 05:23:24 EDT 2009


Brad Van Sickle wrote:
[ .. ]
> Currently, I'm working on creating a content management system for a 
> static website.  The CMS has quite a few sections (manage users, manage 
> events, manage articles, etc... ) but each section does basically the 
> same things (displays the current records, allows you to delete or edit 
> current records, allows you to create a new record) Right now I have it 
> set up so each section is it's own application.  I have an instance 
> script and a package for each section.  Within that package I change out 
> the SQL statements and related code, load different templates for the 
> create/edit forms, etc...  It works well, but I'm not sure that this is 
> the "right" way of doing things.
> 
> It seems to me that there is probably a way to do this by using a 
> different instance script for each section, but having them all leverage 
> the same package by initializing it with section specific data on the 
> forms and SQL statements, and than adding in subclasses or instance 
> script code for any additional methods that may be required... but I'm 
> still kind of new with OO PERL and I can't quite wrap my head around the 
> details.  

Another way to approach this is to use CGI::Application::Dispatch, and 
revert to a single instance script pointing to your Dispatch class, and 
let *it* load the relevant controller class. That way you can have an 
integrated application with many separate components, for example - 
using the MVC approach - UserManager, EventManager, ArticleManager 
controller classes. So something like the following would do it:

# myapp.cgi:
use MyApp::Dispatch;
MyApp::Dispatch->dispatch();

# MyApp::Dispatch:
use base 'CGI::Application::Dispatch';

my @config_files = map { '/path/to/app/root/config/' . $_ }
   $d->read; # where $d = IO::Dir->new('/path/to/app/root/config')

sub dispatch_args {
   return {
     prefix  => 'MyApp',
     table => [
       '/' => { app => 'YourDefaultController', rm => 'default_rm' },
       # specific matches (optional):
       'admin/:app'        => { prefix => 'MyApp::C::Admin' },
       'admin/:app/:rm'    => { prefix => 'MyApp::C::Admin' },
       'admin/:app/:rm/:id'=> { prefix => 'MyApp::C::Admin' },
       # generic matches:
       ':app' => { }, # MyApp::C::* - uses default runmode
       ':app/:rm' => { }, # MyApp::C::* - uses specified runmode
       ':app/:rm/:id' => { }, # captures 'id' in $self->param('id')
     ],
     args_to_new => {
       PARAMS => {
         config_files => \@config_files,
      },
   }
}

# MyApp:Controller::UserManager
use base 'MyApp::Base';

sub default_runmode { ..}
sub display_users { .. }
sub delete_user { .. }
etc

# MyApp::Base # you could put common methods in here eg create
# record, delete record, etc

use base 'CGI::Application';
use CGI::Application::Plugin::TT;
use CGI::Application::Plugin::Session;
etc

Note, I've used 'C' instead of Controller in the dispatch_args() table 
definition to save it line-wrapping. See:
http://search.cpan.org/~markstos/CGI-Application-Dispatch-2.16/lib/CGI/Application/Dispatch.pm
for more details.

CAD also works well in mod_perl & fastcgi environments, and also when 
using CGI::Application::Server for development.

 > Coding that class to handle dynamically passed SQL statements
 > and process dynamic forms seems very very difficult to me.

This is where ORM's such as DBIx::Class and Rose come in very useful as 
your 'Model' in the MVC architecture, but that's a subject for another time.
-- 
Richard Jones


More information about the cgiapp mailing list