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