Download - Create a web-app with Cgi Appplication
How to create a simple Web application with CGI::Application
Template::Toolkit and DBIx::Class
Leonard MillerFebruary 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 = "select * from users";my $dbh = DBI->connect( $ds, $un, $pw );my $sth = $dbh->prepare($sql);$sth->execute();print "Content-type: text/html\r\n\r\n";while (my $h = $sth->fetchrow_hashref()){ print ”Name is:".$h->{'first_name'}."<br>\n";}
What is MVC
• Who has seen code like this:use DBI;my $sql = "select * from users";my $dbh = DBI->connect( $ds, $un, $pw );my $sth = $dbh->prepare($sql);$sth->execute();print "Content-type: text/html\r\n\r\n";while (my $h = $sth->fetchrow_hashref()){ print ”Name is:".$h->{'first_name'}."<br>\n";}
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 = "insert into users ..."; 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 = "insert into users ..."; my $sth = $dbh->prepare($sql); $sth->execute(); print submission_form();}
What is MVC
• Any questions regarding what MVC is?
CGI::ApplicationA 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::Applicationhelloworld.cgi:
use HelloWorldCgiApp;
my $helloworld = HelloWorldCgiApp->new();
$helloworld->run();
CGI::Applicationhelloworld.cgi (with config info):
use HelloWorldCgiApp;my $helloworld = HelloWorldCgiApp->new ( PARAMS => { tt_config => { INCLUDE_PATH => ".", PRE_PROCESS => 'header.html', POST_PROCESS => 'footer.html', }, hw_string => "Hello world!", }, );$helloworld->run();
CGI::Applicationhelloworld.cgi (with config info):
use lib “~/testdir”;use HelloWorldCgiApp;my $helloworld = HelloWorldCgiApp->new ( PARAMS => { tt_config => { INCLUDE_PATH => ".", PRE_PROCESS =>
‘test/header.html', POST_PROCESS =>
‘test/footer.html', }, hw_string => "Hello test world!", }, );$helloworld->run();
CGI::ApplicationHelloWorldCgiApp (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::ApplicationHelloWorldCgiApp (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::ApplicationHelloWorldCgiApp (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::ApplicationHelloWorldCgiApp (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 ModuleHelloWorldCgiApp.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::AbstractCallbackCGI::Application::Plugin::ActionDispatchCGI::Application::Plugin::ActionDispatch::AttributesCGI::Application::Plugin::AnyCGICGI::Application::Plugin::AnyTemplateCGI::Application::Plugin::AnyTemplate::BaseCGI::Application::Plugin::AnyTemplate::ComponentHandlerCGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplateCGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplateExprCGI::Application::Plugin::AnyTemplate::Driver::HTMLTemplatePluggableCGI::Application::Plugin::AnyTemplate::Driver::PetalCGI::Application::Plugin::AnyTemplate::Driver::TemplateToolkitCGI::Application::Plugin::ApacheCGI::Application::Plugin::Apache2::RequestCGI::Application::Plugin::Apache::RequestCGI::Application::Plugin::AuthenticationCGI::Application::Plugin::Authentication::DriverCGI::Application::Plugin::Authentication::Driver::Authen::SimpleCGI::Application::Plugin::Authentication::Driver::CDBICGI::Application::Plugin::Authentication::Driver::DBICGI::Application::Plugin::Authentication::Driver::DBICCGI::Application::Plugin::Authentication::Driver::DummyCGI::Application::Plugin::Authentication::Driver::Filter::cryptCGI::Application::Plugin::Authentication::Driver::Filter::lcCGI::Application::Plugin::Authentication::Driver::Filter::md5CGI::Application::Plugin::Authentication::Driver::Filter::sha1CGI::Application::Plugin::Authentication::Driver::Filter::stripCGI::Application::Plugin::Authentication::Driver::Filter::ucCGI::Application::Plugin::Authentication::Driver::GenericCGI::Application::Plugin::Authentication::Driver::HTPasswdCGI::Application::Plugin::Authentication::StoreCGI::Application::Plugin::Authentication::Store::CookieCGI::Application::Plugin::Authentication::Store::SessionCGI::Application::Plugin::AuthorizationCGI::Application::Plugin::Authorization::DriverCGI::Application::Plugin::Authorization::Driver::DBICGI::Application::Plugin::Authorization::Driver::DummyCGI::Application::Plugin::Authorization::Driver::GenericCGI::Application::Plugin::Authorization::Driver::HTGroupCGI::Application::Plugin::Authorization::Driver::SimpleGroupCGI::Application::Plugin::AutoRunmodeCGI::Application::Plugin::AutoRunmode::FileDelegateCGI::Application::Plugin::BREADCGI::Application::Plugin::BrowserDetectCGI::Application::Plugin::CAPTCHACGI::Application::Plugin::CHICGI::Application::Plugin::Cache::AdaptiveCGI::Application::Plugin::CaptureIOCGI::Application::Plugin::CompressGzipCGI::Application::Plugin::Config::AnyCGI::Application::Plugin::Config::ContextCGI::Application::Plugin::Config::GeneralCGI::Application::Plugin::Config::IniFilesCGI::Application::Plugin::Config::SimpleCGI::Application::Plugin::Config::YAMLCGI::Application::Plugin::ConfigAutoCGI::Application::Plugin::DBH
CGI::Application::Plugin::DBIProfileCGI::Application::Plugin::DBIProfile::DataCGI::Application::Plugin::DBIProfile::Graph::GDGraphInlineCGI::Application::Plugin::DBIProfile::Graph::HTMLCGI::Application::Plugin::DBIProfile::Graph::HTML::HorizontalCGI::Application::Plugin::DBIProfile::Graph::HTMLBarGraphCGI::Application::Plugin::DBIProfile::Graph::SVGTTCGI::Application::Plugin::DebugMessageCGI::Application::Plugin::DebugScreenCGI::Application::Plugin::DevPopupCGI::Application::Plugin::DevPopup::HTTPHeadersCGI::Application::Plugin::DevPopup::LogCGI::Application::Plugin::DevPopup::TimingCGI::Application::Plugin::EmailCGI::Application::Plugin::EparamCGI::Application::Plugin::ErrorPageCGI::Application::Plugin::FeedbackCGI::Application::Plugin::FillInFormCGI::Application::Plugin::FlashCGI::Application::Plugin::FormStateCGI::Application::Plugin::FormValidator::SimpleCGI::Application::Plugin::ForwardCGI::Application::Plugin::HTCompiledCGI::Application::Plugin::HTDotCGI::Application::Plugin::HTMLPrototypeCGI::Application::Plugin::HelpManCGI::Application::Plugin::HtmlTidyCGI::Application::Plugin::I18NCGI::Application::Plugin::JSONCGI::Application::Plugin::LinkIntegrityCGI::Application::Plugin::LogDispatchCGI::Application::Plugin::MasonCGI::Application::Plugin::MenuCGI::Application::Plugin::MessageStackCGI::Application::Plugin::MetadataDBCGI::Application::Plugin::Output::XSVCGI::Application::Plugin::PageBuilderCGI::Application::Plugin::ParsePathCGI::Application::Plugin::PhrasebookCGI::Application::Plugin::ProtectCSRFCGI::Application::Plugin::RateLimitCGI::Application::Plugin::RedirectCGI::Application::Plugin::RequireSSLCGI::Application::Plugin::RoutesCGI::Application::Plugin::RunmodeDeclareCGI::Application::Plugin::SessionCGI::Application::Plugin::StashCGI::Application::Plugin::StreamCGI::Application::Plugin::TTCGI::Application::Plugin::TT::LastModifiedCGI::Application::Plugin::TemplateRunnerCGI::Application::Plugin::ThumbnailCGI::Application::Plugin::TmplInnerOuterCGI::Application::Plugin::ValidateRMCGI::Application::Plugin::View::HTML::TemplateCGI::Application::Plugin::ViewCodeCGI::Application::Plugin::YAML
Questions?
Thank you
Leonard MillerFebruary 7th
Frozen Perl 2009