Commit | Line | Data |
d3394885 |
1 | =head1 NAME |
2 | |
3 | Catalyst::Manual::WritingPlugins - An introduction to writing plugins |
4 | with L<NEXT>. |
5 | |
6 | =head1 DESCRIPTION |
7 | |
8 | Writing an integrated plugin for L<Catalyst> using L<NEXT>. |
9 | |
10 | =head1 WHY PLUGINS? |
11 | |
12 | A Catalyst plugin is an integrated part of your application. By writing |
13 | plugins you can, for example, perform processing actions automatically, |
14 | instead of having to C<forward> to a processing method every time you |
15 | need it. |
16 | |
17 | =head1 WHAT'S NEXT? |
18 | |
19 | L<NEXT> is used to re-dispatch a method call as if the calling method |
20 | doesn't exist at all. In other words: If the class you're inheriting |
21 | from defines a method, and you're overloading that method in your own |
22 | class, NEXT gives you the possibility to call that overloaded method. |
23 | |
24 | This technique is the usual way to plug a module into Catalyst. |
25 | |
26 | =head1 INTEGRATING YOUR PLUGIN |
27 | |
26e73131 |
28 | You can use L<NEXT> for your plugin by overloading certain methods which |
d3394885 |
29 | are called by Catalyst during a request. |
30 | |
31 | =head2 The request life-cycle |
32 | |
33 | Catalyst creates a context object (C<$context> or, more usually, its |
34 | alias C<$c>) on every request, which is passed to all the handlers that |
35 | are called from preparation to finalization. |
36 | |
37 | For a complete list of the methods called during a request, see |
38 | L<Catalyst::Manual::Internals>. The request can be split up in three |
39 | main stages: |
40 | |
41 | =over 4 |
42 | |
43 | =item preparation |
44 | |
45 | When the C<prepare> handler is called, it initializes the request |
46 | object, connections, headers, and everything else that needs to be |
47 | prepared. C<prepare> itself calls other methods to delegate these tasks. |
48 | After this method has run, everything concerning the request is in |
49 | place. |
50 | |
51 | =item dispatch |
52 | |
53 | The dispatching phase is where the black magic happens. The C<dispatch> |
54 | handler decides which actions have to be called for this request. |
55 | |
56 | =item finalization |
57 | |
58 | Catalyst uses the C<finalize> method to prepare the response to give to |
59 | the client. It makes decisions according to your C<response> (e.g. where |
60 | you want to redirect the user to). After this method, the response is |
61 | ready and waiting for you to do something with it--usually, hand it off |
62 | to your View class. |
63 | |
64 | =back |
65 | |
66 | =head2 What Plugins look like |
67 | |
68 | There's nothing special about a plugin except its name. A module named |
69 | C<Catalyst::Plugin::MyPlugin> will be loaded by Catalyst if you specify it |
70 | in your application class, e.g.: |
71 | |
72 | # your plugin |
73 | package Catalyst::Plugin::MyPlugin; |
74 | use warnings; |
75 | use strict; |
76 | ... |
77 | |
78 | # MyApp.pm, your application class |
79 | use Catalyst qw/-Debug MyPlugin/; |
80 | |
81 | This does nothing but load your module. We'll now see how to overload stages of the request cycle, and provide accessors. |
82 | |
83 | =head2 Calling methods from your Plugin |
84 | |
85 | Methods that do not overload a handler are available directly in the |
86 | C<$c> context object; they don't need to be qualified with namespaces, |
87 | and you don't need to C<use> them. |
88 | |
89 | package Catalyst::Plugin::Foobar; |
90 | use strict; |
91 | sub foo { return 'bar'; } |
92 | |
93 | # anywhere else in your Catalyst application: |
94 | |
95 | $c->foo(); # will return 'bar' |
96 | |
97 | That's it. |
98 | |
99 | =head2 Overloading - Plugging into Catalyst |
100 | |
101 | If you don't just want to provide methods, but want to actually plug |
102 | your module into the request cycle, you have to overload the handler |
103 | that suits your needs. |
104 | |
105 | Every handler gets the context object passed as its first argument. Pass |
106 | the rest of the arguments to the next handler in row by calling it via |
107 | |
108 | $c->NEXT::handler-name( @_ ); |
109 | |
110 | if you already C<shift>ed it out of C<@_>. Remember to C<use> C<NEXT>. |
b248fa4a |
111 | |
d3394885 |
112 | =head2 Storage and Configuration |
113 | |
114 | Some Plugins use their accessor names as a storage point, e.g. |
115 | |
116 | sub my_accessor { |
117 | my $c = shift; |
118 | $c->{my_accessor} = .. |
119 | |
120 | but it is more safe and clear to put your data in your configuration |
121 | hash: |
122 | |
123 | $c->config->{my_plugin}{ name } = $value; |
124 | |
125 | If you need to maintain data for more than one request, you should |
126 | store it in a session. |
127 | |
128 | =head1 EXAMPLE |
129 | |
130 | Here's a simple example Plugin that shows how to overload C<prepare> |
131 | to add a unique ID to every request: |
132 | |
133 | package Catalyst::Plugin::RequestUUID; |
b248fa4a |
134 | |
d3394885 |
135 | use warnings; |
136 | use strict; |
b248fa4a |
137 | |
d6d6087c |
138 | use Catalyst::Request; |
d3394885 |
139 | use Data::UUID; |
d6d6087c |
140 | use NEXT; |
141 | |
d3394885 |
142 | our $VERSION = 0.01; |
b248fa4a |
143 | |
d6d6087c |
144 | { # create a uuid accessor |
145 | package Catalyst::Request; |
146 | __PACKAGE__->mk_accessors('uuid'); |
147 | } |
d3394885 |
148 | |
149 | sub prepare { |
d6d6087c |
150 | my $class = shift; |
b248fa4a |
151 | |
9b80ae2c |
152 | # Turns the engine-specific request into a Catalyst context . |
d6d6087c |
153 | my $c = $class->NEXT::prepare( @_ ); |
d3394885 |
154 | |
d6d6087c |
155 | $c->request->uuid( Data::UUID->new->create_str ); |
156 | $c->log->debug( 'Request UUID "'. $c->request->uuid .'"' ); |
d3394885 |
157 | |
158 | return $c; |
159 | } |
160 | |
161 | 1; |
162 | |
163 | Let's just break it down into pieces: |
164 | |
165 | package Catalyst::Plugin::RequestUUID; |
166 | |
167 | The package name has to start with C<Catalyst::Plugin::> to make sure you |
168 | can load your plugin by simply specifying |
169 | |
170 | use Catalyst qw/RequestUUID/; |
171 | |
172 | in the application class. L<warnings> and L<strict> are recommended for |
173 | all Perl applications. |
174 | |
175 | use NEXT; |
176 | use Data::UUID; |
177 | our $VERSION = 0.01; |
178 | |
179 | NEXT must be explicitly C<use>d. L<Data::UUID> generates our unique |
180 | ID. The C<$VERSION> gets set because it's a) a good habit and b) |
181 | L<ExtUtils::ModuleMaker> likes it. |
182 | |
183 | sub prepare { |
184 | |
185 | These methods are called without attributes (Private, Local, etc.). |
186 | |
187 | my $c = shift; |
188 | |
189 | We get the context object for this request as the first argument. |
190 | |
191 | B<Hint!>:Be sure you shift the context object out of C<@_> in this. If |
192 | you just do a |
193 | |
194 | my ( $c ) = @_; |
195 | |
196 | it remains there, and you may run into problems if you're not aware of |
197 | what you pass to the handler you've overloaded. If you take a look at |
198 | |
199 | $c = $c->NEXT::prepare( @_ ); |
200 | |
201 | you see you would pass the context twice here if you don't shift it out |
202 | of your parameter list. |
203 | |
204 | This line is the main part of the plugin procedure. We call the |
205 | overloaded C<prepare> method and pass along the parameters we got. We |
206 | also overwrite the context object C<$c> with the one returned by the |
207 | called method returns. We'll return our modified context object at the |
208 | end. |
209 | |
210 | Note that that if we modify C<$c> before this line, we also modify it |
211 | before the original (overloaded) C<prepare> is run. If we modify it |
212 | after, we modify an already prepared context. And, of course, it's no |
213 | problem to do both, if you need to. Another example of working on the |
214 | context before calling the actual handler would be setting header |
215 | information before C<finalize> does its job. |
216 | |
217 | $c->req->{req_uuid} = Data::UUID->new->create_str; |
218 | |
219 | This line creates a new L<Data::UUID> object and calls the C<create_str> |
220 | method. The value is saved in our request, under the key C<req_uuid>. We |
221 | can use that to access it in future in our application. |
222 | |
223 | $c->log->debug( 'Request UUID "'. $c->req->{req_uuid} .'"' ); |
224 | |
225 | This sends our UUID to the C<debug> log. |
226 | |
227 | The final line |
228 | |
229 | return $c; |
230 | |
231 | passes our modified context object back to whoever has called us. This |
232 | could be Catalyst itself, or the overloaded handler of another plugin. |
233 | |
234 | =head1 SEE ALSO |
235 | |
236 | L<Catalyst>, L<NEXT>, L<ExtUtils::ModuleMaker>, L<Catalyst::Manual::Plugins>, |
237 | L<Catalyst::Manual::Internals>. |
238 | |
239 | =head1 THANKS TO |
240 | |
241 | Sebastian Riedel and his team of Catalyst developers as well as all the |
242 | helpful people in #catalyst. |
243 | |
244 | =head1 COPYRIGHT |
245 | |
246 | This program is free software, you can redistribute it and/or modify it |
247 | under the same terms as Perl itself. |
248 | |
249 | =head1 AUTHOR |
250 | |
251 | S<Robert Sedlacek, C<phaylon@dunkelheit.at>> with a lot of help from the |
26e73131 |
252 | people on #catalyst. |
d3394885 |
253 | |
254 | =cut |