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