How to create a simple Web application with CGI::Application Template::Toolkit and DBIx::Class Leonard Miller February 7, 2009
Who is this talk for? Need to write web applications Don’t want/cannot have a heavy framework Experienced Programmers. Know about CPAN, how to learn from CPAN’s documentation. Newer programmers that could use a new/better way to organize their code.
Why these three Modules? Separate out the code to MVC Pieces Each can be used/tested alone The modules themselves are easy to use and understand
Why not Catalyst? mod_perl/fastcgi: You don’t always have the access on the machine to get Catalyst to work. CGI::Application is a ‘lite’ framework, and as such is much smaller. Not as big and scary. Trivial to install in a local ~/lib dir
What is MVC MVC stands for Model-View-Controller
What is MVC MVC breaks the work into three parts Model - Short for database model. DBIx::Class does all the database work: inserts/queries. View - Template::Toolkit does all the view/html work. Controller - CGI::Application holds all the logic to glue the Model and the View together.
What is MVC Who has seen code like this: use DBI; my $sql = &quot;select * from users&quot;; my $dbh = DBI->connect( $ds, $un, $pw ); my $sth = $dbh->prepare($sql); $sth->execute(); print &quot;Content-type: text/html\r\n\r\n&quot;; while (my $h = $sth->fetchrow_hashref()) { print ”Name is:&quot;.$h->{'first_name'}.&quot;<br>\n&quot;; }
What is MVC Who has seen code like this: use DBI; my $sql = &quot;select * from users&quot; ; my $dbh = DBI->connect( $ds, $un, $pw ); my $sth = $dbh->prepare($sql); $sth->execute(); print &quot;Content-type: text/html\r\n\r\n&quot; ; while (my $h = $sth->fetchrow_hashref()) { print ”Name is:&quot;.$h->{'first_name'}.&quot;<br>\n&quot; ; }
What is MVC Who has seen code like this: my $q = new CGI; if ($q-> param('first_name' eq ''){ print input_form(); } else{ my $sql = &quot;insert into users ...&quot;; my $sth = $dbh->prepare($sql); $sth->execute(); print submission_form(); }
What is MVC Who has seen code like this: my $q = new CGI; if ($q-> param('first_name' eq ''){ print input_form(); } else{ my $sql = &quot;insert into users ...&quot; ; my $sth = $dbh->prepare($sql); $sth->execute(); print submission_form(); }
What is MVC Any questions regarding what MVC is?
CGI::Application A sample program: Helloworld.cgi <- config info HelloWorldCgiApp.pm <- controller Html files: <- View header.html body.html footer.html DB/Main.pm <- Model DB/Main/Users.pm DB/Main/Artists.pm DB/Main/CDs.pm
CGI::Application helloworld.cgi: use HelloWorldCgiApp; my $helloworld = HelloWorldCgiApp->new(); $helloworld->run();
CGI::Application helloworld.cgi (with config info): use HelloWorldCgiApp; my $helloworld = HelloWorldCgiApp->new ( PARAMS => { tt_config => { INCLUDE_PATH => &quot;.&quot;, PRE_PROCESS => 'header.html', POST_PROCESS => 'footer.html', }, hw_string => &quot;Hello world!&quot;, }, ); $helloworld->run();
CGI::Application helloworld.cgi (with config info): use lib “~/testdir”; use HelloWorldCgiApp; my $helloworld = HelloWorldCgiApp->new ( PARAMS => { tt_config => { INCLUDE_PATH => &quot;.&quot;, PRE_PROCESS => ‘ test/ header.html', POST_PROCESS => ‘ test/ footer.html', }, hw_string => &quot;Hello test world!&quot;, }, ); $helloworld->run();
CGI::Application HelloWorldCgiApp (continued): package HelloWorldCgiApp; use base 'CGI::Application'; use Template; sub setup { my $self = shift; $self->run_modes( 'mode1' => 'start’, 'mode2' => 'sec_page' ); $self->start_mode('mode1'); }
CGI::Application HelloWorldCgiApp (continued): package HelloWorldCgiApp; use base 'CGI::Application'; use Template; sub setup { my $self = shift; $self->run_modes( 'mode1' => 'start’, 'mode2' => 'sec_page' ); $self->start_mode('mode1'); } $q -> param (‘ rm ’);
CGI::Application HelloWorldCgiApp (continued): sub start { my $self = shift; my $tt_config = $self->param(‘tt_config’) my $tt = Template->new( $tt_config ); $tt->process('body.html', { hwstr => 'hi world!!!', }, \$html); return $html; }
CGI::Application HelloWorldCgiApp (continued): sub cgiapp_prerun { my ($self, $runmode) = @_; my $q = $self->query; #things you need to run every time #input validation etc. #logging }
DBIx::Class The mysql table: CREATE TABLE users ( user_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, first_name varchar(75) NOT NULL, last_name varchar(75) NOT NULL, country_code CHAR(2) NULL ); +---------+------------+-----------+--------------+ | user_id | first_name | last_name | country_code | +---------+------------+-----------+--------------+ | 1 | joe | user | US | | 2 | Steve | Jobs | US | | 3 | Bill | Gates | US | | 4 | Larry | Wall | US | +---------+------------+-----------+--------------+
DBIx::Class DB/Main.pm package DB::Main; use base qw/DBIx::Class::Schema/; __PACKAGE__->load_classes(); 1;
DBIx::Class DB/Main/User.pm package DB::Main::User; use base qw/DBIx::Class/; __PACKAGE__-> load_components(qw/PK::Auto Core/); __PACKAGE__->table('users'); __PACKAGE__->add_columns(qw/ user_id first_name last_name country_code /); __PACKAGE__-> set_primary_key('user_id');
DBIx::Class Using the DBIx::Class Module HelloWorldCgiApp.pm: use DB::Main; my $schema = DB::Main-> connect('dbi:mysql:db','user', 'password'); my @users = $schema->resultset('User')->all; my $users_rs = $schema->resultset('User'); my $user = $users_rs ->next; $tt->process('body.html', { users => [ @users ], user => $ user, }, \$html);
DBIx::Class Using the Module – inserts: my $new_user = $schema-> resultset('User')->new({ last_name => $last_name, first_name => $first_name, }); $new_user->insert;
DBIx::Class Things that you still need to do: Verify your data -- this is good practice under any circumstances Open your database connection Error handling -- did the DB connection open? Did the sql succeed? Unlike some larger frameworks, CGI::Application will not do the error checking for you. It’s a lite framework, so you still need to do some work
Template::Toolkit Why use Template::Toolkit? Common ‘look and feel’ templates. Easy to change for those people who are better at design than we are. What type of data is It good for? arrays hashes scalars
Template::Toolkit Any html file is a TT file! Simplest usage for a scalar: <html> <body> [% var_name %] </body> </html>
Template::Toolkit Usage for an Array where users is an array: <body> [% FOREACH item IN users %] [% item %]<br /> [% END %] </body>
Template::Toolkit Usage where item is a hash: <body> [% item.user_id %] [% item.first_name %] [% item.last_name %] [% item.country %] <br /> </body>
Template::Toolkit Usage for an Array where users is an array of hashes (like an array of rows from a database): <body> [% FOREACH item IN users %] [% item.user_id %] [% item.first_name %] [% item.last_name %] [% item.country %]<br /> [% END %] </body>
Template::Toolkit Usage for an Array where users is an array of hashes (like an array of rows from a database): <body> <form> <input type=“hidden” name= “rm” value=“page_2” [% FOREACH item IN users %] ... [% END %] <input type=“submit”> </form> </body>
There’s more available CGI::Application::Plugin::AbstractCallback CGI::Application::Plugin::ActionDispatch CGI::Application::Plugin::ActionDispatch::Attributes CGI::Application::Plugin::AnyCGI CGI::Application::Plugin::AnyTemplate CGI::Application::Plugin::AnyTemplate::Base CGI::Application::Plugin::AnyTemplate::ComponentHandler CGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplate CGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplateExpr CGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplatePluggable CGI::Application::Plugin::AnyTemplate::Driver::Petal CGI::Application::Plugin::AnyTemplate::Driver::TemplateToolkit CGI::Application::Plugin::Apache CGI::Application::Plugin::Apache2::Request CGI::Application::Plugin::Apache::Request CGI::Application::Plugin::Authentication CGI::Application::Plugin::Authentication::Driver CGI::Application::Plugin::Authentication::Driver::Authen::Simple CGI::Application::Plugin::Authentication::Driver::CDBI CGI::Application::Plugin::Authentication::Driver::DBI CGI::Application::Plugin::Authentication::Driver::DBIC CGI::Application::Plugin::Authentication::Driver::Dummy CGI::Application::Plugin::Authentication::Driver::Filter::crypt CGI::Application::Plugin::Authentication::Driver::Filter::lc CGI::Application::Plugin::Authentication::Driver::Filter::md5 CGI::Application::Plugin::Authentication::Driver::Filter::sha1 CGI::Application::Plugin::Authentication::Driver::Filter::strip CGI::Application::Plugin::Authentication::Driver::Filter::uc CGI::Application::Plugin::Authentication::Driver::Generic CGI::Application::Plugin::Authentication::Driver::HTPasswd CGI::Application::Plugin::Authentication::Store CGI::Application::Plugin::Authentication::Store::Cookie CGI::Application::Plugin::Authentication::Store::Session CGI::Application::Plugin::Authorization CGI::Application::Plugin::Authorization::Driver CGI::Application::Plugin::Authorization::Driver::DBI CGI::Application::Plugin::Authorization::Driver::Dummy CGI::Application::Plugin::Authorization::Driver::Generic CGI::Application::Plugin::Authorization::Driver::HTGroup CGI::Application::Plugin::Authorization::Driver::SimpleGroup CGI::Application::Plugin::AutoRunmode CGI::Application::Plugin::AutoRunmode::FileDelegate CGI::Application::Plugin::BREAD CGI::Application::Plugin::BrowserDetect CGI::Application::Plugin::CAPTCHA CGI::Application::Plugin::CHI CGI::Application::Plugin::Cache::Adaptive CGI::Application::Plugin::CaptureIO CGI::Application::Plugin::CompressGzip CGI::Application::Plugin::Config::Any CGI::Application::Plugin::Config::Context CGI::Application::Plugin::Config::General CGI::Application::Plugin::Config::IniFiles CGI::Application::Plugin::Config::Simple CGI::Application::Plugin::Config::YAML CGI::Application::Plugin::ConfigAuto CGI::Application::Plugin::DBH CGI::Application::Plugin::DBIProfile CGI::Application::Plugin::DBIProfile::Data CGI::Application::Plugin::DBIProfile::Graph::GDGraphInline CGI::Application::Plugin::DBIProfile::Graph::HTML CGI::Application::Plugin::DBIProfile::Graph::HTML::Horizontal CGI::Application::Plugin::DBIProfile::Graph::HTMLBarGraph CGI::Application::Plugin::DBIProfile::Graph::SVGTT CGI::Application::Plugin::DebugMessage CGI::Application::Plugin::DebugScreen CGI::Application::Plugin::DevPopup CGI::Application::Plugin::DevPopup::HTTPHeaders CGI::Application::Plugin::DevPopup::Log CGI::Application::Plugin::DevPopup::Timing CGI::Application::Plugin::Email CGI::Application::Plugin::Eparam CGI::Application::Plugin::ErrorPage CGI::Application::Plugin::Feedback CGI::Application::Plugin::FillInForm CGI::Application::Plugin::Flash CGI::Application::Plugin::FormState CGI::Application::Plugin::FormValidator::Simple CGI::Application::Plugin::Forward CGI::Application::Plugin::HTCompiled CGI::Application::Plugin::HTDot CGI::Application::Plugin::HTMLPrototype CGI::Application::Plugin::HelpMan CGI::Application::Plugin::HtmlTidy CGI::Application::Plugin::I18N CGI::Application::Plugin::JSON CGI::Application::Plugin::LinkIntegrity CGI::Application::Plugin::LogDispatch CGI::Application::Plugin::Mason CGI::Application::Plugin::Menu CGI::Application::Plugin::MessageStack CGI::Application::Plugin::MetadataDB CGI::Application::Plugin::Output::XSV CGI::Application::Plugin::PageBuilder CGI::Application::Plugin::ParsePath CGI::Application::Plugin::Phrasebook CGI::Application::Plugin::ProtectCSRF CGI::Application::Plugin::RateLimit CGI::Application::Plugin::Redirect CGI::Application::Plugin::RequireSSL CGI::Application::Plugin::Routes CGI::Application::Plugin::RunmodeDeclare CGI::Application::Plugin::Session CGI::Application::Plugin::Stash CGI::Application::Plugin::Stream CGI::Application::Plugin::TT CGI::Application::Plugin::TT::LastModified CGI::Application::Plugin::TemplateRunner CGI::Application::Plugin::Thumbnail CGI::Application::Plugin::TmplInnerOuter CGI::Application::Plugin::ValidateRM CGI::Application::Plugin::View::HTML::Template CGI::Application::Plugin::ViewCode CGI::Application::Plugin::YAML
Questions?
Thank you Leonard Miller February 7th Frozen Perl 2009

Create a web-app with Cgi Appplication

  • 1.
    How to createa simple Web application with CGI::Application Template::Toolkit and DBIx::Class Leonard Miller February 7, 2009
  • 2.
    Who is thistalk for? Need to write web applications Don’t want/cannot have a heavy framework Experienced Programmers. Know about CPAN, how to learn from CPAN’s documentation. Newer programmers that could use a new/better way to organize their code.
  • 3.
    Why these threeModules? Separate out the code to MVC Pieces Each can be used/tested alone The modules themselves are easy to use and understand
  • 4.
    Why not Catalyst?mod_perl/fastcgi: You don’t always have the access on the machine to get Catalyst to work. CGI::Application is a ‘lite’ framework, and as such is much smaller. Not as big and scary. Trivial to install in a local ~/lib dir
  • 5.
    What is MVCMVC stands for Model-View-Controller
  • 6.
    What is MVCMVC breaks the work into three parts Model - Short for database model. DBIx::Class does all the database work: inserts/queries. View - Template::Toolkit does all the view/html work. Controller - CGI::Application holds all the logic to glue the Model and the View together.
  • 7.
    What is MVCWho has seen code like this: use DBI; my $sql = &quot;select * from users&quot;; my $dbh = DBI->connect( $ds, $un, $pw ); my $sth = $dbh->prepare($sql); $sth->execute(); print &quot;Content-type: text/html\r\n\r\n&quot;; while (my $h = $sth->fetchrow_hashref()) { print ”Name is:&quot;.$h->{'first_name'}.&quot;<br>\n&quot;; }
  • 8.
    What is MVCWho has seen code like this: use DBI; my $sql = &quot;select * from users&quot; ; my $dbh = DBI->connect( $ds, $un, $pw ); my $sth = $dbh->prepare($sql); $sth->execute(); print &quot;Content-type: text/html\r\n\r\n&quot; ; while (my $h = $sth->fetchrow_hashref()) { print ”Name is:&quot;.$h->{'first_name'}.&quot;<br>\n&quot; ; }
  • 9.
    What is MVCWho has seen code like this: my $q = new CGI; if ($q-> param('first_name' eq ''){ print input_form(); } else{ my $sql = &quot;insert into users ...&quot;; my $sth = $dbh->prepare($sql); $sth->execute(); print submission_form(); }
  • 10.
    What is MVCWho has seen code like this: my $q = new CGI; if ($q-> param('first_name' eq ''){ print input_form(); } else{ my $sql = &quot;insert into users ...&quot; ; my $sth = $dbh->prepare($sql); $sth->execute(); print submission_form(); }
  • 11.
    What is MVCAny questions regarding what MVC is?
  • 12.
    CGI::Application A sampleprogram: Helloworld.cgi <- config info HelloWorldCgiApp.pm <- controller Html files: <- View header.html body.html footer.html DB/Main.pm <- Model DB/Main/Users.pm DB/Main/Artists.pm DB/Main/CDs.pm
  • 13.
    CGI::Application helloworld.cgi: useHelloWorldCgiApp; my $helloworld = HelloWorldCgiApp->new(); $helloworld->run();
  • 14.
    CGI::Application helloworld.cgi (withconfig info): use HelloWorldCgiApp; my $helloworld = HelloWorldCgiApp->new ( PARAMS => { tt_config => { INCLUDE_PATH => &quot;.&quot;, PRE_PROCESS => 'header.html', POST_PROCESS => 'footer.html', }, hw_string => &quot;Hello world!&quot;, }, ); $helloworld->run();
  • 15.
    CGI::Application helloworld.cgi (withconfig info): use lib “~/testdir”; use HelloWorldCgiApp; my $helloworld = HelloWorldCgiApp->new ( PARAMS => { tt_config => { INCLUDE_PATH => &quot;.&quot;, PRE_PROCESS => ‘ test/ header.html', POST_PROCESS => ‘ test/ footer.html', }, hw_string => &quot;Hello test world!&quot;, }, ); $helloworld->run();
  • 16.
    CGI::Application HelloWorldCgiApp (continued): package HelloWorldCgiApp; use base 'CGI::Application'; use Template; sub setup { my $self = shift; $self->run_modes( 'mode1' => 'start’, 'mode2' => 'sec_page' ); $self->start_mode('mode1'); }
  • 17.
    CGI::Application HelloWorldCgiApp (continued): package HelloWorldCgiApp; use base 'CGI::Application'; use Template; sub setup { my $self = shift; $self->run_modes( 'mode1' => 'start’, 'mode2' => 'sec_page' ); $self->start_mode('mode1'); } $q -> param (‘ rm ’);
  • 18.
    CGI::Application HelloWorldCgiApp (continued): sub start { my $self = shift; my $tt_config = $self->param(‘tt_config’) my $tt = Template->new( $tt_config ); $tt->process('body.html', { hwstr => 'hi world!!!', }, \$html); return $html; }
  • 19.
    CGI::Application HelloWorldCgiApp (continued): sub cgiapp_prerun { my ($self, $runmode) = @_; my $q = $self->query; #things you need to run every time #input validation etc. #logging }
  • 20.
    DBIx::Class The mysqltable: CREATE TABLE users ( user_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, first_name varchar(75) NOT NULL, last_name varchar(75) NOT NULL, country_code CHAR(2) NULL ); +---------+------------+-----------+--------------+ | user_id | first_name | last_name | country_code | +---------+------------+-----------+--------------+ | 1 | joe | user | US | | 2 | Steve | Jobs | US | | 3 | Bill | Gates | US | | 4 | Larry | Wall | US | +---------+------------+-----------+--------------+
  • 21.
    DBIx::Class DB/Main.pm packageDB::Main; use base qw/DBIx::Class::Schema/; __PACKAGE__->load_classes(); 1;
  • 22.
    DBIx::Class DB/Main/User.pm packageDB::Main::User; use base qw/DBIx::Class/; __PACKAGE__-> load_components(qw/PK::Auto Core/); __PACKAGE__->table('users'); __PACKAGE__->add_columns(qw/ user_id first_name last_name country_code /); __PACKAGE__-> set_primary_key('user_id');
  • 23.
    DBIx::Class Using theDBIx::Class Module HelloWorldCgiApp.pm: use DB::Main; my $schema = DB::Main-> connect('dbi:mysql:db','user', 'password'); my @users = $schema->resultset('User')->all; my $users_rs = $schema->resultset('User'); my $user = $users_rs ->next; $tt->process('body.html', { users => [ @users ], user => $ user, }, \$html);
  • 24.
    DBIx::Class Using theModule – inserts: my $new_user = $schema-> resultset('User')->new({ last_name => $last_name, first_name => $first_name, }); $new_user->insert;
  • 25.
    DBIx::Class Things thatyou still need to do: Verify your data -- this is good practice under any circumstances Open your database connection Error handling -- did the DB connection open? Did the sql succeed? Unlike some larger frameworks, CGI::Application will not do the error checking for you. It’s a lite framework, so you still need to do some work
  • 26.
    Template::Toolkit Why useTemplate::Toolkit? Common ‘look and feel’ templates. Easy to change for those people who are better at design than we are. What type of data is It good for? arrays hashes scalars
  • 27.
    Template::Toolkit Any htmlfile is a TT file! Simplest usage for a scalar: <html> <body> [% var_name %] </body> </html>
  • 28.
    Template::Toolkit Usage foran Array where users is an array: <body> [% FOREACH item IN users %] [% item %]<br /> [% END %] </body>
  • 29.
    Template::Toolkit Usage where item is a hash: <body> [% item.user_id %] [% item.first_name %] [% item.last_name %] [% item.country %] <br /> </body>
  • 30.
    Template::Toolkit Usage foran Array where users is an array of hashes (like an array of rows from a database): <body> [% FOREACH item IN users %] [% item.user_id %] [% item.first_name %] [% item.last_name %] [% item.country %]<br /> [% END %] </body>
  • 31.
    Template::Toolkit Usage foran Array where users is an array of hashes (like an array of rows from a database): <body> <form> <input type=“hidden” name= “rm” value=“page_2” [% FOREACH item IN users %] ... [% END %] <input type=“submit”> </form> </body>
  • 32.
    There’s more availableCGI::Application::Plugin::AbstractCallback CGI::Application::Plugin::ActionDispatch CGI::Application::Plugin::ActionDispatch::Attributes CGI::Application::Plugin::AnyCGI CGI::Application::Plugin::AnyTemplate CGI::Application::Plugin::AnyTemplate::Base CGI::Application::Plugin::AnyTemplate::ComponentHandler CGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplate CGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplateExpr CGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplatePluggable CGI::Application::Plugin::AnyTemplate::Driver::Petal CGI::Application::Plugin::AnyTemplate::Driver::TemplateToolkit CGI::Application::Plugin::Apache CGI::Application::Plugin::Apache2::Request CGI::Application::Plugin::Apache::Request CGI::Application::Plugin::Authentication CGI::Application::Plugin::Authentication::Driver CGI::Application::Plugin::Authentication::Driver::Authen::Simple CGI::Application::Plugin::Authentication::Driver::CDBI CGI::Application::Plugin::Authentication::Driver::DBI CGI::Application::Plugin::Authentication::Driver::DBIC CGI::Application::Plugin::Authentication::Driver::Dummy CGI::Application::Plugin::Authentication::Driver::Filter::crypt CGI::Application::Plugin::Authentication::Driver::Filter::lc CGI::Application::Plugin::Authentication::Driver::Filter::md5 CGI::Application::Plugin::Authentication::Driver::Filter::sha1 CGI::Application::Plugin::Authentication::Driver::Filter::strip CGI::Application::Plugin::Authentication::Driver::Filter::uc CGI::Application::Plugin::Authentication::Driver::Generic CGI::Application::Plugin::Authentication::Driver::HTPasswd CGI::Application::Plugin::Authentication::Store CGI::Application::Plugin::Authentication::Store::Cookie CGI::Application::Plugin::Authentication::Store::Session CGI::Application::Plugin::Authorization CGI::Application::Plugin::Authorization::Driver CGI::Application::Plugin::Authorization::Driver::DBI CGI::Application::Plugin::Authorization::Driver::Dummy CGI::Application::Plugin::Authorization::Driver::Generic CGI::Application::Plugin::Authorization::Driver::HTGroup CGI::Application::Plugin::Authorization::Driver::SimpleGroup CGI::Application::Plugin::AutoRunmode CGI::Application::Plugin::AutoRunmode::FileDelegate CGI::Application::Plugin::BREAD CGI::Application::Plugin::BrowserDetect CGI::Application::Plugin::CAPTCHA CGI::Application::Plugin::CHI CGI::Application::Plugin::Cache::Adaptive CGI::Application::Plugin::CaptureIO CGI::Application::Plugin::CompressGzip CGI::Application::Plugin::Config::Any CGI::Application::Plugin::Config::Context CGI::Application::Plugin::Config::General CGI::Application::Plugin::Config::IniFiles CGI::Application::Plugin::Config::Simple CGI::Application::Plugin::Config::YAML CGI::Application::Plugin::ConfigAuto CGI::Application::Plugin::DBH CGI::Application::Plugin::DBIProfile CGI::Application::Plugin::DBIProfile::Data CGI::Application::Plugin::DBIProfile::Graph::GDGraphInline CGI::Application::Plugin::DBIProfile::Graph::HTML CGI::Application::Plugin::DBIProfile::Graph::HTML::Horizontal CGI::Application::Plugin::DBIProfile::Graph::HTMLBarGraph CGI::Application::Plugin::DBIProfile::Graph::SVGTT CGI::Application::Plugin::DebugMessage CGI::Application::Plugin::DebugScreen CGI::Application::Plugin::DevPopup CGI::Application::Plugin::DevPopup::HTTPHeaders CGI::Application::Plugin::DevPopup::Log CGI::Application::Plugin::DevPopup::Timing CGI::Application::Plugin::Email CGI::Application::Plugin::Eparam CGI::Application::Plugin::ErrorPage CGI::Application::Plugin::Feedback CGI::Application::Plugin::FillInForm CGI::Application::Plugin::Flash CGI::Application::Plugin::FormState CGI::Application::Plugin::FormValidator::Simple CGI::Application::Plugin::Forward CGI::Application::Plugin::HTCompiled CGI::Application::Plugin::HTDot CGI::Application::Plugin::HTMLPrototype CGI::Application::Plugin::HelpMan CGI::Application::Plugin::HtmlTidy CGI::Application::Plugin::I18N CGI::Application::Plugin::JSON CGI::Application::Plugin::LinkIntegrity CGI::Application::Plugin::LogDispatch CGI::Application::Plugin::Mason CGI::Application::Plugin::Menu CGI::Application::Plugin::MessageStack CGI::Application::Plugin::MetadataDB CGI::Application::Plugin::Output::XSV CGI::Application::Plugin::PageBuilder CGI::Application::Plugin::ParsePath CGI::Application::Plugin::Phrasebook CGI::Application::Plugin::ProtectCSRF CGI::Application::Plugin::RateLimit CGI::Application::Plugin::Redirect CGI::Application::Plugin::RequireSSL CGI::Application::Plugin::Routes CGI::Application::Plugin::RunmodeDeclare CGI::Application::Plugin::Session CGI::Application::Plugin::Stash CGI::Application::Plugin::Stream CGI::Application::Plugin::TT CGI::Application::Plugin::TT::LastModified CGI::Application::Plugin::TemplateRunner CGI::Application::Plugin::Thumbnail CGI::Application::Plugin::TmplInnerOuter CGI::Application::Plugin::ValidateRM CGI::Application::Plugin::View::HTML::Template CGI::Application::Plugin::ViewCode CGI::Application::Plugin::YAML
  • 33.
  • 34.
    Thank you LeonardMiller February 7th Frozen Perl 2009

Editor's Notes

  • #3 First off, who is this talk for? A few years ago I had a conversation with a co-worker who was a competent programmer, with a degree in computer science. In all of his classes, he had never heard of MVC, and found my group’s method of programming to be confusing. He knew Perl, among other languages, so I decided to write this talk for perl programmers who don’t know MVC. Programmers who need to write web applications in their day to day work. Not necessarily heavy perl programmers, and they don’t necessarily have full access to the (machines/apache configs) their scripts are running on, therefore Catalyst is out of the question. As I said my coworker a few years back was an experienced programmer, he just didn’t know exactly what MVC meant, nor does he use Perl a lot. He understood Data how structures work, as well as databases and the complications that arise when using a database. Just not the in’s and out’s of a web app in perl My co-worker also knew about CPAN and knew how to leverage CPAN modules. He just didn’t know about these modules. Also this talk is for me nine years ago. I was a new programmer and didn’t know to separate the code into the MVC components.
  • #4 Each of the modules can be used and tested alone, you are not required to commit to all three at once. You could do a rolling implementation where you pick one, say Template toolkit, and move to it one page at a time. This way you can test each little piece, and you could switch over the course of a year, each time you do a bug fix on a specific page, you can start to use TT on that page. Also, by themselves, each module is easy to understand. This doesn’t mean that we are tied to these three modules to accomplish these goals, I gave a version of this talk at YAPC08 where instead of DBIx::Class I used the outdated Class::DBI . If you are really tied to a specific ORM like Dave Rolsky’s FEY that you will hear about later today, you can use that instead. The point of this talk is to show one way to implement MVC
  • #5 Catalyst is a great framework, but Catalyst is too big and not easily available on the systems that my employer uses, but it is easy for us to download and install these modules into a local directory without any elevated access, or access to the apache config files.
  • #7 The model is the Database. If you have special database needs, or wanted to write your own SQL, that code would go into your Model section. If you were using a completely different database system besides SQL, that would go here. Its like saying: I don’t care how, just get the user with this Primary Key The View is for all the viewing of the data. If you are going to write HTML, that would go into the View. Outside of the Web Application World, the view is the User interface, and all that would go with the UI belongs here. The controller is the glue that takes information from the View, decides what to do with it, processes it, does inserts/deletes/reads/updates as required with the database, and then tells the VIEW what to do. This is where all the business logic belongs, doing things like data validation, and applying business rules
  • #8 Who has seen code like this? While this isn’t “bad” code, it could be a lot better. Notice on the bottom we have HTML printing out in the while loop. While this code isn’t so bad, you can see where this is going. This is only one slide, and an html error would be very difficult to find once given enough “code rot”
  • #9 Here I have pointed out that in addition to the Perl you have SQL, HTTP headers, and HTML. MVC here would move each of those into their own modules.
  • #10 Here is another example of some code that isn’t bad, but can get messy quickly. Here we are explicitly looking to see if a user has filled out a form,with a “first name” and branching on that. Also there is sql mixed into the perl, but the html is abstracted away, which is good,
  • #11 However submission_form() might have sql embedded in it, and if there is an HTML error it is still hard to find. MVC here would again break the HTML out into its own file, as well as the SQL. CGI::Application also handles the problem of “what function do I call” by having explicit run modes, using an html input field of ‘rm’
  • #12 Do we have any questions regarding MVC
  • #13 I am going to create a simple CGI::Application, there are six files that I will need to create my webapp. The .cgi file will contain config info, and will kick off the Controller. The Controller is HelloWorldCgiApp.pm The View files will be TemplateToolkit html files The Model is MyDatabase.pm
  • #14 Here is the most basic helloworld.cgi you can get. We use the lib, create the object, and then run the object.
  • #15 This is a little more advanced in that this cgi is passing a few configuration variables to the application Module. Here I am basically setting up a config hash to pass to template toolkit that will prepend and postpend the two given files. I am also passing in a famous string.
  • #16 By treating the .cgi file as a config file, you make it very easy to setup test scripts/environments. Just put all the production specific information in this file and replace it with the test info including a change to @inc; My office has taken to adding a production flag to the .cgi scripts so that things like overridding of email addresses for testing doesn’t need to be taken out before migrating the code to production.
  • #17 This here is the setup for your basic Controller module. Here we are calling run modes with two modes, mode 1 and mode 2, and they call the functions start() and sec_page() respectively. The next line, we are deciding what runmode to default to, if no runmode is given.
  • #18 Runmodes are key to understanding how CGI::App work. Cgi::app looks for a query parameter named ‘rm’ and calls the corresponding function in the hash here. You can set a hidden variable in your html that will determine the next runmode.
  • #19 This is start() the default runmode that we created in the previous slide. As you can see, we initialize some variables, and then call tt-&gt;process() to get the HTML, and we return that. At this point the CGI::App module will take the HTML and send it to the browser along with the HTML headers.
  • #20 If there is anything you need to do before executing any runmode, there is a prerun that will allow you do do things like creating a database handle, or doing some standard logging.
  • #21 Now we have moved onto MODEL. This is the Database table that we are using. We have four fields, the first is an autonumber, and a primary key.
  • #22 Here is the ClassDBI file to interface with the database.
  • #23 Here is the DBIx::Class file to interface with the database. DBIx::Class also allows One to many relationships to be represented but that is beyond the scope of building a simple web app.
  • #24 This is how you use DBIx::Class inside the Controller. You call a retrieve, and then pass the documents to Template toolkit.
  • #25 Here is the basic insert syntax for DBIx::Class
  • #26 There are some things that you still need to do that might be offered for free from a heavier MVC like catalyst. Because this is a lite framework you still need to explicitly open your database, and manually do inserts/updates/deletes. When you trade off a large framework for a smaller light framework you need to make compromises.
  • #27 TT is the View component in our MVC framework. I chose TT for my example because that is what my office uses. Yes you can use HTML::Toolkit or just about any other type of templating system. I chose TT for my presentation here. These files are much simpler for folks like Web designers to manipulate and give back to you. Again this is the strength of MVC: your web person doesn’t need to understand how the file interacts with perl, they just need to make the html.
  • #28 This will print an HTML page with just the scalar var_name printed out. Pretty simple
  • #29 Here we have a for loop iterating over a list of users.
  • #30 Here we are using the hash notation. TT is smart because it figures out if it needs to dereference something for you, so you don’t have to. If your code required an arrow to dereference the variable, your html gurus don’t need to worry about any of that with TT.
  • #31 Here we have an array of users
  • #33 There are a lot more modules available on CPAN for CGI::Application here are a few