1Catalyst::DispatchType:U:sCehraiCnoendt(r3i)buted Perl DCoactuamleynstta:t:iDoinspatchType::Chained(3)
2
3
4

NAME

6       Catalyst::DispatchType::Chained - Path Part DispatchType
7

SYNOPSIS

9         #   root action - captures one argument after it
10         sub foo_setup : Chained('/') PathPart('foo') CaptureArgs(1) {
11             my ( $self, $c, $foo_arg ) = @_;
12             ...
13         }
14
15         #   child action endpoint - takes one argument
16         sub bar : Chained('foo_setup') Args(1) {
17             my ( $self, $c, $bar_arg ) = @_;
18             ...
19         }
20

DESCRIPTION

22       See "USAGE".
23

METHODS

25       $self->list($c)
26
27       Debug output for Path Part dispatch points
28
29       $self->match( $c, $path )
30
31       Calls "recurse_match" to see if a chain matches the $path.
32
33       $self->recurse_match( $c, $parent, \@path_parts )
34
35       Recursive search for a matching chain.
36
37       $self->register( $c, $action )
38
39       Calls register_path for every Path attribute for the given $action.
40
41       $self->uri_for_action($action, $captures)
42
43       Get the URI part for the action, using $captures to fill the capturing
44       parts.
45

USAGE

47       Introduction
48
49       The "Chained" attribute allows you to chain public path parts together
50       by their private names. A chain part's path can be specified with
51       "PathPart" and can be declared to expect an arbitrary number of argu‐
52       ments. The endpoint of the chain specifies how many arguments it gets
53       through the "Args" attribute. :Args(0) would be none at all, ":Args"
54       without an integer would be unlimited. The path parts that aren't end‐
55       points are using "CaptureArgs" to specify how many parameters they
56       expect to receive. As an example setup:
57
58         package MyApp::Controller::Greeting;
59         use base qw/ Catalyst::Controller /;
60
61         #   this is the beginning of our chain
62         sub hello : PathPart('hello') Chained('/') CaptureArgs(1) {
63             my ( $self, $c, $integer ) = @_;
64             $c->stash->{ message } = "Hello ";
65             $c->stash->{ arg_sum } = $integer;
66         }
67
68         #   this is our endpoint, because it has no :CaptureArgs
69         sub world : PathPart('world') Chained('hello') Args(1) {
70             my ( $self, $c, $integer ) = @_;
71             $c->stash->{ message } .= "World!";
72             $c->stash->{ arg_sum } += $integer;
73
74             $c->response->body( join "<br/>\n" =>
75                 $c->stash->{ message }, $c->stash->{ arg_sum } );
76         }
77
78       The debug output provides a separate table for chained actions, showing
79       the whole chain as it would match and the actions it contains. Here's
80       an example of the startup output with our actions above:
81
82         ...
83         [debug] Loaded Path Part actions:
84         .-----------------------+------------------------------.
85         ⎪ Path Spec             ⎪ Private                      ⎪
86         +-----------------------+------------------------------+
87         ⎪ /hello/*/world/*      ⎪ /greeting/hello (1)          ⎪
88         ⎪                       ⎪ => /greeting/world           ⎪
89         '-----------------------+------------------------------'
90         ...
91
92       As you can see, Catalyst only deals with chains as whole paths and
93       builds one for each endpoint, which are the actions with ":Chained" but
94       without ":CaptureArgs".
95
96       Let's assume this application gets a request at the path
97       "/hello/23/world/12". What happens then? First, Catalyst will dispatch
98       to the "hello" action and pass the value 23 as an argument to it after
99       the context. It does so because we have previously used :CaptureArgs(1)
100       to declare that it has one path part after itself as its argument. We
101       told Catalyst that this is the beginning of the chain by specifying
102       ":Chained('/')". Also note that instead of saying ":PathPart('hello')"
103       we could also just have said ":PathPart", as it defaults to the name of
104       the action.
105
106       After "hello" has run, Catalyst goes on to dispatch to the "world"
107       action. This is the last action to be called: Catalyst knows this is an
108       endpoint because we did not specify a ":CaptureArgs" attribute. Never‐
109       theless we specify that this action expects an argument, but at this
110       point we're using :Args(1) to do that. We could also have said ":Args"
111       or left it out altogether, which would mean this action would get all
112       arguments that are there. This action's ":Chained" attribute says
113       "hello" and tells Catalyst that the "hello" action in the current con‐
114       troller is its parent.
115
116       With this we have built a chain consisting of two public path parts.
117       "hello" captures one part of the path as its argument, and also speci‐
118       fies the path root as its parent. So this part is "/hello/$arg". The
119       next part is the endpoint "world", expecting one argument. It sums up
120       to the path part "world/$arg". This leads to a complete chain of
121       "/hello/$arg/world/$arg" which is matched against the requested paths.
122
123       This example application would, if run and called by e.g.
124       "/hello/23/world/12", set the stash value "message" to "Hello" and the
125       value "arg_sum" to "23". The "world" action would then append "World!"
126       to "message" and add 12 to the stash's "arg_sum" value.  For the sake
127       of simplicity no view is shown. Instead we just put the values of the
128       stash into our body. So the output would look like:
129
130         Hello World!
131         35
132
133       And our test server would have given us this debugging output for the
134       request:
135
136         ...
137         [debug] "GET" request for "hello/23/world/12" from "127.0.0.1"
138         [debug] Path is "/greeting/world"
139         [debug] Arguments are "12"
140         [info] Request took 0.164113s (6.093/s)
141         .------------------------------------------+-----------.
142         ⎪ Action                                   ⎪ Time      ⎪
143         +------------------------------------------+-----------+
144         ⎪ /greeting/hello                          ⎪ 0.000029s ⎪
145         ⎪ /greeting/world                          ⎪ 0.000024s ⎪
146         '------------------------------------------+-----------'
147         ...
148
149       What would be common uses of this dispatch technique? It gives the pos‐
150       sibility to split up logic that contains steps that each depend on each
151       other. An example would be, for example, a wiki path like "/wiki/Foo‐
152       BarPage/rev/23/view". This chain can be easily built with these
153       actions:
154
155         sub wiki : PathPart('wiki') Chained('/') CaptureArgs(1) {
156             my ( $self, $c, $page_name ) = @_;
157             #  load the page named $page_name and put the object
158             #  into the stash
159         }
160
161         sub rev : PathPart('rev') Chained('wiki') CaptureArgs(1) {
162             my ( $self, $c, $revision_id ) = @_;
163             #  use the page object in the stash to get at its
164             #  revision with number $revision_id
165         }
166
167         sub view : PathPart Chained('rev') Args(0) {
168             my ( $self, $c ) = @_;
169             #  display the revision in our stash. Another option
170             #  would be to forward a compatible object to the action
171             #  that displays the default wiki pages, unless we want
172             #  a different interface here, for example restore
173             #  functionality.
174         }
175
176       It would now be possible to add other endpoints, for example "restore"
177       to restore this specific revision as the current state.
178
179       You don't have to put all the chained actions in one controller. The
180       specification of the parent through ":Chained" also takes an absolute
181       action path as its argument. Just specify it with a leading "/".
182
183       If you want, for example, to have actions for the public paths
184       "/foo/12/edit" and "/foo/12", just specify two actions with ":Path‐
185       Part('foo')" and ":Chained('/')". The handler for the former path needs
186       a :CaptureArgs(1) attribute and a endpoint with ":PathPart('edit')" and
187       ":Chained('foo')". For the latter path give the action just a :Args(1)
188       to mark it as endpoint. This sums up to this debugging output:
189
190         ...
191         [debug] Loaded Path Part actions:
192         .-----------------------+------------------------------.
193         ⎪ Path Spec             ⎪ Private                      ⎪
194         +-----------------------+------------------------------+
195         ⎪ /foo/*                ⎪ /controller/foo_view         ⎪
196         ⎪ /foo/*/edit           ⎪ /controller/foo_load (1)     ⎪
197         ⎪                       ⎪ => /controller/edit          ⎪
198         '-----------------------+------------------------------'
199         ...
200
201       Here's a more detailed specification of the attributes belonging to
202       ":Chained":
203
204       Attributes
205
206       PathPart
207               Sets the name of this part of the chain. If it is specified
208               without arguments, it takes the name of the action as default.
209               So basically "sub foo :PathPart" and "sub foo :PathPart('foo')"
210               are identical.  This can also contain slashes to bind to a
211               deeper level. An action with "sub bar :PathPart('foo/bar')
212               :Chained('/')" would bind to "/foo/bar/...". If you don't spec‐
213               ify ":PathPart" it has the same effect as using ":PathPart", it
214               would default to the action name.
215
216       Chained Has to be specified for every child in the chain. Possible val‐
217               ues are absolute and relative private action paths, with the
218               relatives pointing to the current controller, or a single slash
219               "/" to tell Catalyst that this is the root of a chain. The
220               attribute ":Chained" without arguments also defaults to the "/"
221               behavior.
222
223               Because you can specify an absolute path to the parent action,
224               it doesn't matter to Catalyst where that parent is located. So,
225               if your design requests it, you can redispatch a chain through
226               any controller or namespace you want.
227
228               Another interesting possibility gives ":Chained('.')", which
229               chains itself to an action with the path of the current con‐
230               troller's namespace.  For example:
231
232                 #   in MyApp::Controller::Foo
233                 sub bar : Chained CaptureArgs(1) { ... }
234
235                 #   in MyApp::Controller::Foo::Bar
236                 sub baz : Chained('.') Args(1) { ... }
237
238               This builds up a chain like "/bar/*/baz/*". The specification
239               of "."  as the argument to Chained here chains the "baz" action
240               to an action with the path of the current controller namespace,
241               namely "/foo/bar". That action chains directly to "/", so the
242               "/bar/*/baz/*" chain comes out as the end product.
243
244       CaptureArgs
245               Must be specified for every part of the chain that is not an
246               endpoint. With this attribute Catalyst knows how many of the
247               following parts of the path (separated by "/") this action
248               wants to capture as its arguments. If it doesn't expect any,
249               just specify :CaptureArgs(0).  The captures get passed to the
250               action's @_ right after the context, but you can also find them
251               as array references in "$c->request->captures->[$level]". The
252               $level is the level of the action in the chain that captured
253               the parts of the path.
254
255               An action that is part of a chain (that is, one that has a
256               ":Chained" attribute) but has no ":CaptureArgs" attribute is
257               treated by Catalyst as a chain end.
258
259       Args    By default, endpoints receive the rest of the arguments in the
260               path. You can tell Catalyst through ":Args" explicitly how many
261               arguments your endpoint expects, just like you can with ":Cap‐
262               tureArgs". Note that this also affects whether this chain is
263               invoked on a request. A chain with an endpoint specifying one
264               argument will only match if exactly one argument exists in the
265               path.
266
267               You can specify an exact number of arguments like :Args(3),
268               including 0. If you just say ":Args" without any arguments, it
269               is the same as leaving it out altogether: The chain is matched
270               regardless of the number of path parts after the endpoint.
271
272               Just as with ":CaptureArgs", the arguments get passed to the
273               action in @_ after the context object. They can also be reached
274               through "$c->request->arguments".
275
276       Auto actions, dispatching and forwarding
277
278       Note that the list of "auto" actions called depends on the private path
279       of the endpoint of the chain, not on the chained actions way. The
280       "auto" actions will be run before the chain dispatching begins. In
281       every other aspect, "auto" actions behave as documented.
282
283       The "forward"ing to other actions does just what you would expect. But
284       if you "detach" out of a chain, the rest of the chain will not get
285       called after the "detach".
286

AUTHOR

288       Matt S Trout <mst@shadowcatsystems.co.uk>
289
291       This program is free software, you can redistribute it and/or modify it
292       under the same terms as Perl itself.
293
294
295
296perl v5.8.8                       2007-09-20Catalyst::DispatchType::Chained(3)
Impressum