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