Managing Complexity
       with
  CGI::Prototype
   brian d foy, brian@stonehenge.com
    Stonehenge Consulting Ser vices
...
Web application flow
Start up
Receive input
Process input
Return output
Clean up
Shut down
Looks simple,
   right?
Is the request valid?

Should I process the transaction?

Do I have all the necessary input?

Is this part of a multi-step...
Language
agnostic
Current fad is
Model-View-Controller
       (MVC)
MVC Architecture

Model -> data store -> database
View -> data display -> web page
Controller -> user interaction -> form
...
Choose your poison

Mason
CGI::Application
Maypole, Catalyst, Catalyst++
CGI::Prototype
Using CGI::Prototype

Model -> DBI, Class::DBI, XML
View -> Template Toolkit, XSLT -> HTML
Controller -> HTML form widgets
Application state

Each state is a namespace
Each state has a Template file
Change state at any time by changing
namespace
Application flow

Inherit from CGI::Prototype
Single URL
WebApp->activate;
The rest is in packages and templates
CGI::Proto...
sub activate {
  my $self = shift;
  eval {
    $self->app_enter;
    my $this_page = $self->dispatch;
    $this_page->con...
package TPR::Dashboard::FindByName;
use base qw(TPR::Dashboard);

my $users = [];

sub respond {
   my $self = shift;
   m...
Flexibility

Change action by changing namespace
CGI::Prototype object handles the input
and data (Class::Prototyped) in $...
Handling Errors

Respond with Error namespace
Rest of transaction does Error stuff
Still has access to all data
CGI::Proto...
Multiple Responses
Decide which template to use as late as
possible
No search results -> show search form
One search resul...
[% self.CGI.header %]
<!DOCTYPE ...>
<html>

<head>
   <title>[% self.title %]</title>
   <link rel=quot;stylesheetquot; t...
Add accessors...
sub action { quot;add_subscriberquot; }
sub title { quot;Add a subscriberquot; }

my $db = TPR::Subscribe...
...use them in Template
   <title>[% self.title %]</title>

   [% self.CGI.start_form(
      Method => quot;GETquot;,
    ...
The View just views

Accessors are just accessors
Do not change the state
Change the state in the Controller
All views the...
Change behavior
__PACKAGE__->reflect->addSlots(
   [qw(engine FIELD autoload)] => sub {
       my $self = shift;
       re...
CGI::Prototype::Hidden
     is even easier
References

Introduction to CGI::Prototype
http://www.ourmedia.org/node/1644
Introduction to Class::Prototyped
http://www....
Upcoming SlideShare
Loading in...5
×

CGI::Prototype (NPW 2006)

16,392

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
16,392
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "CGI::Prototype (NPW 2006)"

  1. 1. Managing Complexity with CGI::Prototype brian d foy, brian@stonehenge.com Stonehenge Consulting Ser vices Nordic Perl Workshop • June 16, 2006
  2. 2. Web application flow Start up Receive input Process input Return output Clean up Shut down
  3. 3. Looks simple, right?
  4. 4. Is the request valid? Should I process the transaction? Do I have all the necessary input? Is this part of a multi-step process? Which output do I give?
  5. 5. Language agnostic
  6. 6. Current fad is Model-View-Controller (MVC)
  7. 7. MVC Architecture Model -> data store -> database View -> data display -> web page Controller -> user interaction -> form widgets
  8. 8. Choose your poison Mason CGI::Application Maypole, Catalyst, Catalyst++ CGI::Prototype
  9. 9. Using CGI::Prototype Model -> DBI, Class::DBI, XML View -> Template Toolkit, XSLT -> HTML Controller -> HTML form widgets
  10. 10. Application state Each state is a namespace Each state has a Template file Change state at any time by changing namespace
  11. 11. Application flow Inherit from CGI::Prototype Single URL WebApp->activate; The rest is in packages and templates CGI::Prototype handles the flow
  12. 12. sub activate { my $self = shift; eval { $self->app_enter; my $this_page = $self->dispatch; $this_page->control_enter; $this_page->respond_enter; my $next_page = $this_page->respond; $this_page->respond_leave; if ($this_page ne $next_page) { $this_page->control_leave; $next_page->control_enter; } $next_page->render_enter; $next_page->render; $next_page->render_leave; $next_page->control_leave; $self->app_leave; }; $self->error($@) if $@; }
  13. 13. package TPR::Dashboard::FindByName; use base qw(TPR::Dashboard); my $users = []; sub respond { my $self = shift; my $q = $self->CGI; my $name = $q->param('subscriber_name'); $users = $self->db->get_subscriber_by_name( $name ) || []; my $count = @$users; if( @$users == 1 ){ $q->param( 'subscriber_id', $users->[0]->pk ); quot;TPR::CGI::ShowSubscriberquot;; } elsif( @$users == 0 ) { quot;TPR::CGI::StartPagequot;; } else { __PACKAGE__; } } sub users { $users }
  14. 14. Flexibility Change action by changing namespace CGI::Prototype object handles the input and data (Class::Prototyped) in $self Choose template with template() Template has access to self.foo
  15. 15. Handling Errors Respond with Error namespace Rest of transaction does Error stuff Still has access to all data CGI::Prototype has safe mode (no 500s, hopefully)
  16. 16. Multiple Responses Decide which template to use as late as possible No search results -> show search form One search result -> show details Many search results -> show list Database error -> show error page
  17. 17. [% self.CGI.header %] <!DOCTYPE ...> <html> <head> <title>[% self.title %]</title> <link rel=quot;stylesheetquot; type=quot;text/cssquot; href=quot;... quot;/> </head> <body> <div id=quot;headerquot; class=quot;menubarquot;> ... </div> <div id=quot;contentquot; class=quot;middlequot;> <!-- BEGIN Content [% template %] --> [% PROCESS $template %] <!-- END Content [% template %] --> </div> <div id=quot;footerquot;> </div> </body></html>
  18. 18. Add accessors... sub action { quot;add_subscriberquot; } sub title { quot;Add a subscriberquot; } my $db = TPR::Subscribers::Database::SQLite->new( $file ); sub db { $db } sub subscriber { $_[0]->db->get_subscriber_by_pk( $_[1] ); }
  19. 19. ...use them in Template <title>[% self.title %]</title> [% self.CGI.start_form( Method => quot;GETquot;, Action => self.CGI.url, ) %] [% self.CGI.hidden( Name => 'action', Value => self.action, Override => 1, ) -%]
  20. 20. The View just views Accessors are just accessors Do not change the state Change the state in the Controller All views then get the feature
  21. 21. Change behavior __PACKAGE__->reflect->addSlots( [qw(engine FIELD autoload)] => sub { my $self = shift; require Template; Template->new( { PROCESS => [ $self->config_wrapper ], INCLUDE_PATH => quot;/web/cgi-bin/local-templatesquot;, } ); } ); sub config_wrapper { 'Wrapper.tt' } sub template { (my $package = ref $_[0] || $_[0]) =~ s/.*:://; my $file = quot;$package.ttquot;; -e quot;/web/cgi-bin/local-templates/$filequot; ? $file : quot;I could not find $package.ttquot;; }
  22. 22. CGI::Prototype::Hidden is even easier
  23. 23. References Introduction to CGI::Prototype http://www.ourmedia.org/node/1644 Introduction to Class::Prototyped http://www.ourmedia.org/node/1728 Various articles on stonehenge.com

×