• Like
  • Save
CGI::Prototype (NPW 2006)
Upcoming SlideShare
Loading in...5
×

CGI::Prototype (NPW 2006)

  • 15,998 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
15,998
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Managing Complexity with CGI::Prototype brian d foy, brian@stonehenge.com Stonehenge Consulting Ser vices Nordic Perl Workshop • June 16, 2006
  • 2. Web application flow Start up Receive input Process input Return output Clean up Shut down
  • 3. Looks simple, right?
  • 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. Language agnostic
  • 6. Current fad is Model-View-Controller (MVC)
  • 7. MVC Architecture Model -> data store -> database View -> data display -> web page Controller -> user interaction -> form widgets
  • 8. Choose your poison Mason CGI::Application Maypole, Catalyst, Catalyst++ CGI::Prototype
  • 9. Using CGI::Prototype Model -> DBI, Class::DBI, XML View -> Template Toolkit, XSLT -> HTML Controller -> HTML form widgets
  • 10. Application state Each state is a namespace Each state has a Template file Change state at any time by changing namespace
  • 11. Application flow Inherit from CGI::Prototype Single URL WebApp->activate; The rest is in packages and templates CGI::Prototype handles the flow
  • 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. 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. 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. 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. 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. [% 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. 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. ...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. 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. 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. CGI::Prototype::Hidden is even easier
  • 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