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