changelog the refactoring
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Manual / Tutorial.pod
CommitLineData
83cea649 1=head1 NAME
2
3Catalyst::Manual::Tutorial - Getting started with Catalyst
4
5=head1 DESCRIPTION
6
7This document aims to get you up and running with Catalyst.
8
83cea649 9=head2 Installation
10
61b1e958 11The first step is to install Catalyst, and the simplest way to do this
12is to install the Catalyst bundle from CPAN:
83cea649 13
d538823f 14 $ perl -MCPAN -e 'install Task::Catalyst'
83cea649 15
61b1e958 16This will retrieve Catalyst and a number of useful extensions and
587d5860 17install them for you. This process might not be totally painless
56d8daeb 18though, and you might want to look at CatInABox at
587d5860 19L<http://use.perl.org/~jk2addict/journal/28071>, especially if you are
20on a system that lacks a compiler.
83cea649 21
22
587d5860 23=head2 The very basics - Setting up the skeleton application.
83cea649 24
61b1e958 25Catalyst includes a helper script, C<catalyst.pl>, that will set up a
26skeleton application for you:
83cea649 27
56d8daeb 28 $ catalyst.pl tutorial
b248fa4a 29
de6fb80a 30 created "tutorial"
31 created "tutorial/script"
587d5860 32 ... output snipped
de6fb80a 33 created "tutorial/script/tutorial_create.pl"
83cea649 34
587d5860 35This creates the directory structure, populated with skeleton
61b1e958 36files.
83cea649 37
587d5860 38=head2 Testing out the skeleton application
83cea649 39
40You can test out your new application by running the server script that
07e73f82 41Catalyst provides:
83cea649 42
de6fb80a 43 $ cd tutorial
44 $ script/tutorial_server.pl
b33ed88c 45
b460ad78 46 [...] [catalyst] [debug] Debug messages enabled
387e4c50 47 [...] [catalyst] [debug] Loaded plugins:
48 .------------------------------------------------------------------------------.
49 | Catalyst::Plugin::Static::Simple |
50 '------------------------------------------------------------------------------'
b33ed88c 51 [...] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
61b1e958 52 [...] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
de6fb80a 53 [...] [catalyst] [debug] Found home "/home/users/me/tutorial"
387e4c50 54 [...] [catalyst] [debug] Loaded Private actions:
55 .--------------------------------------+---------------------------------------.
56 | Private | Class |
57 +--------------------------------------+---------------------------------------+
de6fb80a 58 | /default | tutorial |
387e4c50 59 '--------------------------------------+---------------------------------------'
b248fa4a 60
56d8daeb 61 [...] [catalyst] [info] tutorial powered by Catalyst 5.67
387e4c50 62 You can connect to your server at http://localhost:3000
b33ed88c 63
64(Note that each line logged by Catalyst begins with a timestamp, which has
61b1e958 65been replaced here with "C<...>" so that the text fits onto the lines.)
b460ad78 66
61b1e958 67The server is now waiting for you to make requests of it. Try using
68telnet to manually make a simple GET request of the server (when
69telnet responds with "Escape character is '^]'.", type "GET / HTTP/1.0"
70and hit return twice):
83cea649 71
72 $ telnet localhost 3000
73 Trying 127.0.0.1...
74 Connected to localhost.
75 Escape character is '^]'.
76 GET / HTTP/1.0
b248fa4a 77
387e4c50 78 HTTP/1.0 200 OK
79 Date: Mon, 07 Nov 2005 14:57:39 GMT
80 Content-Length: 5525
81 Content-Type: text/html; charset=utf-8
83cea649 82 Status: 200
56d8daeb 83 X-Catalyst: 5.67
83cea649 84
387e4c50 85 [...]
83cea649 86 Connection closed by foreign host.
87 $
88
de6fb80a 89You can see the full welcome message by visiting
387e4c50 90http://localhost:3000/ with your browser.
91
83cea649 92More trace messages will appear in the original terminal window:
93
387e4c50 94 [...] [catalyst] [debug] **********************************
95 [...] [catalyst] [debug] * Request 1 (0.063/s) [2148]
96 [...] [catalyst] [debug] **********************************
97 [...] [catalyst] [debug] Arguments are ""
61b1e958 98 [...] [catalyst] [debug] "GET" request for "" from localhost
387e4c50 99 [...] [catalyst] [info] Request took 0.046883s (21.330/s)
100 .------------------------------------------------------------------+-----------.
101 | Action | Time |
102 +------------------------------------------------------------------+-----------+
103 | /default | 0.000000s |
104 '------------------------------------------------------------------+-----------'
83cea649 105
106The server will continue running until you interrupt it.
107
108The application can also be tested from the command line using the generated
de6fb80a 109helper script, C<script/tutorial_test.pl>.
83cea649 110
8d47005f 111=head2 Getting started
83cea649 112
56d8daeb 113So you picked Catalyst. Good choice. We assume you have installed it as
8d47005f 114well. For this tutorial you will also need the following modules:
83cea649 115
8d47005f 116L<Catalyst::Plugin::Session>
83cea649 117
8d47005f 118L<Catalyst::Plugin::Session::Store::File>
83cea649 119
8d47005f 120L<Catalyst::Plugin::Session::State::Cookie>
83cea649 121
8d47005f 122L<Catalyst::Plugin::Authentication>
83cea649 123
587d5860 124L<Catalyst::Plugin::Authentication::Store::Minimal>
125
126L<Catalyst::Plugin::Authentication::::Minimal>
127
128L<Catalyst::Plugin::Authentication::Credential::Password>
129
8d47005f 130L<Catalyst::Plugin::Authorization::Roles>
83cea649 131
8d47005f 132L<DBD::SQLite>
83cea649 133
8d47005f 134...
135
de6fb80a 136If you have not already done this following the example above, then to get
137started all you need to do is type:
8d47005f 138
de6fb80a 139 catalyst.pl tutorial
8d47005f 140
c425bfeb 141=for commentary
142Poor choice of application name - searching for "tutorial" in the docs
143also results in discussion of the tutorial process, which is probably
144not what the reader wants.
145
146=cut
147
8d47005f 148This should create a directory called F<tutorial> and fill it with the
149default (standard) Catalyst installation. Change to this directory
150because we will be running all further commands from inside the
151F<tutorial> directory.
152
de6fb80a 153If you now run the built-in mini-server with:
154
155 script/tutorial_server.pl
8d47005f 156
de6fb80a 157it will show some standard debug messages in the console screen
158(more about those in a minute), and then inform you that you can now
159connect to the test server on port 3000. Point your browser at
56d8daeb 160http://localhost:3000/ to see the built-in Catalyst welcome screen.
de6fb80a 161
162The other important thing B<catalyst.pl> did was create your root
56d8daeb 163controller. This file is a standard Perl module like all the other
de6fb80a 164controllers that you might add to your application. It lives in the
8d47005f 165F<lib/> directory, and will have the same name as you supplied to the
de6fb80a 166command above. In our case it is F<tutorial.pm>. Alongside this file is
8d47005f 167a directory of the same name, which is the top level namespace for the
168entire application. Thus every other module we create will be
56d8daeb 169"tutorial::something".
8d47005f 170
171The root controller is used to load plugins, to configure the
172application and its plugins, and for generic private actions. We will
173explain more about those later.
174
175=head2 Debugging
176
177The simplest way to debug your Catalyst application is to run it using
b248fa4a 178the built-in mini-server as described in L<Getting started>.
8d47005f 179
180If you want to output any debugging information to the console, then
56d8daeb 181call C<< $c->log->debug() >>, passing it a string to output. For data
182structures, C<use> L<Data::Dumper> and call C<<
c425bfeb 183$c->log->debug(Dumper($structure)) >>
8d47005f 184
185=head2 Model/View/Controller
186
187The recommended method for code organization in a Catalyst application
188is known as the "Model View Controller" design pattern (also referred to
de6fb80a 189"MVC". See L<http://en.wikipedia.org/wiki/Model-view-controller>).
190
56d8daeb 191The point of the MVC pattern is to separate the dependencies of parts of
192the application from each other, and give them standard
8d47005f 193interfaces. Following this theory of organization should give your code
de6fb80a 194all the benefits of modularity. The main benefits are interchangeability
56d8daeb 195of parts and reusability of code.
8d47005f 196
56d8daeb 197Thus you could replace your flat-file data storage with a relational
198database, or your MySQL database with an Oracle database, and not have
199to change any of your Controller or View logic. Or you could later
200decide to output information from your application as RSS instead of
201HTML just by adding a new View module.
8d47005f 202
203=head3 Model
204
205Models deal with the storage of data. For a complex website, you may
56d8daeb 206need multiple data sources, each having its own model class that
207provides an abstracted interface to it. In this tutorial we are going to
208be using a simple database.
8d47005f 209
210=head3 View
211
212Views are used to display information to the user. In a web framework,
56d8daeb 213the View is generally used to output HTML to the browser. As mentioned
214previously, Views can also be used to output RSS or any other kind of
215data. One easy way to do this with Catalyst is to use a templating
216system such as L<Template Toolkit|Template>. If outputting HTML is all
217you are going to do, then you will probably only need one View.
8d47005f 218
219=head3 Controller
220
56d8daeb 221A controller is responsible for responding to user choices, and thus
222controls what the application does. Since this is a web framework,
223Catalyst controllers are frequently used to react directly to URLs
224requested by the user. This tutorial will describe the simplest way of
225using controllers, where each path or part of a path is assigned its own
8d47005f 226action (or subroutine). More complex controlling mechanisms will be
56d8daeb 227mentioned briefly, and can be read about in detail elsewhere in the
228manual.
8d47005f 229
230
231=head2 Controlling
232
56d8daeb 233Now let's write our first bit of application code. First, we would like
8d47005f 234our application to greet our users. We'll assume for now that our users
235will be sent to the I<users/greet> URL. To create a controller that
236serves the I<users> namespace, we run the following command in our
237F<tutorial> directory:
238
de6fb80a 239 script/tutorial_create.pl controller Users
8d47005f 240
241This will create a Users.pm in F<lib/tutorial/Controller>. Open this
242file in an editor and take a look. You will notice there is some
56d8daeb 243commented-out code which we will ignore for now. To make something
8d47005f 244happen when our URL is visited, we will write a "greet" action which
245looks like this:
246
587d5860 247 sub greet : Local {
248 my ($self, $c) = @_;
8d47005f 249
c425bfeb 250 my $name = $c->req->param('name');
587d5860 251 $c->log->debug("Got name: $name\n");
8d47005f 252
587d5860 253 if ($c->req->method eq 'POST') {
254 if(!$name) {
255 $c->stash->{message} = 'Please fill in a name!';
256 }
257 else {
258 $c->stash->{message} = "Hello $name!";
259 }
61b1e958 260 }
587d5860 261 $c->stash->{template} = 'greet.tt';
262 }
8d47005f 263
56d8daeb 264Whew! So, what does all this do? Let's take it one step at a time. The
265subroutine declaration gives the action a name. To the right of the name
266there is an attribute type that looks like this:
de6fb80a 267
268 : Local
269
56d8daeb 270That defines which URIs will translate to this action. "Local" matches
de6fb80a 271exactly one URI:
272
273 /users/greet
274
275The URI matched by "Local" is composed from the namespace minus the
276tutorial::controller portion, that is common to all controllers,
277and the action name itself. Because it is a URI, we use forward slashes
278instead of double colons. So, in summary, when a user requests:
279
280 http://localhost:3000/users/greet
281
282the "greet" action defined above in the Users controller will be executed.
8d47005f 283
284The second line retrieves the parameters Catalyst gives us when it calls
285our method. The first is the instance of our Users class, and the second
56d8daeb 286is commonly called the "context", held in C<$context>, or abbreviated to
287C<$c>. From now on, whenever we are talking about the context object,
288it will be represented as C<$c> in the code.
8d47005f 289
de6fb80a 290The context is the magical object containing any information you need from
291catalyst, or want to send to it, and is passed from action to action.
292You will see it used frequently in Catalyst applications, and a list of all
293its methods is available in the L<Catalyst> POD.
c425bfeb 294
295On the third line we use the ->param method of the context's request object
296to retrieve one of the query parameters, just like in L<CGI>.
8d47005f 297
587d5860 298On the fourth, we make a debug output of this object on the server console,
299or the error log if running under CGI or mod_perl.
8d47005f 300
56d8daeb 301Next, if we have a post request, we check if the name field contains
302anything (or is "true"). If it isn't, we assign an error message to a
303"message" field in the stash. The stash is a special hash of the context
304object, which allows us to pass data on to other methods we call later,
305typically in the View.
8d47005f 306
307If the username did contain a value, then we just set our message to
308greet the user by name.
309
310Finally, we set the special "template" variable in the stash to the name
56d8daeb 311of the template we want our View to use to display this page.
8d47005f 312
313=head2 Viewing
314
56d8daeb 315OK, so reacting and checking the users data is all fine, but how do we
316actually display the page/form in the first place, and our results? In
317this tutorial, we'll use Template Toolkit for our viewing. To create our
318TT-based view, just run the following command:
8d47005f 319
de6fb80a 320 script/tutorial_create.pl view TToolkit TT
8d47005f 321
322Notice that this time we not only gave it the type of module we wanted
323to create (a view), and a name, but also a third argument, "TT". This is
56d8daeb 324a Catalyst helper module, which will make a standard Template Toolkit
8d47005f 325module for you. And that's all you need to do there.
326
327To use the view, the easiest way is to set up a standard "end" action.
56d8daeb 328This is a special private action which will not be matched to a path
329like our "greet" action, but instead will be called after all other
330processing is done. Only one end action will be called in any request
331cycle. If there is one in a controller, it will be preferred over one in
332the application module, and so on.
b248fa4a 333
8d47005f 334Since we're writing a simple application, just add an end action like
335this to F<tutorial.pm>:
336
de6fb80a 337 sub end : Private {
338 my ($self, $c) = @_;
339 $c->forward('tutorial::View::TToolkit') unless $c->res->body();
340 }
8d47005f 341
342The first line declares the end sub, and marks it as a Private action.
56d8daeb 343(This is the second and last attribute type we'll be using in this
344tutorial.) The second line collects our standard parameters as shown in
345the controller's greet action.
8d47005f 346
347The third line directs Catalyst to pass processing on to our TToolkit
56d8daeb 348view. The forward method, when just passed a class name, calls
349C<process> on that class. The standard TT view's C<process> method
350renders the template named in the template variable in the stash, using
351all the other variables in the stash as values to fill it in.
8d47005f 352
56d8daeb 353NB: This is such a common way to end your processing that there is a
8d47005f 354plugin which does it for you: L<Catalyst::Plugin::DefaultEnd>.
355
56d8daeb 356Template Toolkit also has access to the entire context object via the
357special variable "c". For example, using C<[% c.config.name %]> in our
358template will output "tutorial", our project name.
8d47005f 359
360All that remains is to create a simple template called "greet.tt",
587d5860 361containing a form with a text field called "name" like below.
362
c425bfeb 363 <html><head><title> [% c.name %]</head><body>
56d8daeb 364 <p>[% message %]</p>
365 <form action="[% c.req.uri %]" method="post">
587d5860 366 <input type="text" name="name"/>
c425bfeb 367 <input type="submit" value="Submit" name="submit"/>
587d5860 368 </form>
c425bfeb 369 </body></html>
8d47005f 370
56d8daeb 371In the example above, we use C<[% c.req.uri %]>, since we're posting to
372ourself. If we post to another action, we commonly use the uri_for
373method, like this:
587d5860 374
de6fb80a 375 [% c.uri_for('/users/greet')%]
587d5860 376
de6fb80a 377Place this file in the F<root> directory. By default, templates are
c425bfeb 378searched for here, but we can change that, which brings us to...
8d47005f 379
380=head2 Configuring
381
56d8daeb 382As previously mentioned, the configuration of modules, plugins, and so
383on is done in the main application file. This is especially true for
384bits which need to be done before an instance of them is created, for
385example Template Toolkit.
8d47005f 386
387The TT View looks for its templates in the F<root> directory by default.
388Since this is also the directory that static files go in, we'd rather
389have a separate F<templates> directory. To do this, change the config
390call in F<tutorial.pm> like this:
391
392 __PACKAGE__->config( name => 'tutorial',
393 'View::TToolkit' => {
394 'INCLUDE_PATH' => __PACKAGE__->path_to('templates')
395 }
396 );
397
398And move the F<greet.tt> file from F<root> to the F<templates> directory
399(after creating it).
400
de6fb80a 401Now we can run our application again by killing (B<ctrl-c>) and restarting
8d47005f 402B<script/tutorial_server.pl>. Try connecting to
403I<localhost:3000/users/greet> with a browser and see what happens. What
404happens if you try to visit I<localhost:3000/users> ?
405
406=head2 Users and Authenticating
407
56d8daeb 408One of the many reasons to write dynamic websites instead of just using
409static HTML is to allow us to produce different content for different
410users, as well as restricting access to pages (which we could do with
411just Apache's htpasswd system).
8d47005f 412
56d8daeb 413In this tutorial, we will just be using basic authentication. When
414writing a real application, you'll want to use a database or other
415secure store to contain your user data.
8d47005f 416
417To add authentication, all we need to do is add the
56d8daeb 418L<Catalyst::Plugin::Authentication> module to our main application
419file. Then we need to pick a storage method (one of the
420L<Catalyst::Plugin::Authentication::Store> modules), and a method of
421verifying the user's credentials (one of the
422L<Catalyst::Plugin::Authentication::Credential> modules). Edit
423F<tutorial.pm> to look like this:
8d47005f 424
425 use Catalyst qw/-Debug Static::Simple Authentication
426 Authentication::Store::Minimal
427 Authentication::Credential::Password/;
428
56d8daeb 429To configure, add some users to the config call. For example:
8d47005f 430
431 authentication => { 'users' =>
432 { 'fred' =>
433 { 'password' => 'fred1234',
434 }
435 }
436 }
437
56d8daeb 438Generally, setting up configuration data for plugins is done based on
439the type of plugin. Check the documentation of the plugin for exact
440details; in this example we should look in
441L<Catalyst::Plugin::Authentication::Store::Minimal>.
8d47005f 442
56d8daeb 443Since our user data is in the config, we can update it at runtime, and
444thus add users dynamically. (Of course, to keep them permanently we'd
445need to save our data to disk and read it back into the config on
446startup.)
8d47005f 447
56d8daeb 448To allow creation of new users we'll add a C<create> action to our Users
8d47005f 449controller.
450
c425bfeb 451 sub create : Local {
587d5860 452 my ($self, $c) = @_;
c425bfeb 453 my ($username, $passwd1, $passwd2) = map { $c->req->param($_)}
8d47005f 454 ('username', 'password', 'passwordverify');
455
c425bfeb 456 if($username && $passwd1 && $passwd2) {
457 if($c->config->{authentication}{users}{$username}) {
56d8daeb 458 $c->stash->{message} = 'Sorry, that user already exists';
587d5860 459 $c->stash->{username} = $username;
8d47005f 460 }
c425bfeb 461 elsif($passwd1 eq $passwd2) {
462 $c->config->{authentication}->{users}->{$username} =
463 {password => $passwd1};
587d5860 464 $c->stash->{message} = 'User created!';
8d47005f 465 }
c425bfeb 466 else {
587d5860 467 $c->stash->{username} = $username;
c425bfeb 468 $c->stash->{message} = 'Passwords do not match!';
8d47005f 469 }
470 }
587d5860 471 $c->stash->{template} = 'usercreate.tt';
8d47005f 472 }
473
56d8daeb 474All this is doing is checking that all the appropriate fields are
475filled, and that the password fields contain the same data, and then
476adding the user to the config hash. All the checks produce a message
477which can be displayed to the user via the View.
8d47005f 478
c425bfeb 479The usercreate.tt template looks like this:
480
481 <html><head><title>[% c.config.name %]</title></head><body>
482 <h1>Create a new user</h1>
67dde50d 483 <h2>Current users are:</h2>
484 <p>
485 [% FOREACH key = c.config.authentication.users.keys %]
486 [% key %]<br/>
487 [% END %]
488 </p>
56d8daeb 489 <p> [% message %] </p>
c425bfeb 490 <form action="/users/create" method="post">
491 <p>User Name: <input type="text" name="username"/></p>
492 <p>Password: <input type="password" name="password"/></p>
493 <p>Confirm Password: <input type="password" name="passwordverify"/></p>
494 <p><input type="submit" name="submit" value="submit"></p>
495 </form>
496 </body></html>
497
56d8daeb 498In order for our users to be able to login, we need a C<login> action
499which we put in the Users controller:
c425bfeb 500
501 sub login : Local {
502 my ($self, $c) = @_;
503 $c->stash->{template} = 'userlogin.tt';
504 if(!$c->login()) {
505 $c->stash->{message} = 'Please login.';
506 }
507 else {
508 $c->stash->{message} = "Welcome " . $c->user->id;
509 }
8d47005f 510 }
511
c425bfeb 512
513And the userlogin.tt template:
514
515 <html><head><title>[% c.config.name %]</title></head><body>
56d8daeb 516 <p> [% message %] </p>
c425bfeb 517 <form name='login' action='/users/login' method='post'>
518 <p>Username: <input type='text' name='user' /></p>
519 <p>Password: <input type='password' name='password' /></p>
520 <p><input type="submit" /></form>
521 </body></html>
522
523
56d8daeb 524Very simple. Since Credential::Password's "login" call extracts the
525username/password data from the query itself (assuming we use a standard
8d47005f 526name for our form fields), we don't have to do anything but call it.
527
56d8daeb 528To keep the user logged in, all we need to do is add the Session modules
529to our collection, and the Auth modules will automatically use them:
8d47005f 530
531 use Catalyst qw/-Debug Static::Simple Authentication
532 Authentication::Store::Minimal
533 Authentication::Credential::Password
534 Session Session::Store::File Session::State::Cookie/;
535
536Magic!
537
c425bfeb 538=head2 Exercise
539
540As an exercise for the reader, do the following:
541
56d8daeb 542Change C<users/greet> and C<greet.tt> so that the welcome message greets
543the user by name.
c425bfeb 544
56d8daeb 545Enforce user logging in by adding an C<auto> action in tutorial.pm (see
546the L<Catalyst> documentation to find out about the C<auto> action).
c425bfeb 547
56d8daeb 548=head2 Authorizing
8d47005f 549
56d8daeb 550Authentication is about verifying users, and authorization is about
551allowing them to do things. Catalyst currently has two Authorization
c425bfeb 552modules, Roles and ACL. The Roles module allows you to define groups
553which you can assign your users to, and then allow access to areas of
56d8daeb 554your website to the groups. The ACL module lets you do more fine grained
555access/restriction by allowing of denying access however you like. (It
556also supports Roles as done by the roles module.) This example uses
557L<Catalyst::Plugin::Authorization::Roles>. To use this add
558"Authorization::Roles" into the "use Catalyst" statement in tutorial.pm.
8d47005f 559
560Adding Roles via the Minimal store we are already using is quite simple,
561we just add a roles key to each user, defining the names of the roles
562they belong to.
563
564 authentication => { 'users' =>
565 { 'fred' =>
566 { 'password' => 'fred1234',
c425bfeb 567 'roles' => ['admin']
8d47005f 568 }
569 }
570 }
571
572We need an interface for our admins to administer the roles, i.e. assign
573the users to groups. To restrict access to certain actions, we just need
c425bfeb 574to call C<< $c->check_user_roles() >> in each action. So we can
de6fb80a 575make a restricted I<http://localhost:3000/users/groups> page like this:
8d47005f 576
c425bfeb 577 sub groups : Local {
578 my ($self, $c) = @_;
587d5860 579 if($c->check_user_roles('admin')) {
8d47005f 580 # Now we can do things only an admin will see
56d8daeb 581 if (my $params = $c->req->params) {
587d5860 582 my $users = $c->config->{authentication}{users};
583 foreach my $u (keys %$params) {
8d47005f 584 $users->{$u}{roles} = $params->{$u} if($users->{$u});
585 }
c425bfeb 586 $c->stash->{message} = 'Updated user roles!';
8d47005f 587 }
587d5860 588 else {
c425bfeb 589 $c->stash->{users} = $c->config->{authentication};
8d47005f 590 }
c425bfeb 591 $c->stash->{template} = 'usersgroups.tt';
61b1e958 592 }
587d5860 593 else {
c425bfeb 594 $c->stash->{message} = 'Admins Only!';
595 $c->stash->{template} = 'error.tt';
8d47005f 596 }
597 }
598
56d8daeb 599What we are doing here is checking whether the logged-in user (used by
600default in the C<check_user_roles> method) is a member of the admin
601group. If it is, then we display the usergroups template, and update
602the users hash as required. Otherwise, we just show the user an error
603page.
8d47005f 604
c425bfeb 605For this simple example, the usersgroups.tt and error.tt templates could
606both look like this:
607
608 <html><head><title>[% c.config.name %]</title></head><body>
56d8daeb 609 <p>[% message %]</p>
c425bfeb 610 <p>[% c.stash.users %]</p>
611 </body></html>
612
8d47005f 613And that's all there is to it.
614
c425bfeb 615=for authors
616So it's not clear what the groups action is doing - and with the
617current template, nothing happens. Running through the sample code,
56d8daeb 618it's clear what's happening (which is very little), but the purpose,
c425bfeb 619and how to display data is not clear.
620
621=cut
622
623So that you can test this out properly without having to go to the
624trouble of deleting browser cookies manually, we will add a logout
625action in the Users controller:
626
627 sub logout : Local {
628 my ($self, $c) = @_;
629 $c->stash->{message} = "You have successfully logged out";
630 $c->logout;
631 }
632
633
8d47005f 634=head2 Data Storage (Modelling)
635
56d8daeb 636Whether we want our users to be able to contribute to our website, or
637just create it from changeable data, we need to store the data
638somewhere. Generally this is done using a database, but models can also
639use other data sources, for example another website, or an RSS feed.
8d47005f 640
56d8daeb 641If you have or want a database, there are still choices to be
642made. There are several modules for accessing databases using an
643object-oriented wrapper. The best known are probably L<DBIx::Class> and
644L<Class::DBI>. Catalyst supports making models using either of these.
8d47005f 645
56d8daeb 646For a simple example, we will allow our users to store their favorite
647greeting in our database. Create a table called "greetings" in a
648database, that contains a "user" field and a "greeting" field. The
649simplest way to create a model of your database is to use these helper
650modules, for example with L<DBIx::Class>:
8d47005f 651
de6fb80a 652 script/tutorial_create.pl model UserData DBIC dbi:SQLite:/path/to/mydb.db
8d47005f 653
654This will cause the DBIx::Class Loader to inspect your database, and create a
655module in the Model::UserData namespace for each table in your database.
656
56d8daeb 657Now we need a form for our users to enter/edit their personal greetings
658in, so we'll make a I<http://localhost:3000/users/editgreeting> page:
8d47005f 659
587d5860 660 sub editgreeting : Local {
661 my ($self, $c) = @_;
662 if($c->req->params->{greeting}) {
663 if(!$c->user_exists) {
664 $c->stash->{message} = "You're not logged in!";
8d47005f 665 }
587d5860 666 else {
c425bfeb 667 my $grtable = $c->model('UserData::Greetings');
668 my $record = $grtable->find_or_create(user => $c->user->id);
4cfbdfdb 669 $record->greeting($c->req->params->{greeting});
8d47005f 670 $record->update;
587d5860 671 $c->stash->{message} = 'Greeting updated';
8d47005f 672 }
673 }
587d5860 674 $c->stash->{template} = 'usersgreeting.tt';
8d47005f 675 }
83cea649 676
c425bfeb 677Using C<< $c->user_exists >> from the Authentication plugin, this checks
56d8daeb 678whether the user is logged in already. If they are, and they have
679entered a new greeting, we use DBIx::Class' C<find_or_create> method to
680fetch or create a new record in the greetings table for the user. Once
681we have the record, we change the value of the greeting field, and call
682C<update> to store the new value in the database.
eff5f524 683
8d47005f 684=head2 Engines (Apache and FastCGI)
83cea649 685
8d47005f 686Now that we have the basics together, we can try running our application on a
56d8daeb 687"real" server instead of just using the test server that Catalyst comes
8d47005f 688with. L<Catalyst::Engine> is the module used to implement various types of
9ecc2672 689servers to run it on. The current popular ones are Apache and FastCGI.
b460ad78 690
8d47005f 691=head3 Apache
b460ad78 692
9ecc2672 693Apache needs to be configured: we need to tell it to load your
8d47005f 694application. You can either use Catalyst for your entire website, or
695subsections. Use the Location directive to choose a path to run your
696application under:
b460ad78 697
8d47005f 698 <Location />
56d8daeb 699 SetHandler perl-script
de6fb80a 700 PerlResponseHandler tutorial
8d47005f 701 </Location>
b460ad78 702
56d8daeb 703You will need to install the perl modules of your application into one
704of perl's library directories, as listed by B<perl -V>, so that Apache
705can find them. Alternatively you can use the C<PerlSwitches> directive
706to tell Apache where to look:
b460ad78 707
de6fb80a 708 PerlSwitches -I/path/to/tutorial/
b460ad78 709
56d8daeb 710These instructions are for using Apache2 and mod_perl 2.0. If you are
711using mod_perl 1.3 or 1.99, please refer to either
712L<Catalyst::Engine::Apache::MP13> or L<Catalyst::Engine::Apache2::MP19>
713for details of the slightly different ways to do it.
b460ad78 714
8d47005f 715If you wish to ensure that Apache pre-loads your application, use the
56d8daeb 716PerlModule directive. This means that there will be less of a delay when
717your application is accessed.
b460ad78 718
de6fb80a 719 PerlModule tutorial
b460ad78 720
8d47005f 721=head3 FastCGI
b460ad78 722
c425bfeb 723These instructions apply to the use of C<mod_fastcgi> under Apache
724(either 1 or 2 series).
b460ad78 725
c425bfeb 726There are 3 ways to attach a program to a URL with C<mod_fastcgi>;
727we'll examine all of them, and explain how to avoid having the
de6fb80a 728C<tutorial_fastcgi.pl> substring in the user-visible URLs.
b460ad78 729
c425bfeb 730In all of these examples, we assume that the C<DocumentRoot> is
de6fb80a 731C</var>, that our app is called C<tutorial> and is kept in C</usr>, that
c425bfeb 732you want the users to access the app either from the root of the
733server-uri-space, or from C</theapp>. We also assume that the general
734FastCGI settings (C<FastCgiIpcDir>, loading the module) are already
735correct (they don't depend on Catalyst or your application layout).
83cea649 736
8d47005f 737=head4 static application
738
c425bfeb 739In this setup, you tell C<mod_fastcgi> that a particular I<file> is to
740be run as a FastCGI handler. Put this somewhere in Apache's
741configuration:
8d47005f 742
de6fb80a 743 FastCgiServer /usr/apps/tutorial/script/tutorial_fastcgi.pl
744 Alias / /usr/apps/tutorial/script/tutorial_fastcgi.pl/
8d47005f 745
746If you want your app under C</theapp>, change the C<Alias> line to:
747
de6fb80a 748 Alias /theapp /usr/apps/tutorial/script/tutorial_fastcgi.pl
8d47005f 749
de6fb80a 750Note the detail of the trailing C</ >: this is a general rule of the
c425bfeb 751C<Alias> directive, both sides must end with C</ >, or both must not;
752you can't have one with C</ > and the other without, or strange things
753happen.
8d47005f 754
755=head4 dynamic application
756
c425bfeb 757In this setup, you tell C<mod_fastcgi> that certain files are to be
758treated as FastCGI handlers, in the same way you have to tell
759C<mod_cgi>. Put this in the configuration:
8d47005f 760
761 FastCgiConfig -autoUpdate
762
de6fb80a 763 <Directory /usr/apps/tutorial/script>
8d47005f 764 Options +ExecCGI
765 <Files *_fastcgi.pl>
766 SetHandles fastcgi-script
767 </Files>
768 </Directory>
83cea649 769
de6fb80a 770 Alias / /usr/apps/tutorial/script/tutorial_fastcgi.pl/
b460ad78 771
8d47005f 772Again, if you want your app under C</theapp>, change the C<Alias> line to:
b460ad78 773
de6fb80a 774 Alias /theapp /usr/apps/tutorial/script/tutorial_fastcgi.pl
b460ad78 775
8d47005f 776=head4 external server
b460ad78 777
c425bfeb 778In this setup, the application is started separately from Apache, and
779communicates via a socket with C<mod_fastcgi>. This can be useful if
780you need to have a particular environment for your application (maybe
781different between applications), or you want to run them on different
782machines, or under different users for security reasons.
b460ad78 783
c425bfeb 784If you want to use a UNIX socket (on the filesystem), put this in
785Apache's configuration:
b460ad78 786
de6fb80a 787 FastCgiExternalServer /tmp/somewhere -socket /tmp/tutorial-socket
8d47005f 788 Alias / /tmp/somewhere/
b460ad78 789
c425bfeb 790Note that C</tmp> should I<not> exist: it's just a name to connect the
791two parts.
b460ad78 792
c425bfeb 793Again, if you want your app under C</theapp>, change the C<Alias> line
794to:
b460ad78 795
8d47005f 796 Alias /theapp /tmp/somewhere
797
798Then start your Catalyst application:
799
de6fb80a 800 $ cd /usr/apps/tutorial
801 $ ./script/tutorial_fastcgi -l /tmp/tutorial-socket
8d47005f 802
c425bfeb 803If you want to use a TCP socket, simply change the C</tmp> to a
804C<host:port> pair, both in Apache's configuration and on the command
805line of your application.
8d47005f 806
807=head2 Upgrading
808
56d8daeb 809Upgrading your application to newer Catalyst versions is quite
810simple. After installing the new Catalyst package, just run:
8d47005f 811
de6fb80a 812 catalyst.pl -scripts
8d47005f 813
56d8daeb 814One level above your application directory. This will update the scripts
815directory only, and leave the rest of your app alone. If you wish to
816make use of other parts of Catalyst that have been updated, leave off
817the B<-scripts> argument, this will cause .new files to appear, for each
818module that has either been updated, or is different to the original
819because you have changed it. To find out what these changes are, type:
8d47005f 820
de6fb80a 821 diff tutorial/lib/tutorial/View/TT.pm tutorial/lib/tutorial/View/TT.pm.new
8d47005f 822
56d8daeb 823for each of the changed files. (This is a Unix command; Windows users
824will need to find some equivalent.) Copy any changes you need into your
825original file, then remove the .new files. (This makes life less
c425bfeb 826complicated when the next upgrade comes around.)
8d47005f 827
c425bfeb 828=head1 AUTHORS
8d47005f 829
830Jess Robinson, C<jrobinson@cpan.org>
831Andrew Ford, C<A.Ford@ford-mason.co.uk>
832Marcus Ramberg, C<mramberg@cpan.org>
c425bfeb 833Kieren Diment, C<kd@totaldatasolution.com>
de6fb80a 834Gavin Henry, C<ghenry@cpan.org>
b460ad78 835
836Please send comments, corrections and suggestions for improvements to
de6fb80a 837jrobinson@cpan.org, ghenry@cpan.org
8d47005f 838
839=head1 TODO
840
56d8daeb 841Finish DBIC examples with templates and tested code. Make /users/groups
842do something "useful".
8d47005f 843
56d8daeb 844Many other things....
b460ad78 845
83cea649 846=head1 COPYRIGHT
847
61b1e958 848This program is free software, you can redistribute it and/or modify
849it under the same terms as Perl itself.