Day 3 - The Layout of a Catalyst Application
The structure and organisation behind a Catalyst application.
catalyst.pl MyApp
When you run the Catalyst helper with the catalyst.pl
command, it
creates quite a lot of files which provide you a skeleton application.
The base application is created with the Catalyst::Helper package (using the Template Toolkit for the actual code generation), which can be subclassed to provide more sophisticated code generators. For example Catalyst::Example::InstantCRUD (which generates traditional form-based database applications) provides an extension to the base helper with Catalyst::Helper::InstantCRUD.
The skeleton application provides a single "Hello World" screen which the user will see when visiting any URL in your application, along with a complete application structure, including directories, basic package files, tests, and more. In this Advent entry, we explain the basic anatomy of a Catalyst application, and explain what these files and directories are for.
Makefile.PL
Location: MyApp/Makefile.PL
It might not look important, but you should never remove this file from your application's base directory: Catalyst needs it to automatically find its location on your computer's filesystem. In addition, it is required in order to build a distribution (e.g. for uploading to CPAN), a PAR package, or just to simply collect your application's dependencies. Catalyst uses Module::Install for Makefile and installation handling. If you'd like to add a dependency on the current version of DBIx::Class, for example, you'd add
requires 'DBIx::Class' => '0.07003';
to Makefile.PL
. This will alert you of a missing module or wrong
version when you run perl Makefile.PL
.
The Tests
Location: MyApp/t
This is the location where your application's tests go. CPAN has a rich set of libraries to assist you in creating live and unit tests.
Usually, Perl tests have the format 00-name.t
, where the 00
is a
number that shows the order of the tests, and name
being the topic
of the test file. Naturally you're not forced to do it this way. For
example, sometimes it's appropriate to use three digits instead of
two, the first being an indicator of what will be tested. To
illustrate:
203-schema_category.t
Where the 2
prefixes all tests for my DBIx-Class schema classes,
and the 03
is the running number showing their order. There are
several ways to run tests, and a wide choice of tools which can be
used. When installing a CPAN module manually, usually we use the
following approach:
perl Makefile.PL # This creates the Makefile and test for # your applications dependencies, if you # specified them in it. make # Prepares your application for the other # uses of 'make'. For example 'make install' make test # Runs your distribution's test suite.
You don't need to do all of that to run your tests, of course. During
development, you can simply run your test suite by using prove
:
prove -l t/*.t
This allows a far more fine-grained control on what parts of the test suites to run. Taking the example from above, This would run the schema test files:
prove -l t/2*.t
The prove
commandline utility is part of the Test-Harness
distribution, which you should find shipped with your Perl 5
distribution. You might want to read up its documentation to explore
the possibilities.
Let's say you want to run a single test file. Nothing's
easier than that, since every .t
file is just a Perl script:
$ perl -Ilib t/203-schema_category.t
Will show you details on every test in the file. If you have taken
out the -Debug
flag of your application, but want to see its
debug output during this run, use the CATALYST_DEBUG
environment
variable:
$ CATALYST_DEBUG=1 perl -Ilib t/203-schema_category.t
If you want to run your tests through the Perl debugger (i.e. perl
-d
) you can use the pler
utility which is part of the
Devel::Pler package available from CPAN.
The root
Location: MyApp/root
This is the place for non-Perl files. By default it includes some nice graphics and Catalyst logos. It's also usually the place for all of your templates, and static files, such as CSS stylesheets, Javascript files, and other graphics. With Catalyst's powerful configuration options, the layout of this directory can be changed completely to fit your needs.
The Configuration File
Location: MyApp/myapp.yml
By default, catalyst.pl
will create a YAML
configuration file for
you, but you're not limited to that. At the time of writing,
Catalyst::Plugin::ConfigLoader
supports YAML, JSON, XML, INI, raw
Perl, and Config::General (Apache-like) file formats. The
configuration file gives you control over any of your components'
config
options. For example this YAML snippet sets .tt2
as the
default template extension for a view class called MyApp::View::TT
:
# myapp.yml # ... View::TT: TEMPLATE_EXTENSION: ".tt2" # ...
The Perl Modules
Location: MyApp/lib
This is where the code for your application actually lives. After creating a new Catalyst project, you will have this initial setup of Perl modules:
The Application Class
Location: MyApp/lib/MyApp.pm
This is were you specify which plugins to load, and where you can
implement methods which will be available through your context object
($c
, as it's usually called). Note however, that it is recommended
that you use the application class only for core configuration and
startup-related issues, and put any other methods into controller
classes.
The MVC Directories
Locations: MyApp/lib/MyApp/Controller MyApp/lib/MyApp/Model MyApp/lib/MyApp/View
Catalyst follows the Model-View-Controller principle of application
design (see Catalyst::Manual::About). Therefore these directories are
provided by default, as almost everyone will need them. You can also add
auxiliary modules here as well (which might work independently of the
Catalyst application). Thus MyApp/Schema/*
would be where you'd put
your database schema, or MyApp/Base/Controller
could be a base class
for controller methods (with subclasses under MyApp/Controller
).
The Root Controller
Location: MyApp/lib/Controller/Root.pm
Most applications will need a place to store relevant application-wide controller actions; these should go into the root controller.
Typical examples are
- A default handler for 404 pages
-
sub default : Private { my ($self, $c) = @_; $c->response->body("404 - File Not Found"); $c->response->status(404); }
- A default hander for the index action
-
sub index : Private { my ($self, $c) = @_; # ... # code for application root # ... }
- An auto handler that performs application-wide authorization
-
sub auto : Private { my ($self, $c) = @_; # Allow people to actually reach crucial pages if ($c->request->path =~ /^(?:login|logout|static/)) { return 1; } # If a user doesn't exist, force login # note the ^ beginning of string placeholder above plugs a possible # security hole if (!$c->user_exists) { # Redirect the user to the login page $c->response->redirect($c->uri_for('/login')); return 0; } # User found, so return 1 to continue with processing return 1; }
The Scripts
Location: MyApp/script
These are used to run your application or its helpers. (Note that some Catalyst engines don't need a script to run, such as the mod_perl and POE engines.)
The Creation Helper Script
This is simply used to create new components in your application, if they provide helpers. You might want to look up their documentation to find out if they do, and what arguments they take. Here are some examples:
script/myapp_create.pl controller Foo::Bar
creates a MyApp::Controller::Foo::Bar
module in
lib/MyApp/Controller/Foo/Bar.pm
. Another common thing might be a
view:
script/myapp_create.pl view TT TT
for a MyApp::View::TT
(see Catalyst::View::TT for details).
The Development Server
During your application's development phase, you don't need to deploy your application to a standalone web server for testing. Catalyst is engine-agnostic, so you can use its built-in server for testing. The command
script/myapp_server.pl -d -p 2050 -r
would run your application with full debugging output (-d
) on port
2050 (-p 2050
) and restart if one of your components changes (-r
).
Running a Test Request
This simple script does nothing more than start up your app, make a request, and print its body to STDOUT. For example:
script/myapp_test.pl /foo/bar
would show you the output of the /foo/bar
action. You could pipe
this to lynx for a quick look at the
generated html. For example:
$ script/myapp_test.pl /foo/bar | lynx -stdin
or:
$ script/myapp_test.pl /foo/bar | lynx -dump -stdin | less
The Engine Scripts
Finally there are myapp_cgi.pl
and myapp_fastcgi.pl
scripts.
While Catalyst will run under plain CGI, this is not recommended as the
application has to start afresh for every request, and thus will be very
slow. However this script can be used in persistent environments like
CGI::SpeedyCGI. The FastCGI script is for use with the FastCGI or
fcgid persistent environments. At
present, FastCGI is the most common deployment route for Catalyst
applications.
Wrap up
So that's what happens when you type catalyst.pl
at the command line.
We hope that this article will help Catalyst users understand the
structure of their applications a bit better. While it may seem
daunting at first, the architecture of a typical Catalyst application is
simple and intuitive.
AUTHORS
Robert 'phaylon' Sedlacek <rs@474.at>
Kieren Diment <diment@gmail.com>
COPYRIGHT
Copyright 2006 Robert Sedlacek. This document can be modified and re-distributed under the same conditions as Perl itself.