SlideShare a Scribd company logo
1 of 23
Managing Complexity
       with
  CGI::Prototype
   brian d foy, brian@stonehenge.com
    Stonehenge Consulting Ser vices
  Nordic Perl Workshop • June 16, 2006
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 process?

Which output do I give?
Language
agnostic
Current fad is
Model-View-Controller
       (MVC)
MVC Architecture

Model -> data store -> database
View -> data display -> web page
Controller -> user interaction -> form
widgets
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::Prototype handles the flow
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 $@;
}
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 }
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
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)
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
[% 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>
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] );
   }
...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,
      ) -%]
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
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;;
   }
CGI::Prototype::Hidden
     is even easier
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

More Related Content

What's hot

Who Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterWho Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniter
ciconf
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
Wildan Maulana
 
Gravity Forms Hooks & Filters
Gravity Forms Hooks & FiltersGravity Forms Hooks & Filters
Gravity Forms Hooks & Filters
iamdangavin
 

What's hot (20)

Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
 
Who Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterWho Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniter
 
Web 11 | AJAX + JSON + PHP
Web 11 | AJAX + JSON + PHPWeb 11 | AJAX + JSON + PHP
Web 11 | AJAX + JSON + PHP
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
WordPress overloading Gravityforms using hooks, filters and extending classes
WordPress overloading Gravityforms using hooks, filters and extending classes WordPress overloading Gravityforms using hooks, filters and extending classes
WordPress overloading Gravityforms using hooks, filters and extending classes
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
 
Oop php 5
Oop php 5Oop php 5
Oop php 5
 
Identify Literate Code
Identify Literate CodeIdentify Literate Code
Identify Literate Code
 
Gravity Forms Hooks & Filters
Gravity Forms Hooks & FiltersGravity Forms Hooks & Filters
Gravity Forms Hooks & Filters
 
11. CodeIgniter vederea unei singure inregistrari
11. CodeIgniter vederea unei singure inregistrari11. CodeIgniter vederea unei singure inregistrari
11. CodeIgniter vederea unei singure inregistrari
 
PHP PPT FILE
PHP PPT FILEPHP PPT FILE
PHP PPT FILE
 
PHP and MySQL
PHP and MySQLPHP and MySQL
PHP and MySQL
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object CalisthenicsPHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHPObject Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
 

Viewers also liked (7)

Sociology Project
Sociology ProjectSociology Project
Sociology Project
 
Sociology Project
Sociology ProjectSociology Project
Sociology Project
 
Making My Own CPAN
Making My Own CPANMaking My Own CPAN
Making My Own CPAN
 
Dobitoci
DobitociDobitoci
Dobitoci
 
Kalan 3
Kalan 3Kalan 3
Kalan 3
 
Sanskriti - Business Quiz Finals
Sanskriti - Business Quiz  FinalsSanskriti - Business Quiz  Finals
Sanskriti - Business Quiz Finals
 
6 more things about Perl 6
6 more things about Perl 66 more things about Perl 6
6 more things about Perl 6
 

Similar to CGI::Prototype (NPW 2006)

symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
patter
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
arcware
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 

Similar to CGI::Prototype (NPW 2006) (20)

Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
Yii Introduction
Yii IntroductionYii Introduction
Yii Introduction
 
Get AngularJS Started!
Get AngularJS Started!Get AngularJS Started!
Get AngularJS Started!
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Drupal 8 migrate!
Drupal 8 migrate!Drupal 8 migrate!
Drupal 8 migrate!
 
Implementation of GUI Framework part3
Implementation of GUI Framework part3Implementation of GUI Framework part3
Implementation of GUI Framework part3
 
PHPConf-TW 2012 # Twig
PHPConf-TW 2012 # TwigPHPConf-TW 2012 # Twig
PHPConf-TW 2012 # Twig
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Api Design
Api DesignApi Design
Api Design
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
Web internship Yii Framework
Web internship  Yii FrameworkWeb internship  Yii Framework
Web internship Yii Framework
 
Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016
Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016
Ajax on drupal the right way - DrupalCamp Campinas, São Paulo, Brazil 2016
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Agile data presentation 3 - cambridge
Agile data   presentation 3 - cambridgeAgile data   presentation 3 - cambridge
Agile data presentation 3 - cambridge
 
Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
 
Basics of AngularJS
Basics of AngularJSBasics of AngularJS
Basics of AngularJS
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 

More from brian d foy

The Whitespace in the Perl Community
The Whitespace in the Perl CommunityThe Whitespace in the Perl Community
The Whitespace in the Perl Community
brian d foy
 
Advanced modulinos
Advanced modulinosAdvanced modulinos
Advanced modulinos
brian d foy
 

More from brian d foy (20)

Conferences for Beginners presentation
Conferences for Beginners presentationConferences for Beginners presentation
Conferences for Beginners presentation
 
20 years in Perl
20 years in Perl20 years in Perl
20 years in Perl
 
PrettyDump Perl 6 (London.pm)
PrettyDump Perl 6 (London.pm)PrettyDump Perl 6 (London.pm)
PrettyDump Perl 6 (London.pm)
 
Dumping Perl 6 (French Perl Workshop)
Dumping Perl 6 (French Perl Workshop)Dumping Perl 6 (French Perl Workshop)
Dumping Perl 6 (French Perl Workshop)
 
Perl v5.26 Features (AmsterdamX.pm)
Perl v5.26 Features (AmsterdamX.pm)Perl v5.26 Features (AmsterdamX.pm)
Perl v5.26 Features (AmsterdamX.pm)
 
Dumping Perl 6 (AmsterdamX.pm)
Dumping Perl 6 (AmsterdamX.pm)Dumping Perl 6 (AmsterdamX.pm)
Dumping Perl 6 (AmsterdamX.pm)
 
6 things about perl 6
6 things about perl 66 things about perl 6
6 things about perl 6
 
Perl 5.28 new features
Perl 5.28 new featuresPerl 5.28 new features
Perl 5.28 new features
 
The Surprisingly Tense History of the Schwartzian Transform
The Surprisingly Tense History of the Schwartzian TransformThe Surprisingly Tense History of the Schwartzian Transform
The Surprisingly Tense History of the Schwartzian Transform
 
Perl Power Tools - Saint Perl 6
Perl Power Tools - Saint Perl 6Perl Power Tools - Saint Perl 6
Perl Power Tools - Saint Perl 6
 
Perl Bag of Tricks - Baltimore Perl mongers
Perl Bag of Tricks  -  Baltimore Perl mongersPerl Bag of Tricks  -  Baltimore Perl mongers
Perl Bag of Tricks - Baltimore Perl mongers
 
The Whitespace in the Perl Community
The Whitespace in the Perl CommunityThe Whitespace in the Perl Community
The Whitespace in the Perl Community
 
CPAN Workshop, Chicago 2014
CPAN Workshop, Chicago 2014CPAN Workshop, Chicago 2014
CPAN Workshop, Chicago 2014
 
Parsing JSON with a single regex
Parsing JSON with a single regexParsing JSON with a single regex
Parsing JSON with a single regex
 
Reverse Installing CPAN
Reverse Installing CPANReverse Installing CPAN
Reverse Installing CPAN
 
Advanced modulinos
Advanced modulinosAdvanced modulinos
Advanced modulinos
 
Advanced modulinos trial
Advanced modulinos trialAdvanced modulinos trial
Advanced modulinos trial
 
Bag of tricks
Bag of tricksBag of tricks
Bag of tricks
 
I ❤ CPAN
I ❤ CPANI ❤ CPAN
I ❤ CPAN
 
Tour of the Perl docs
Tour of the Perl docsTour of the Perl docs
Tour of the Perl docs
 

Recently uploaded

Recently uploaded (20)

Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 

CGI::Prototype (NPW 2006)

  • 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
  • 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?
  • 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