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>