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