3 Catalyst::Manual::ExtendingCatalyst - Extending The Framework
7 This document will provide you with access points, techniques and best
8 practices to extend the framework itself or to find more elegant ways
9 to abstract and use your own code.
11 The L<Catalyst> core developer community tries to build and evolve the
12 framework in a design that won't get in your way. There are many entry
13 points to alter or extend the behaviour of the framework and the
14 applications built upon it, and it can be confusing at first to decide
15 on a place to start. This document is written to help you orient
16 yourself in the possibilities, current practices and their consequences.
18 Please read the L<BEST PRACTICES> section before deciding on a design,
19 especially if you plan to release your code to the CPAN. The Catalyst
20 developer and user communities, which you naturally also belong to, will
21 benefit most if we all work together and coordinate.
23 If you are unsure on an implementation or have an idea you would like to
24 have RfC'ed, it surely is a good idea to send your questions and
25 suggestions to the Catalyst mailing list (See L<Catalyst/SUPPORT>) or
26 come to the C<#catalyst> channel on the C<irc.perl.org> network. You
27 might also want to refer to those places for research if a module doing
28 what you're trying to implement already exists. This might give you
29 either a solution to your problem or a already built base, which gives
30 you at least a head start.
34 During Catalyst's early days, it was common to write plugins to provide
35 functionality application wide. Since then, Catalyst grew a lot more
36 flexible and powerful. It soon became a best practice to use some other
37 form of abstraction or interface, to keep the scope of its influence as
38 close as possible to where it belongs.
40 For those in a hurry, here's a quick checklist of some fundamental
41 points. If you are going to read the whole thing anyway, you can jump
42 forward to L</Namespaces>.
44 =head2 Quick Checklist
48 =item Use the C<CatalystX::*> namespace if you can!
50 Excluding plugins and of course your C<MyApp> code. B<Mind the X!>
52 =item Don't make it a plugin unless you have to!
54 A plugin should be careful as it declares in global namespace.
56 =item There's a community. Use it!
58 There are many experienced developers in the Catalyst community, there's
59 always the IRC channel and the mailing list to discuss things.
61 =item Add tests and documentation!
63 This gives a stable base for contribution, and even more important,
64 trust. The easiest way is a test application. See
65 L<Catalyst::Manual::Tutorial::Testing> for more information.
71 While some core extensions (engines, plugins, etc.) have to be placed in
72 the C<Catalyst::*> namespace, the Catalyst core would like to ask
73 developers to use the C<CatalystX::*> namespace if possible.
75 When you try to put a base class for a C<Model>, C<View> or C<Controller>
76 directly under your C<MyApp> directory as, for example,
77 C<MyApp::Controller::Foo>, you will have the problem that Catalyst will
78 try to load that base class as a component of your application. The
79 solution is simple: Use another namespace. Common ones are
80 C<MyApp::Base::Controller::*> or C<MyApp::ControllerBase::*> as examples.
82 =head2 Can it be a simple module?
84 Sometimes you want to use functionality in your application that doesn't
85 require the framework at all. Remember that Catalyst is just Perl and you
86 always can just C<use> a module. If you have application specific code
87 that doesn't need the framework, there is no problem in putting it in
88 your C<MyApp::*> namespace. Just don't put it in C<Model>, C<Controller>
89 or C<View>, because that would make Catalyst try to load them as
92 =head2 Inheritance and overriding methods
94 While Catalyst itself is still based on L<NEXT>, extension developers
95 are encouraged to use L<Class::C3>, which is what Catalyst will be
96 switching to in some point in the future.
98 When overriding a method, keep in mind that some day additionally
99 arguments may be provided to the method, if the last parameter is not
100 a flat list. It is thus better to override a method by shifting the
101 invocant off of C<@_> and assign the rest of the used arguments, so
102 you can pass your complete arguments to the original method via C<@_>:
109 my ($bar, $baz) = @_;
111 return $self->next::method(@_);
114 If you would do the common
116 my ($self, $foo, $bar) = @_;
118 you'd have to use a much uglier construct to ensure that all arguments
119 will be passed along and the method is future proof:
121 $self->next::method(@_[ 1 .. $#_ ]);
123 =head2 Tests and documentation
125 When you release your module to the CPAN, proper documentation and at
126 least a basic test suite (which means more than pod or even just
127 C<use_ok>, sorry) gives people a good base to contribute to the module.
128 It also shows that you care for your users. If you would like your
129 module to become a recommended addition, these things will prove
134 In planning to release a module to a broad community like those of
135 Catalyst or CPAN and Perl themselves, you should include beforehand if
136 you can spare the resources to keep it up to date, fix bugs and include
139 If you're not sure about this, you can always ask in the proper Catalyst
140 or Perl channels if someone else might be interested in the project, and
141 would jump in as co-maintainer.
143 A public repository can further ease interaction with the community. Even
144 read only access enables people to provide you with patches to your
145 current development version. subversion, SVN and SVK, are broadly
146 preferred in the Catalyst community.
148 If you're developing a Catalyst extension, please consider asking the
149 core team for space in Catalyst's own subversion repository. You can get
150 in touch about this via IRC or the Catalyst developers mailing list.
152 =head2 The context object
154 Sometimes you want to get a hold of the context object in a component
155 that was created on startup time, where no context existed yet. Often
156 this is about the model reading something out of the stash or other
157 context information (current language, for example).
159 First it should be said that, if you use the context object in your
160 component and therefor tie it to an existing request, you might get into
161 problems when you try to use the component (e.g. the model, which would
162 be the most common case) outside of Catalyst, for example in cronjobs.
164 A stable solution to this problem is to design the Catalyst model
165 separately from the underlying model logic. Let's take
166 L<Catalyst::Model::DBIC::Schema> as an example. You can create a
167 schema outside of Catalyst that knows nothing about the web. This kind
168 of design ensures encapsulation and makes development and maintenance
169 a whole lot easier. The you use the aforementioned model to tie your
170 schema to your application. This gives you a C<MyApp::DBIC> (the
171 name is of course just an example) model as well as
172 C<MyApp::DBIC::$ResultSource> models to access your result sources
175 By creating such a thin layer between the actual model and the Catalyst
176 application the schema itself is not at all tied to any application, and
177 the layer in-between can access the model's API using information from
180 So the only question remaining is, how does a Catalyst component access
181 the context object at request time? The solution to this problem is
182 L<Catalyst::Component/"ACCEPT_CONTEXT($c, @args)">.
186 The application and/or its developer have to interact with the extension
187 by configuring them. There is of course again more than one way to do it.
191 You can specify any valid Perl attribute on Catalyst actions you like.
192 (See L<attributes/"Syntax of Attribute Lists"> for a description of what
193 is valid.) They will be available on the C<Catalyst::Action> instance via
194 its C<attributes> accessor. To give an example, this action
196 sub foo : Local Bar('Baz') {
198 my $attributes = $self->action_for('foo')->attributes;
199 $c->res->body( $attributes->{Bar}[0] );
202 will set the response body to C<Baz>. The values always come in an array
203 reference. As you can see, you can use attributes to configure your
204 actions. You can specify or alter these attributes via
205 L</"Component Configuration">, or even react on them as soon as Catalyst
206 encounters them by providing your own
207 L<component base class|/"Component Base Classes">.
209 =head2 Creating custom accessors
211 L<Catalyst::Component> uses L<Class::Accessor::Fast> for accessor
212 creation. Please refer to the modules documentation for usage
215 =head2 Component configuration
217 On creation time, the class configuration of your component (the one
218 available via C<$self-E<gt>config>) will be merged with possible
219 configuration settings from the applications configuration (either
220 directly or via config file) and stored in the controller object's
221 hash reference. So, if you read possible configurations like
223 my $model_name = $controller->{model_name};
225 you will get the right value. The C<config> accessor always only
226 contains the original class configuration and must not be used for
227 component configuration.
229 You are advised to create accessors on your component class for your
230 configuration values. This is good practice and makes it easier to
231 capture configuration key typos. You can do this with the
232 C<mk_ro_accessors> method provided to L<Catalyst::Component> via
233 L<Class::Accessor::Fast>:
235 use base 'Catalyst::Controller';
236 __PACKAGE__->mk_ro_accessors('model_name');
238 my $model_name = $controller->model_name;
240 =head1 IMPLEMENTATION
242 This part contains the technical details of various implementation
243 methods. Please read the L</"BEST PRACTICES"> before you start your
244 implementation, if you haven't already.
246 =head2 Action classes
248 Usually, your action objects are of the class L<Catalyst::Action>.
249 You can override this with the C<ActionClass> attribute to influence
250 execution and/or dispatching of the action. A popular example is
251 L<Catalyst::Action::RenderView>, which is used in every newly created
252 Catalyst application in your root controller:
254 sub end : ActionClass('RenderView') { }
256 Usually, you want to override either the C<execute> or the C<match>
257 method, or both. The execute method of the action will naturally
258 call the methods code. You can surround this by overriding the method
261 package Catalyst::Action::MyFoo;
265 use base 'Catalyst::Action';
269 my ($controller, $c, @args) = @_;
271 # put your 'before' code here
272 my $r = $self->next::method(@_);
273 # put your 'after' code here
280 We use L<Class::C3> to re-dispatch to the original C<execute> method in
281 the L<Catalyst::Action> class.
283 When a request comes in, Catalyst's dispatcher searches, depending on
284 the dispatch type, the target action or chain to invoke. From time to
285 time it asks the actions themselves, or through the controller, if they
286 would match the current request. That's what the C<match> method does.
287 So with overriding this, you can change on what the action will match
288 and add new matching criteria.
290 To give a totally bogus example, this action class will make the action
291 only match on Mondays:
293 package Catalyst::Action::OnlyMondays;
297 use base 'Catalyst::Action';
301 return 0 if ( localtime(time) )[6] == 1;
302 return $self->next::method(@_);
307 And this is how we'd use it:
309 sub foo: Local ActionClass('OnlyMondays') {
311 $c->res->body('I feel motivated!');
314 If you are using action classes often or have some specific base classes
315 that you want to specify more conveniently, you can implement a component
316 base class providing an attribute handler.
318 For further information on action classes, please refer to
319 L<Catalyst::Action> and L<Catalyst::Manual::Actions>.
321 =head2 Component base classes
323 Many plugins that were written should really have been just controller
324 base classes. With such a class, you could provide functionality scoped
325 to a single controller, not polluting the global namespace in the context
328 You can provide regular Perl methods in a base class as well as actions
329 which will be inherited to the subclass. Please refer to L</Controllers>
330 for an example of this.
332 You can introduce your own attributes by specifying a handler method in
333 the controller base. For example, to use a C<FullClass> attribute to
334 specify a fully qualified action class name, you could use the following
335 implementation. Note, however, that this functionality is already
336 provided via the C<+> prefix for action classes. A simple
338 sub foo : Local ActionClass('+MyApp::Action::Bar') { ... }
340 will use C<MyApp::Action::Bar> as action class.
342 package MyApp::Base::Controller::FullClass;
344 use base 'Catalyst::Controller';
346 sub _parse_FullClass_attr {
347 my ($self, $app_class, $action_name, $value, $attrs) = @_;
348 return( ActionClass => $value );
353 Note that the full line of arguments is only provided for completeness
354 sake. We could use this attribute in a subclass like any other Catalyst
357 package MyApp::Controller::Foo;
359 use base 'MyApp::Base::Controller::FullClass';
361 sub foo : Local FullClass('MyApp::Action::Bar') { ... }
367 Many things can happen in controllers, and it often improves
368 maintainability to abstract some of the code out into reusable base
371 You can provide usual Perl methods that will be available via your
372 controller object, or you can even define Catalyst actions which will be
373 inherited by the subclasses. Consider this controller base class:
375 package MyApp::Base::Controller::ModelBase;
377 use base 'Catalyst::Controller';
379 sub list : Chained('base') PathPart('') Args(0) {
381 my $model = $c->model( $self->{model_name} );
382 my $condition = $self->{model_search_condition} || {};
383 my $attrs = $self->{model_search_attrs} || {};
384 $c->stash(rs => $model->search($condition, $attrs);
387 sub load : Chained('base') PathPart('') CaptureArgs(1) {
388 my ($self, $c, $id) = @_;
389 my $model = $c->model( $self->{model_name} );
390 $c->stash(row => $model->find($id));
395 This example implements two simple actions. The C<list> action chains to
396 a (currently non-existent) C<base> action and puts a result-set into the
397 stash taking a configured C<model_name> as well as a search condition and
398 attributes. This action is a L<chained|Catalyst::DispatchType::Chained>
399 endpoint. The other action, called C<load> is a chain midpoint that takes
400 one argument. It takes the value as an ID and loads the row from the
401 configured model. Please not that the above code is simplified for
402 clarity. It misses error handling, input validation, and probably some
405 The class above is not very useful by its own, but we can combine it with
406 some custom actions by sub-classing it:
408 package MyApp::Controller::Foo;
410 use base 'MyApp::Base::Controller::ModelBase';
413 model_name => 'DB::Foo',
414 model_search_condition => { is_active => 1 },
415 model_search_attrs => { order_by => 'name' },
418 sub base : Chained PathPart('foo') CaptureArgs(0) { }
420 sub view : Chained('load') Args(0) {
422 my $row = $c->stash->{row};
423 $c->res->body(join ': ', $row->name, $row->description);
428 This class uses the formerly created controller as a base class. First,
429 we see the configurations that were used in the parent class. Next comes
430 the C<base> action, where everything chains off of.
432 Note that inherited actions act like they were declared in your
433 controller itself. You can therefor call them just by their name in
434 C<forward>s, C<detaches> and C<Chained(..)> specifications. This is an
435 important part of what makes this technique so useful.
437 The new C<view> action ties itself to the C<load> action specified in the
438 base class and outputs the loaded row's C<name> and C<description>
439 columns. The controller C<MyApp::Controller::Foo> now has these publicly
446 Will call the controller's C<base>, then the base classes C<list> action.
450 First, the controller's C<base> will be called, then it will C<load> the
451 row with the corresponding C<$id>. After that, C<view> will display some
452 fields out of the object.
456 =head2 Models and Views
458 If the functionality you'd like to add is really a data-set you want to
459 manipulate, for example internal document types, images, files, it might
460 be better suited as a model.
462 Same goes for views. If your code handles representation or deals with
463 the applications interface and should be universally available, it could
464 be a perfect candidate for a view.
466 Please implement a C<process> method in your views. This method will be
467 called by Catalyst if it is asked to forward to a component without a
468 specified action. Note that C<process> is B<not a Catalyst action> but
469 a simple Perl method.
471 You are also encouraged to implement a C<render> method corresponding
472 with the one in L<Catalyst::View::TT>. This has proven invaluable,
473 because people can use your view for much more fine-grained content
476 Here is some example code for a fictional view:
478 package CatalystX::View::MyView;
480 use base 'Catalyst::View';
485 my $template = $c->stash->{template};
486 my $content = $self->render($c, $template, $c->stash);
487 $c->res->body( $content );
491 my ($self, $c, $template, $args) = @_;
494 # prepare content here
504 The first thing to say about plugins is that if you're not sure if your
505 module should be a plugin, it probably shouldn't. It once was common to
506 add features to Catalyst by writing plugins that provide accessors to
507 said functionality. As Catalyst grew more popular, it became obvious that
508 this qualifies as bad practice.
510 By designing your module as a Catalyst plugin, every method you implement,
511 import or inherit will be available via your applications context object.
512 Said more harshly, you're polluting global namespace, and you should be
513 only doing that when you really need.
515 Often, developers design extensions as plugins because they need to get
516 hold of the context object. Either to get at the stash or
517 request/response objects are the widely spread reasons. It is, however,
518 perfectly possible to implement a regular Catalyst component (read:
519 model, view or controller) that receives the current context object via
520 L<Catalyst::Component/"ACCEPT_CONTEXT($c, @args)">.
522 So when is a plugin suited to your task? Your code needs to be a plugin
523 to act upon or alter specific parts of Catalyst's request lifecycle. If
524 your functionality needs to wrap some C<prepare_*> or C<finalize_*>
525 stages, you won't get around a plugin.
527 Another valid target for a plugin architecture are things that B<really>
528 have to be globally available, like sessions or authentication.
530 B<Please do not> release Catalyst extensions as plugins only to provide
531 some functionality application wide. Design it as a controller base class
532 or another suiting technique with a smaller scope, so that your code only
533 influences those parts of the application where it is needed, and
534 namespace clashes and conflicts are ruled out.
536 The implementation is pretty easy. Your plugin will be inserted in the
537 application's inheritance list, above Catalyst itself. You can by this
538 alter Catalyst's request lifecycle behaviour. Every method you declare,
539 every import in your package will be available as method on the
540 application and the context object. As an example, let's say you want
541 Catalyst to warn you every time uri_for returned an undefined value, for
542 example because you specified the wrong number of captures for the
543 targeted action chain. You could do this with this simple
544 implementation (excuse the lame class name, it's just an example):
546 package Catalyst::Plugin::UriforUndefWarning;
552 my $uri = $c->next::method(@_);
554 'uri_for returned undef for:',
562 This would override Catalyst's C<uri_for> method and emit a C<warn> log
563 entry containing the arguments that led to the undefined return value.
565 =head2 Factory components with COMPONENT()
567 Every component inheriting from L<Catalyst::Component> contains a
568 C<COMPONENT> method. It is used on application startup by
569 C<setup_components> to instantiate the component object for the Catalyst
570 application. By default, this will merge the components own
571 C<config>uration with the application wide overrides and call the class'
572 C<new> method to return the component object.
574 You can override this method and do and return whatever you want.
575 However, you should use L<Class::C3> to forward to the original
576 C<COMPONENT> method to merge the configuration of your component.
578 Here is a stub C<COMPONENT> method:
580 package CatalystX::Component::Foo;
582 use base 'Catalyst::Component';
588 my ($app_class, $config) = @_;
590 # do things here before instantiation
591 my $obj = $self->next::method(@_);
592 # do things to object after instantiation
597 The arguments are the class name of the component, the class name of
598 the application instantiating the component, and a hash reference
599 with the controller's configuration.
601 You are free to re-bless the object, instantiate a whole other component
602 or really do anything compatible with Catalyst's expectations on a
605 For more information, please see
606 L<Catalyst::Component/"COMPONENT($c, $arguments)">.
611 L<Catalyst::Manual::Actions>,
612 L<Catalyst::Component>
616 Robert Sedlacek C<rs@474.at>
618 =head1 LICENSE AND COPYRIGHT
620 This document is free, you can redistribute it and/or modify it under
621 the same terms as Perl itself.