Commit | Line | Data |
83cea649 |
1 | =head1 NAME |
2 | |
3 | Catalyst::Manual::Tutorial - Getting started with Catalyst |
4 | |
5 | =head1 DESCRIPTION |
6 | |
7 | This document aims to get you up and running with Catalyst. |
8 | |
61b1e958 |
9 | NOTE: THIS DOCUMENT IS STILL VERY MUCH IN AN EARLY DRAFT STATE. SEE |
10 | THE NOTES AT THE BOTTOM OF THE DOCUMENT. |
83cea649 |
11 | |
12 | =head2 Installation |
13 | |
61b1e958 |
14 | The first step is to install Catalyst, and the simplest way to do this |
15 | is to install the Catalyst bundle from CPAN: |
83cea649 |
16 | |
17 | $ perl -MCPAN -e 'install Bundle::Catalyst' |
18 | |
61b1e958 |
19 | This will retrieve Catalyst and a number of useful extensions and |
20 | install them for you. |
83cea649 |
21 | |
22 | |
23 | =head2 Setting up your application |
24 | |
61b1e958 |
25 | Catalyst includes a helper script, C<catalyst.pl>, that will set up a |
26 | skeleton application for you: |
83cea649 |
27 | |
83cea649 |
28 | created "My-App" |
29 | created "My-App/script" |
30 | created "My-App/lib" |
31 | created "My-App/root" |
32 | created "My-App/t" |
33 | created "My-App/t/m" |
34 | created "My-App/t/v" |
35 | created "My-App/t/c" |
36 | created "My-App/lib/My/App" |
37 | created "My-App/lib/My/App/M" |
38 | created "My-App/lib/My/App/V" |
39 | created "My-App/lib/My/App/C" |
40 | created "My-App/lib/My/App.pm" |
b33ed88c |
41 | created "My-App/Build.PL" |
83cea649 |
42 | created "My-App/Makefile.PL" |
43 | created "My-App/README" |
44 | created "My-App/Changes" |
45 | created "My-App/t/01app.t" |
b33ed88c |
46 | created "My-App/t/02pod.t" |
47 | created "My-App/t/03podcoverage.t" |
48 | created "My-App/script/my_app_cgi.pl" |
49 | created "My-App/script/my_app_fastcgi.pl" |
50 | created "My-App/script/my_app_server.pl" |
51 | created "My-App/script/my_app_test.pl" |
52 | created "My-App/script/my_app_create.pl" |
83cea649 |
53 | |
61b1e958 |
54 | This creates the directory structure shown, populated with skeleton |
55 | files. |
83cea649 |
56 | |
57 | |
58 | |
59 | =head2 Testing out the sample application |
60 | |
61 | You can test out your new application by running the server script that |
07e73f82 |
62 | Catalyst provides: |
83cea649 |
63 | |
64 | $ cd My-App |
b33ed88c |
65 | $ script/my_app_server.pl |
66 | |
b460ad78 |
67 | [...] [catalyst] [debug] Debug messages enabled |
b33ed88c |
68 | [...] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher" |
61b1e958 |
69 | [...] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP" |
b33ed88c |
70 | [...] [catalyst] [debug] Found home "/usr/home/jester/foo/My-App/script/.." |
61b1e958 |
71 | [...] [catalyst] [debug] Loaded private actions |
b33ed88c |
72 | .=--------------------------------+------------------------------------=. |
73 | | Private | Class | |
74 | |=--------------------------------+------------------------------------=| |
75 | | /default | My::App | |
76 | '=--------------------------------+------------------------------------=' |
77 | |
78 | [....] [catalyst] [info] My::App powered by Catalyst 5.20 |
79 | You can connect to your server at http://localhost:3000/ |
80 | |
81 | (Note that each line logged by Catalyst begins with a timestamp, which has |
61b1e958 |
82 | been replaced here with "C<...>" so that the text fits onto the lines.) |
b460ad78 |
83 | |
61b1e958 |
84 | The server is now waiting for you to make requests of it. Try using |
85 | telnet to manually make a simple GET request of the server (when |
86 | telnet responds with "Escape character is '^]'.", type "GET / HTTP/1.0" |
87 | and hit return twice): |
83cea649 |
88 | |
89 | $ telnet localhost 3000 |
90 | Trying 127.0.0.1... |
91 | Connected to localhost. |
92 | Escape character is '^]'. |
93 | GET / HTTP/1.0 |
94 | |
95 | HTTP/1.0 200 |
b33ed88c |
96 | Server: Catalyst/5.20 |
83cea649 |
97 | Status: 200 |
b33ed88c |
98 | Date: Fri May 13 14:15:46 EDT 2005 |
99 | X-catalyst: 5.20 |
83cea649 |
100 | Content-length: 40 |
101 | Content-Type: text/html; charset=ISO-8859-1 |
102 | |
103 | Congratulations, My::App is on Catalyst! |
104 | Connection closed by foreign host. |
105 | $ |
106 | |
107 | More trace messages will appear in the original terminal window: |
108 | |
b460ad78 |
109 | [...] [catalyst] [debug] ******************************** |
110 | [...] [catalyst] [debug] * Request 1 (0.027/s) [9818] |
111 | [...] [catalyst] [debug] ******************************** |
61b1e958 |
112 | [...] [catalyst] [debug] "GET" request for "" from localhost |
b460ad78 |
113 | [...] [catalyst] [info] Request took 0.051399s (19.456/s) |
61b1e958 |
114 | .=--------------------------------------------------+----------=. |
115 | | Action | Time | |
116 | |=--------------------------------------------------+----------=| |
117 | | /default | 0.000026s | |
118 | '=--------------------------------------------------+----------=' |
83cea649 |
119 | |
120 | The server will continue running until you interrupt it. |
121 | |
122 | The application can also be tested from the command line using the generated |
b33ed88c |
123 | helper script, C<script/my_app_test.pl>. |
83cea649 |
124 | |
125 | |
126 | =head2 Getting your application invoked |
127 | |
61b1e958 |
128 | Catalyst applications are usually run from mod_perl, but can also be |
129 | run as CGI or FastCGI scripts. Running under mod_perl gives better |
130 | performance, but for development purposes you may want to run your |
131 | application as a CGI script, especially as changes to your application |
132 | code take effect under CGI without having to restart the web server. |
83cea649 |
133 | |
134 | To run from mod_perl you need to add something like this to your Apache |
135 | configuration file: |
136 | |
b460ad78 |
137 | <Location /my-app> |
83cea649 |
138 | SetHandler perl-script |
b460ad78 |
139 | PerlHandler My::App |
83cea649 |
140 | </Location> |
141 | |
142 | To run as a CGI script you need a wrapper script like: |
143 | |
144 | #!/usr/bin/perl -w |
145 | |
146 | use strict; |
b460ad78 |
147 | use lib '/path/to/My/App/lib'; |
148 | use My::App; |
83cea649 |
149 | |
b460ad78 |
150 | My::App->run; |
83cea649 |
151 | |
83cea649 |
152 | |
153 | |
b460ad78 |
154 | =head2 Examining the generated code |
83cea649 |
155 | |
61b1e958 |
156 | The generated application code is quite simple and looks something |
157 | like this: |
83cea649 |
158 | |
159 | package My::App; |
160 | |
161 | use strict; |
162 | use Catalyst qw/-Debug/; |
163 | |
164 | our $VERSION = '0.01'; |
165 | |
166 | My::App->config( |
61b1e958 |
167 | name => 'My::App', |
168 | root => '/home/andrew/My-App/root', |
83cea649 |
169 | ); |
170 | |
61b1e958 |
171 | __PACKAGE__->setup(); |
172 | |
173 | sub default : Private { |
174 | my ( $self, $c ) = @_; |
175 | $c->res->output('Congratulations, My::App is on Catalyst!'); |
176 | } |
83cea649 |
177 | |
178 | 1; |
179 | |
180 | |
61b1e958 |
181 | When the C<Catalyst> module is imported by the application code, |
182 | Catalyst performs the first stage of its initialization. This includes |
183 | loading the appropriate Engine module for the environment in which the |
184 | application is running, loading any plugins and ensuring that the |
185 | calling module (the application module) inherits from C<Catalyst> |
186 | (which makes the Catalyst methods C<config> and C<setup> available to |
187 | the application module). |
b460ad78 |
188 | |
61b1e958 |
189 | The call to C<config> sets up configuration data for the application. |
190 | The C<name> and C<root> items are the minimum required, and specify |
191 | the name of the application and the path to the root directory where |
07e73f82 |
192 | documents, images, and templates can be found. |
b460ad78 |
193 | |
61b1e958 |
194 | Catalyst associates I<actions> with URLs and on receiving a request |
195 | dispatches to the action that matches to request URL. The call to |
196 | C<setup> in the code above registers a default action. With just |
197 | this action registered the application will respond to all requests |
198 | with the same message "Congratulations, My::App is on Catalyst!". |
b460ad78 |
199 | |
61b1e958 |
200 | As you see, the default action is defined as a Private action. |
b160463f |
201 | Most private actions are not directly available from a web url. This |
07e73f82 |
202 | also includes the built-in actions, 'default','begin','end', and |
b160463f |
203 | 'auto', although they will be called as part of some chains. |
204 | The rest can only be reached by using C<forward>. |
b460ad78 |
205 | |
61b1e958 |
206 | The call to the C<setup> method also triggers the second stage of |
207 | Catalyst's initialization process. In this phase Catalyst searches |
208 | for any component modules, locating and registering any actions it |
209 | finds in those modules. |
210 | |
b460ad78 |
211 | Component modules have names prefixed with the application module name, |
eff5f524 |
212 | followed by C<M>, C<V> or C<C> (or the optional long |
213 | forms: C<Model>, C<View> or C<Controller>) followed by the component |
214 | name, for example: |
b460ad78 |
215 | |
eff5f524 |
216 | My::App::C::ShoppingCart # short (default) version |
61b1e958 |
217 | My::App::Controller::ShoppingCart # long version |
b460ad78 |
218 | |
eff5f524 |
219 | My::App::M::User # short (default) version |
220 | My::App::Model::User # long version |
b460ad78 |
221 | |
222 | =head2 Extending the generated code |
223 | |
b460ad78 |
224 | |
83cea649 |
225 | You can start extending the application by adding new actions: |
226 | |
61b1e958 |
227 | sub test1 : Global { |
228 | my ( $self, $c ) = @_; |
229 | $c->res->output('In a new test action #1'); |
230 | } |
231 | sub default : Private { |
232 | my ( $self, $c ) = @_; |
233 | $c->res->output('Congratulations, My::App is on Catalyst!'); |
234 | } |
83cea649 |
235 | |
eff5f524 |
236 | # called like '/article/2005/06' |
237 | sub archive_month : Regex('^article/(\d{4})/(\d{2})$') { |
238 | my ( $self, $c ) = @_; |
239 | |
240 | my $datetime = DateTime->new( |
241 | year => $c->request->snippets->[0], |
242 | month => $c->request->snippets->[1] |
243 | ); |
244 | } |
83cea649 |
245 | |
07e73f82 |
246 | TODO: explain briefly about plugins, actions, and components |
b460ad78 |
247 | |
eff5f524 |
248 | If the action is a Regex type, you can use capturing parentheses to |
249 | extract values within the matching URL (2005, 06 in the above |
250 | example). Those values are available in the $c->req->snippets |
251 | anonymous array. See L<Catalyst::Manual::Intro#Actions> for details. |
b460ad78 |
252 | |
253 | |
254 | =head2 Hooking in to Template Toolkit |
255 | |
61b1e958 |
256 | One of the first things you will probably want to add to your |
257 | application is a templating system for generating your output. |
258 | Catalyst works well with Template Toolkit. If you are unfamiliar with |
259 | Template Toolkit then I suggest you look at L<http://tt2.org>, install |
260 | C<Template>, read the documentation and play around with it, and have |
261 | a look at the I<Badger Book> (I<Template Toolkit> by Darren |
07e73f82 |
262 | Chamberlain, Dave Cross, and Andy Wardley, O'Reilly & Associates, 2004). |
b460ad78 |
263 | |
61b1e958 |
264 | You can create a stub Template Toolkit view component using the create |
265 | script that Catalyst set up as part of the skeleton application: |
b460ad78 |
266 | |
267 | $ script/create.pl view TT TT |
268 | |
1c14b779 |
269 | this generates a view component named C<My::App::V::TT>, which you |
61b1e958 |
270 | might use by forwarding from your C<end> action: |
b460ad78 |
271 | |
272 | # In My::App or My::App::Controller::SomeController |
273 | |
274 | sub end : Private { |
275 | my($self, $c) = @_; |
1c14b779 |
276 | $c->forward('My::App::V::TT'); |
b460ad78 |
277 | } |
278 | |
61b1e958 |
279 | The generated TT view component simply subclasses the |
280 | C<Catalyst::View::TT> class. It looks like this (with the POD |
281 | stripped out): |
b460ad78 |
282 | |
283 | package My::App::V::TT; |
284 | |
285 | use strict; |
286 | use base 'Catalyst::View::TT'; |
287 | |
288 | 1; |
289 | |
61b1e958 |
290 | C<Catalyst::View::TT> initializes a Template Toolkit object with an |
291 | options hash initialized with built-in default settings followed by |
292 | the contents of the hash C<<%{__PACKAGE__->config()}>>. You can |
293 | configure TT more to your needs by adding a C<new> method to the |
294 | generated TT component: |
b460ad78 |
295 | |
296 | sub new { |
61b1e958 |
297 | my $self = shift; |
298 | $self->config->{PRE_PROCESS} = 'config/main'; |
299 | $self->config->{WRAPPER} = 'site/wrapper'; |
300 | return $self->SUPER::new(@_); |
b460ad78 |
301 | } |
302 | |
83cea649 |
303 | |
304 | |
305 | =head1 AUTHOR |
306 | |
307 | Andrew Ford, C<A.Ford@ford-mason.co.uk> |
61b1e958 |
308 | Marcus Ramberg, C<mramberg@cpan.org> |
83cea649 |
309 | |
61b1e958 |
310 | As noted above, this document is at an alpha stage. My plan for this |
311 | document is as follows: |
b460ad78 |
312 | |
313 | =over 4 |
314 | |
315 | =item 1 |
316 | |
07e73f82 |
317 | Expand this document fairly rapidly to cover topics relevant to |
318 | a newcomer to Catalyst, in an order that can be read sequentially |
b460ad78 |
319 | |
320 | =item 2 |
321 | |
07e73f82 |
322 | Incorporate feedback |
b460ad78 |
323 | |
324 | =item 3 |
325 | |
07e73f82 |
326 | Revise the text |
b460ad78 |
327 | |
328 | =back |
329 | |
330 | Placeholders are indicated by the words: TODO or CHECK |
331 | |
332 | Please send comments, corrections and suggestions for improvements to |
333 | A.Ford@ford-mason.co.uk |
334 | |
335 | |
83cea649 |
336 | =head1 COPYRIGHT |
337 | |
61b1e958 |
338 | This program is free software, you can redistribute it and/or modify |
339 | it under the same terms as Perl itself. |