How to create a simple Web application with Web::App Template

advertisement
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 = "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::Application
A sample program:
• Helloworld.cgi
<- config info
• HelloWorldCgiApp.pm <- controller
• Html files:
<- View
– header.html
– body.html
– footer.html
• DB/Main.pm
– DB/Main/Users.pm
– DB/Main/Artists.pm
– DB/Main/CDs.pm
<- Model
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 => ".",
PRE_PROCESS
=> 'header.html',
POST_PROCESS => 'footer.html',
},
hw_string => "Hello world!",
},
);
$helloworld->run();
CGI::Application
helloworld.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::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;
$q -> param (‘rm’);
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):
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
[% item %]<br />
[% END %]
</body>
users %]
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
Download