Creating a Catalyst Application in Catalyst 5.8

Exclusive offer: get 50% off this eBook here
Catalyst 5.8: the Perl MVC Framework

Catalyst 5.8: the Perl MVC Framework — Save 50%

Build scalable and extendable web applications using the agile MVC framework

$23.99    $12.00
by Antano Solar John | June 2010 | Open Source

In this article by Antano Solar John, author of Catalyst 5.8: The Perl MVC Framework, we will be creating a basic application. We'll create the skeleton of the application and write some Catalyst actions (Perl code that gets executed on URL requests). Then we'll learn how to use the Template Toolkit (TT) to generate HTML output and finally, connect a SQLite database to Catalyst with DBIx::Class.

Creating the application skeleton

Catalyst comes with a script called catalyst.pl to make this task as simple as possible. catalyst.pl takes a single argument, the application's name, and creates an application with that specified name. The name can be any valid Perl module name such as MyApp or MyCompany::HR::Timesheets.

Let's get started by creating MyApp, which is the example application for this article:

$ catalyst.pl MyApp
created "MyApp"
created "MyApp/script"
created "MyApp/lib"
created "MyApp/root"
created "MyApp/root/static"
created "MyApp/root/static/images"
created "MyApp/t"
created "MyApp/lib/MyApp"
created "MyApp/lib/MyApp/Model"
created "MyApp/lib/MyApp/View"
18 ]
created "MyApp/lib/MyApp/Controller"
created "MyApp/myapp.conf"
created "MyApp/lib/MyApp.pm"
created "MyApp/lib/MyApp/Controller/Root.pm"
created "MyApp/README"
created "MyApp/Changes"
created "MyApp/t/01app.t"
created "MyApp/t/02pod.t"
created "MyApp/t/03podcoverage.t"
created "MyApp/root/static/images/catalyst_logo.png"
created "MyApp/root/static/images/btn_120x50_built.png"
created "MyApp/root/static/images/btn_120x50_built_shadow.png"
created "MyApp/root/static/images/btn_120x50_powered.png"
created "MyApp/root/static/images/btn_120x50_powered_shadow.png"
created "MyApp/root/static/images/btn_88x31_built.png"
created "MyApp/root/static/images/btn_88x31_built_shadow.png"
created "MyApp/root/static/images/btn_88x31_powered.png"
created "MyApp/root/static/images/btn_88x31_powered_shadow.png"
created "MyApp/root/favicon.ico"
created "MyApp/Makefile.PL"
created "MyApp/script/myapp_cgi.pl"
created "MyApp/script/myapp_fastcgi.pl"
created "MyApp/script/myapp_server.pl"
created "MyApp/script/myapp_test.pl"
created "MyApp/script/myapp_create.pl"
Change to application directory, and run "perl Makefile.PL" to make sure
your installation is complete.

At this point it is a good idea to check if the installation is complete by switching to the newly-created directory (cd MyApp) and running perl Makefile.PL. You should see something like the following:

$ perl Makefile.PL
include /Volumes/Home/Users/solar/Projects/CatalystBook/MyApp/inc/Module/
Install.pm
include inc/Module/Install/Metadata.pm
include inc/Module/Install/Base.pm
Cannot determine perl version info from lib/MyApp.pm
include inc/Module/Install/Catalyst.pm
*** Module::Install::Catalyst
include inc/Module/Install/Makefile.pm
Please run "make catalyst_par" to create the PAR package!
*** Module::Install::Catalyst finished.
include inc/Module/Install/Scripts.pm
include inc/Module/Install/AutoInstall.pm
include inc/Module/Install/Include.pm
include inc/Module/AutoInstall.pm
*** Module::AutoInstall version 1.03
*** Checking for Perl dependencies...
[Core Features]
- Test::More ...loaded. (0.94 >= 0.88)
- Catalyst::Runtime ...loaded. (5.80021 >= 5.80021)
- Catalyst::Plugin::ConfigLoader ...loaded. (0.23)
- Catalyst::Plugin::Static::Simple ...loaded. (0.29)
- Catalyst::Action::RenderView ...loaded. (0.14)
- Moose ...loaded. (0.99)
- namespace::autoclean ...loaded. (0.09)
- Config::General ...loaded. (2.42)
*** Module::AutoInstall configuration finished.
include inc/Module/Install/WriteAll.pm
include inc/Module/Install/Win32.pm
include inc/Module/Install/Can.pm
include inc/Module/Install/Fetch.pm
Writing Makefile for MyApp
Writing META.yml

Note that it mentions that all the required modules are available. If any modules are missing, you may have to install those modules using cpan.You can also alternatively install the missing modules by running make followed by make install.

We will discuss what each of these files do but for now, let's just change to the newly-created MyApp directory (cd MyApp) and run the following command:

$ perl script/myapp_server.pl

This will start up the development web server. You should see some debugging information appear on the console, which is shown as follows:

[debug] Debug messages enabled
[debug] Loaded plugins:
.--------------------------------------------.
| Catalyst::Plugin::ConfigLoader 0.23
| Catalyst::Plugin::Static::Simple 0.21 |
'--------------------------------------------'
[debug] Loaded dispatcher "Catalyst::Dispatcher" [debug] Loaded engine
"Catalyst::Engine::HTTP"
[debug] Found home "/home/jon/projects/book/chapter2/MyApp"
[debug] Loaded Config "/home/jon/projects/book/chapter2/MyApp/myapp.conf"
[debug] Loaded components:
.-----------------------------+----------.
| Class | Type +-
------------------------------+----------+
| MyApp::Controller::Root | instance |
'----------------------------------+----------'
[debug] Loaded Private actions:
.----------------------+-------- --------+----.
| Private | Class | Method |
+-----------+------------+--------------+
| /default | MyApp::Controller::Root | default |
| /end | MyApp::Controller::Root | end
|/index | MyApp::Controller::Root | index
'--------------+--------------+-------'
[debug] Loaded Path actions:
.----------------+----------
----.
| Path | Private
|
+-------------------+---------------------
----+
| / | /default
|
| / | /index
|
'----------------+----------------------------
----'
[info] MyApp powered by Catalyst 5.80004
You can connect to your server at http://localhost:3000

This debugging information contains a summary of plugins, Models, Views, and Controllers that your application uses, in addition to showing a map of URLs to actions. As we haven't added anything to the application yet, this isn't particularly helpful, but it will become helpful as we add features.

To see what your application looks like in a browser, simply browse to http://localhost:3000. You should see the standard Catalyst welcome page as follows:

Let's put the application aside for a moment, and see the usage of all the files that were created. The list of files is as shown in the following screenshot:

Before we modify MyApp, let's take a look at how a Catalyst application is structured on a disk. In the root directory of your application, there are some support files. If you're familiar with CPAN modules, you'll be at home with Catalyst. A Catalyst application is structured in exactly the same way (and can be uploaded to the CPAN unmodified, if desired).

This article will refer to MyApp as your application's name, so if you use something else, be sure to substitute properly.

Latest helper scripts

Catalyst 5.8 is ported to Moose and the helper scripts for Catalyst were upgraded much later. Therefore, it is necessary for you to check if you have the latest helper scripts. We will discuss helper scripts later. For now, catalyst.pl is a helper script and if you're using an updated helper script, then the lib/MyApp.pm file (or lib/whateverappname.pm) will have the following line:

use Moose;

If you don't see this line in your application package in the lib directory, then you will have to update the helper scripts. You can do that by executing the following command:

cpan Catalyst::Helper

Files in the MyApp directory

The MyApp directory contains the following files:

  • Makefile.PL: This script generates a Makefile to build, test, and in stall your application. It can also contain a list of your application's CPAN dependencies and automatically install them.
    To run Makefile.PL and generate a Makefile, simply type perl Makefile.PL. After that, you can run make to build the application, make test to test the application (you can try this right now, as some sample tests have already been created), make install to install the application, and so on. For more details, see the Module::Install documentation. It's important that you don't delete this file. Catalyst looks for it to determine where the root of your application is.
  • Changes: This is simply a free-form text file where you can document changes to your application. It's not required, but it can be helpful to end users or other developers working on your application, especially if you're writing an open source application.
  • README: This is just a text file with information on your application. If you're not going to distribute your application, you don't need to keep it around.
  • myapp.conf: This is your application's main confi guration file, which is loaded when you start your application. You can specify configuration directly inside your application, but this file makes it easier to tweak settings without worrying about breaking your code. myapp.conf is in Apache-style syntax, but if you rename the file to myapp.pl, you can write it in Perl (or myapp.yml for YML format; see the Config::Any manual for a complete list).

The name of this file is based on your application's name. Everything is converted to lowercase, double colons are replaced with underscores, and the .conf extension is appended.

Files in the lib directory

The heart of your application lives in the lib directory.

  • This directory contains a file called MyApp.pm. This file defines the namespace and inheritance that are necessary to make this a Catalyst application. It also contains the list of plugins to load application-specific configurations. These configurations can also be defined in the myapp.conf file mentioned previously. However, if the same configuration is mentioned in both the files, then the configuration mentioned here takes precedence.
  • Inside the lib directory, there are three key directories, namely MyApp/Controller, MyApp/Model, and MyApp/View. Catalyst loads the Controllers, Models, and Views from these directories respectively.
Catalyst 5.8: the Perl MVC Framework Build scalable and extendable web applications using the agile MVC framework
Published: July 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

Right now, there's one Controller called Root.pm. This will handle all root level (/) URLs. This is where the code that generates the welcome page is located.

Keep in mind that MyApp is just like any other namespace of a module. The application is created with whatever you passed as an argument to catalyst.pl when you created the application. Just like any other module, a namespace with double colons corresponds to subdirectories in the filesystem. For example, catalyst.pl MyCompany::HR::Timeslips would create the application with the namespace MyCompany::HR::Timeslips. Therefore, it will be represented in the filesystem as MyCompany/HR/ Timeslips.pm as the application is created within the lib directory when using catalyst.pl. The path on the filesystem from the root of your catalyst application will be lib/MyCompany/HR/ Timeslips.pm. Similarly, the other files/directories that are created will be lib/MyCompany/HR/Timeslips/Controller/.

Files in the root directory

The next special directory is the root directory. This directory will hold your templates and other non-code support files. A subdirectory called /root/static is for static content such as images and stylesheets. Catalyst is set up to serve static files from this directory automatically (under the /static path), thanks to Catalyst::Plugin::Static::Simple. Later, when you deploy your application, you can point your web server at this directory to serve the static files without hitting the application every time.

Files in the script directory

Finally, there is the script directory that contains the scripts needed to run, test, and modify your application.

my app_server.pl is the development server; a self-contained HTTP server that you can use to run your application while you're developing it.

my app_cgi.pl is a CGI script for deploying your application with a web server that cannot use mod_perl or FastCGI. It's very slow, so use it only as a last resort.

The last server is called myapp_fastcgi.pl, which allows you to run your application as a FastCGI server.

There are also two utility scripts in this directory. You can use the myapp_test.pl script to test an action, without opening a web browser. For example, you can print the source of the welcome page by running the following command line:

$ perl script/myapp_test.pl /

The last script is myapp_create.pl, which is a version of catalyst.pl that's customized for your application. It can create Models, Views, Controllers, tests, and many other things. We'll use it in the next two sections to create a View and Model for MyApp.

All of the scripts in the script directory accept command-line arguments to customize their behavior. perl script/myapp_<scriptname>.pl --help will explain the details of that script.

Files in the t directory

The t directory is where your application's automatic tests are stored. By default, you'll have the following three tests:

  1. 01app.t, which is a test that passes if your application compiles.
  2. 02pod.t, which will pass if your Plain Old Documentation (POD) embedded API documentation, inside your application, is valid.
  3. 03podcoverage.t, which tests that every public function in your application has some documentation.

You can run the tests in this command by running make test, after Makefile.PL creates the Makefile.

Handling URL requests

When a user makes a request using the browser, Catalyst will look for the appropriate method that can handle the request within packages called Controllers. These Controller methods send back a response to the requesting agent like the browser.

We will discuss in detail later in this article how controller methods are mapped to URLs and vice versa. However, for now, let's stick to a basic format where the first argument in the URL is the name of the Controller, the second argument is the method within the Controller, and the rest of the arguments are arguments to the Controller method. For example, http://localhost:3000/hello/index will match the hello Controller (Hello.pm) and index will match the subroutine index (sub index) within the hello Controller (Hello.pm).

If the Controller method is not mentioned, then the index method is taken as default.

Let's create a new Controller called "Hello" to check this (this should respond to the /hello request):

perl script/myapp_create.pl controller Hello

This will create /lib/MyApp/Controller/Hello.pm (and /t/controller_Hello.t ). Hello.pm will now have the following contents:

package MyApp::Controller::Hello;
use Moose;
use namespace::autoclean;
BEGIN {extends 'Catalyst::Controller'; }
=head1 NAME
MyApp::Controller::Hello - Catalyst Controller
=head1 DESCRIPTION
Catalyst Controller.
=head1 METHODS
=cut
=head2 index
=cut
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
$c->response->body('Matched MyApp::Controller::Hello in Hello.');
}
=head1 AUTHOR
(Your Name on the Machine)
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
__PACKAGE__->meta->make_immutable;
1;

This file consists of three parts. At the top is the package declaration (so Perl knows what this module is named), and then some use statements (to tell Perl that this module uses Moose). Then, BEGIN {extends 'Catalyst::Controller'; } to tell Moose/Perl that this module is a Catalyst Controller. Next, there is some POD (the text starting with =) that you can fill in to provide some API documentation (see man perlpod for the syntax). If you don't think you need documentation, you can delete it; it's ignored by Perl. However, it is a good practice to include at least basic documentation for every module and method. The perldoc utility included with perl will process this documentation into text, HTML, LaTeX, and so on.

Next there's an index subroutine. Following that is some more documentation and a __PACKAGE__-<meta->make_immutable. It tells Moose that this module will not change at runtime. This statement is necessary for performance gains and is good practice to mention in every Moose module. This statement is followed by 1. The 1 is important to Perl for historical reasons and must not be removed. Modules must return true when they'reloaded, otherwise Perl will assume that the loading has failed and will die with an error message. 1 is always true, so it's conventional to use it for this purpose.

Let us check what just happened by running the server with the following command:

perl script/myapp_server.pl

You will see something like the following besides the debug information you saw earlier:

[debug] Loaded Path actions:
.---------------------------------+-----------------------
----.
| Path | Private
|
+------------------------------+-------------------------
----+
| / | /index
|
| / | /default
|
| /hello | /hello/index
|

Opening the URL http://localhost:3000/hello will show you the following:

Matched MyApp::Controller::Hello in Hello

Adding a View

Now that the URL is mapped to the Controller method as expected, let us try something more challenging and show some HTML content. Instead of writing the HTML inside the response body as in the previous example, in this section, we will use a View. A View is a system that defi nes how content will be rendered. For this article, we will mostly be using the TT view which is based on a templating package, TT, that is available for any Perl program independent of Catalyst. To learn more about the TT package, visit http://template-toolkit.org/.

In the Controller method (sub index in Hello.pm), we will remove the line $c-<response-<body(). So, the Controller method looks like the following:

sub index :Path :Args(0) {
my ( $self, $c ) = @_;
}

Please note that Catalyst takes care of forwarding the response to the default view after the Controller's execution. Later in this article, we will discover how Catalyst handles that and how it can be manipulated.

Let us create a View (using TT as mentioned) that the application can use as the default view.

The Template Toolkit module is included with the Catalyst::Devel package, so you should already have it. You'll need to install the Catalyst interface to it though by running the following command line:

$ cpan -i Catalyst::View::TT

If you don't have TT for some reason, cpan will detect that and install it for you. Once that's complete, create the View by running the following command line:

$ perl script/myapp_create.pl view TT TT

You will see something like the following:

$ perl script/myapp_create.pl view TT TT
exists "/Volumes/Home/Users/solar/Projects/CatalystBook/MyApp/script/../
lib/MyApp/View"
exists "/Volumes/Home/Users/solar/Projects/CatalystBook/MyApp/script/../
t"
created "/Volumes/Home/Users/solar/Projects/CatalystBook/MyApp/script/../
lib/MyApp/View/TT.pm"
created "/Volumes/Home/Users/solar/Projects/CatalystBook/MyApp/script/../
t/view_TT.t"

The TT TT part of the previous command means to create a View called View/TT.pm (the first TT) based on the standard Catalyst::View::TT (the second TT). This technically means you can have multiple views of Catalyst::View::TT with different names. You can choose any valid Perl filename as the name of your View (the first TT), but a simple TT makes the most sense here. For more complex applications with multiple views, it is a best practice to name them after the purpose they fulfill such as HTML or JSON.

Next, it's a good idea to add Catalyst::View::TT to the prerequisites section of Makefile.PL. Your application will run fine if you omit this step, but if you're diligent about adding your prerequisites to Makefile.PL, it will be very easy to move your application to another machine. A simple perl Makefile.PL && make on the new machine will allow Catalyst to automatically install all of your application's dependencies while you have a cup of coffee and relax. A minute of your time here will save much more time later.

Currently, the Makefile.PL looks something like the following:

#!/usr/bin/env perl
# IMPORTANT: if you delete this file your app will not work as
# expected. You have been warned.
use inc::Module::Install;
use Module::Install::Catalyst; # Complain loudly if you don't have
# Catalyst::Devel installed or haven't
said
# 'make dist' to create a standalone
tarball.
name 'MyApp';
all_from 'lib/MyApp.pm';
requires 'Catalyst::Runtime' => '5.80021';
requires 'Catalyst::Plugin::ConfigLoader';
requires 'Catalyst::Plugin::Static::Simple';
requires 'Catalyst::Action::RenderView';
requires 'Moose';
requires 'namespace::autoclean';
requires 'Config::General'; # This should reflect the config file
format you've chosen
# See Catalyst::Plugin::ConfigLoader for supported
formats
test_requires 'Test::More' => '0.88';
catalyst;
install_script glob('script/*.pl');
auto_install;
WriteAll;

All you need to do to add a prerequisite is add a line of code like:

requires 'Catalyst::View::TT' => 0;

near the other requires statements in the previous code snippet (order isn't important). The 0 represents the minimum version of the module that your application requires. Leaving it at 0 is fine if you don't know the version, but it's best to specify the current version you're using to develop with. You can determine the version of any module on your system by typing the following line of code:

perl -MSome::Module -e 'print Some::Module->VERSION'

The next step is to create a template in the root/hello directory. For this example, we're going to create a page that says "Hello, world!", so let's call it root/hello/index.tt. The root directory is the default place where Catalyst::View::TT will look for templates. This can be changed by configuration if you really need to.

Here's the code to use in index.tt:


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/
TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Hello, world!</title>
</head>
<body>
<h1>Hello, world.</h1>
<p>
Here's a word from our Controller: [% word | html %].
</p>
</body>
</html>

This is just a regular XHTML file, with some special control sequences for Template Toolkit.

[% word%] tells TT to get the value of a variable called "word" and display it at that point in the template. The | html part after word in the example is a TT filter that means to escape any HTML in word so that < is rendered as an actual < sign and not an HTML tag. This prevents a type of security hole called cross-site scripting (XSS). While security probably isn't important for a "hello world" page, it's wise to get into good habits now.

Run the server, as explained, by typing perl script/myapp_server.pl, and open the page http://localhost/hello.

Hello, world.
Here's a word from our Controller:

Note that nothing is rendered in the place of [% word | html %]. This is because we haven't set that variable "word" in the Controller. Such variables that are passed between Controllers and Views are called stash.

We can set the stash in the Controller by modifying the code to the following:

sub index :Path :Args(0) {
my ( $self, $c) = @;
$c->stash->{word} = "Bonjour!";
}

Now open http://localhost:3000/hello, and you will see the following:

Hello, world.
Here's a word from our Controller: Bonjour!.

Note that the word set in the stash for the variable word is now rendered instead of [% word | html %].

Catalyst 5.8: the Perl MVC Framework Build scalable and extendable web applications using the agile MVC framework
Published: July 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

More on Controller methods

In this section, we will discover the available flexibility on method declaration and URL mapping. We will start by trying to change the last example to accept an argument from the URL that it can render instead of Bonjour!

We can start by modifying the index subroutine. If we have to pass an argument Hello/index/dsads, then we can change the code to the following:

sub index :Path :Args(1) {
my ( $self, $c, @args ) = @_; //Store the argument(s) from the URL
in the list @args
$c->stash->{word} = $args[0];
}

Notice that we have changed Args(0) to Args(1). This will accept the argument after index. The URL /hello is derived from the name of the Controller with colons converted to / and the Hello from Hello.pm converted to all lowercase. The :Path attribute after index tells Catalyst that this method will handle URL requests that do not mention the method name such as /hello. The Args(1) attribute declares that this action expects one argument.

Now if you run the server and open a URL like http://localhost:3000/hello/Bonjour!, then you will see the following output:

Hello, world.
Here's a word from our Controller: Bonjour!.

Notice that the [% word | html %] is replaced with Bonjour!. Change Bonjour! to another word in the URL and that word should show up.

Congratulations! You have created your first dynamic Catalyst application.

If we specified :Local instead of :Path, then Catalyst would map the index action to handle a URL that looks like /hello/index. So, the URL looks like the following http://localhost/hello/index/Bonjour!, where Bonjour! is the argument that is being passed to the Controller. If we omitted the attributes (:Local, :Path, and so on), Catalyst would ignore the action entirely and it would be a normal Perl subroutine in the package. If we want to handle any URL with this method, then we can use the :Global attribute.

We also changed the first line of the hello subroutine to receive the parameter within the method. Initially, it looked like my ( $self, $c ) = @_;. This gets the first two arguments passed to the action by Catalyst, $self and $c.

$self is a MyApp::Controller::Hello object and is not of much use right now. $c is the Catalyst context and contains all the information about our application and the current request (and therefore is very useful). Catalyst passes more than just $self and $c though, so we want to modify that line to read my ($self, $c, @args)=@_;. This will allow us to access the rest of the arguments via the @args array.

Arguments are everything in the URL that Catalyst didn't use when matching an action. As an example, /hello/foo would invoke the action matching /hello followed by one argument (if we defi ned index as :Global above, it would accept any number of arguments. That is /hello/foo/bar will match the index method and consider foo and bar as two arguments). These two arguments will be passed to the action and will be available in the @args variable that you specified.

When you run the Catalyst server, you would see something like the following in the log:

[debug] Loaded Path actions:
.-------------------------------------+---------------------.
| Path | Private
|
+-------------------------------------+--------------------+
| / | /index
|
| / | /default
|
| /hello | /hello/index
|
'-------------------------------------+----------------------'

Notice that this table has two columns, Path and Private. Path is what you can mention in the URL and Private is which Controller (hello.pm) and method (sub index) it would get mapped to.

Let us revise what just happened:

my ( $self, $c, @args ) = @_;
my $word = $args[0] || 'Default word';
$c->stash->{word} = $word;

<p>The first line receives all the arguments from the URL in <i>@args</i>.</p>

The second line assigns the first argument to a variable called word (or uses Default Word if there isn't a first argument). Finally, we put $word in the stash as word, so the [% word %] statement in our template can access that variable.

The template that will be rendered is determined by the private name of your action. In this case, the action /hello/hello will be attempted to be rendered with root/hello/hello.tt. If you haven't set $c->response->body yet, the default View will be called to render the template. If you have more than one View, you will have to confi gure a default one by setting the default_view option in your config file to the name of your View. In this example, it would be "TT".

The View will then proceed to look for a stash variable named template that you can set to force a particular template to be rendered. If none is found, then it will use the private path of your action (not the public URI that dispatches to your action, but the /hello/everything path consisting of the Controller and action name) and append .tt as extension. It will look for this hello/hello.tt in the default template include path, which is root.

The stash is a data structure that exists throughout a single Catalyst request. Data you insert into the stash in an action will be available to the View (and other actions). Templates can only access variables that have been explicitly placed here, so it's important to remember to put your useful data in the stash (otherwise it will be gone at the end of the subroutine in the Controller, instead of at the end of the request).

If you're interested in experimenting some more with this setup, here are some things to try. Edit the hello.tt template to change the look of the page. You shouldn't even need to restart your development server for changes to take effect. After that, add another page to your application by creating another subroutine in Hello.pm and another template. Editing Hello.pm will require a restart, but you can automatically restart the server when necessary by running the server like perl script/myapp_server.pl -r -d. The -r will cause the server to restart when appropriate, and the -d will show debugging information, even if you've turned it off inside your application. This is especially useful as you will want to deactivate the hardcoded -Debug option in your MyApp.pm, once you are ready to deploy your application.

Some technical details

At this point, you may be wondering why the hello.tt template showed up without your code ever calling any methods in the Template Toolkit View. This is because the end action in the default Root.pm uses an ActionClass called RenderView. The end action in Root is called at the end of every request, and the RenderView ActionClass will automatically forward to the default View. If you'd rather be explicit about invoking the View, then you can add a line like:

$c->forward('View::TT');

at the end of your action (RenderView will stay out of the way). You can also set a default_view config option for a general default View, or set a stash variable named current_view to the name of the View you want to forward to for the current request only. If you have more than one View you should always explicitly forward or set any of these variables, as currently there's no rigorous definition of "default". You can make every action in a single Controller forward to the same View by overriding the end action in that Controller as follows:

sub end : Private {
my ($self, $c) = @_;
$c->forward('View::TT');
}

If you override end like this, the default end in Root.pm will not be called. (Only one end action is executed per request—the one that's "closest" to the action that started the request cycle.)

Adding a database

The other component that many web applications require is a SQL relational database. Technically whatever ways are available to Perl for accessing databases, Catalyst has them all. The most popular is via an Object-relational mapper (ORM) called DBIx::Class (DBIC). Object-relational mappers allow you to perform operations on your database as though each database object were a Perl object. This means that instead of writing SQL like SELECT * FROM table, you can instead say @results = $table_resultset->all. The advantage of this approach is that DBIC handles the SQL for you, so you can switch from SQLite to DB2 without modifying any of your code. The resulting code in your Controller is also more readable; everything looks like a manipulation of Perl objects and data structures. We'll see the power of this approach throughout the article, but for now, let's just create a simple DBIC Model.

You can use any database that you like for this, but I recommend SQLite for development. SQLite is an "embedded" database, so the database exists as a single file and requires no server to run.

Installing SQLite

The first step is to install SQLite from the SQLite website at http://sqlite.org/ (or through your distribution's package manager, the package is usually called "sqlite3"). You'll also need to install the Perl version of SQLite, called DBD::SQLite, and DBIx::Class itself as well as an adapter that will link our database schema definition to the Catalyst application. You can install these, except for SQLite, using cpan with the following:

$ cpan -i DBD::SQLite DBIx::Class Catalyst::Model::DBIC::Schema

Creating a database schema

Once the dependencies are installed, we'll create a sample database with the sqlite3 command-line utility:

$ sqlite3 tmp/database
SQLite version 3.3.8
Enter ".help" for instructions
sqlite> CREATE TABLE test (id INTEGER PRIMARY KEY, subject TEXT, message
TEXT, date DATETIME);
sqlite> INSERT INTO test (id, subject, message, date) VALUES(NULL, "test
message", "this is a test message", "2005-01-01 00:00");
sqlite> INSERT INTO test (id, subject, message, date) VALUES(NULL,
"another test message", "this is a another test message, hooray", "2005-
01-01 00:01");
sqlite> SELECT * FROM test;
1|test message|this is a test message|2005-01-01 00:00
2|another test message|this is a another test message, hooray|2005-01-01
00:01
sqlite> .quit
$

Here we created a test table in a database file called tmp/database and added two rows to it.

SQLite has unusual semantics for auto-incrementing primary keys. You must declare the auto-increment column exactly as "INTEGER PRIMARY KEY" and then assign NULL during INSERT operations. DBIC will handle this automatically, but you should be aware of this unconventional approach when interacting with the database from within the sqlite3 utility.

Creating a database model for Catalyst

To use this database from Catalyst, we need to create a Catalyst Model. We can do this using the following command line:

$ perl script/myapp_create.pl model TestDatabase DBIC::Schema MyApp::
Schema::TestDatabase create=dynamic dbi:SQLite:tmp/database

If you are on Windows, you may want to be careful in replacing / with \ whenever filesystems are referred.

The first argument is the name of the Catalyst Model (TestDatabase). DBIC::Schema is what sort of model we're creating. MyApp::Schema::TestDatabase is where the schema definition will be stored (we won't use the Schema in this example, but real applications will). create=dynamic tells DBIC to read the database every time the application is started to determine the schema (layout of tables, foreign key relations, and so on.). The final argument is the DBI connect string for the database.

Using the Model

We'll also create another Controller to learn to create a database Model as follows:

$ perl script/myapp_create.pl controller Database

Now, we'll want to create code to show this template in the Database.pm Controller. In this case, using the index action that's automatically generated will be fine.

We will need to populate a variable called messages with the data from our database. The code to do this looks like the following:

sub index :Path Args(0) {
# same as index :Private my ( $self, $c ) = @_;
$c->stash->{messages} = $c->model('TestDatabase::test')->search({});
}

This is almost the same as our hello action, but in this case we fill the messages variable with the entries in the test table (in the TestDatabase Model). The $c->model(...) syntax allows you to access any Model by name. DBIC::Schema supports extra syntax to allow you to name a table in the database directly (the :: test part), so we use that to create a ResultSet object. The ResultSet is an iterator object that will only access the database when it is required; this is to make sure it doesn't fetch any data that isn't required by the application. The ->search({}) part will make sure that you receive a fresh ResultSet object.

Once we have this, we'll create a template to show data from the database in a file called root/database/index.tt. It should look like the following:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/
TR/xhtml11/DTD/xhtml11.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Hello, database!</title>
</head>
<body>
<h1>Database</h1>
<p>Here's what the database looks like: </p>
<ol>
[% WHILE (message = messages.next) %]
<li>
<p>Message <b>[% message.subject | html %]</b> (#[% message.id | html
%]):</p>
<p>[% message.message | html %]</p>
<p>Written at <i>[% message.date | html %]</i>.</p>
</li>
[% END %]
</ol>
</body>
</html>

The [% WHILE (message = messages.next) %] command loops over each row in the ResultSet for the test table, and creates a variable called message that holds that row. The other [% ... %] commands in the template simply extract the data from the row via the column name. That's all there is to it—Catalyst handles the hard stuff for you!

To view your database as an HTML page, start the development server again and browse to http://localhost:3000/database.

You will see something like the following:

Summary

In this article, we created our first Catalyst application with the catalyst.pl utility. After running the skeleton application and inspecting it with a web browser, we added an HTML template View with the myapp_create.pl script and created a "Hello" Controller to display a "Hello, world" page. Finally, we added a database Model using DBIC::Schema and created a Controller containing actions that show data from the database, via the View and templates, as an HTML page.

About the Author :


Antano Solar John

Antano Solar is a techie to the core—a tech evangelist who is passionate about using technology to revolutionize the learning experience! Antano has contributed to the open source community in terms of documentation, code, and support, with a variety of platforms based on languages such as PHP, Perl, Lisp, Python, and Ruby.

He loves to share his tech excitement with fellow techies and non-techies, and does so through publishing papers, books, and delivering seminars at colleges, universities such as the IIT, and corporate tech events.

He has published a paper on enhancing wireless networks in an IEEE Journal. His paper on an engine helping machines understand objectives by meta-modeling, using Neurolinguistic Programming principles and Deep Structure, is considered a landmark.

An avid hacker, Antano has won two Yahoo hack-day awards. He recently won the award for developing a Hybrid Search Engine from scratch in 24 hours that uses Machine Intelligence and Social Intelligence to identify, search, and present the information in the required format.

Professionally, until recently, Antano was a Consultant and a Trainer providing IT solutions and sessions on VoIP, Networks and Software Plaforms, and Languages. He is currently the Chief Technology Officer at NuVeda Learning. In his current role, he is responsible for the development and deployment of Learning Management Systems that are used by large MNCs globally. He also plays the role of a Chief Architect in the research and development of technologies related to the understanding and measuring of Learning. He is excited by the challenges of using complex technologies such as Artificial Intelligence and Natural Language Processing.

Occasionally, when Antano needs to take a "Tech" break, he likes to train and tell stories!

Books From Packt

Django 1.2 E-commerce
Django 1.2 E-commerce

Agile Web Application Development with Yii1.1 and PHP5
Agile Web Application Development with Yii1.1 and PHP5

Joomla! 1.5 JavaScript jQuery
Joomla! 1.5 JavaScript jQuery

Grok 1.0 Web Development
Grok 1.0 Web Development

Spring Security 3
Spring Security 3

JavaFX 1.2 Application Development Cookbook
JavaFX 1.2 Application Development Cookbook

GlassFish Security
GlassFish Security

Firebug 1.5: Editing, Debugging, and Monitoring Web Pages
Firebug 1.5: Editing, Debugging, and Monitoring Web Pages

Your rating: None Average: 5 (1 vote)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
g
q
V
A
2
R
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software