X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FExtendingCatalyst.pod;h=3cc5967cae78d5e3216b1fd1fa825917a287978f;hp=d13c220857047bed34c6d624810fe9cd5fe52e30;hb=4307eb1cd503012fb2ff86ecd1d0da6b7f5b3d25;hpb=a70cede49db4ba051d7f0575be49b6e0f9b7a862 diff --git a/lib/Catalyst/Manual/ExtendingCatalyst.pod b/lib/Catalyst/Manual/ExtendingCatalyst.pod index d13c220..3cc5967 100644 --- a/lib/Catalyst/Manual/ExtendingCatalyst.pod +++ b/lib/Catalyst/Manual/ExtendingCatalyst.pod @@ -115,15 +115,19 @@ L. =head2 Using Moose roles to apply method modifiers Rather than having a complex set of base classes which you have to mixin -via multiple inheritence, if your functionality is well structured, then +via multiple inheritance, if your functionality is well structured, then it's possible to use the composability of L roles, and method modifiers to hook onto to provide functionality. -For a simple example of this, see L. +These can be applied to your models/views/controllers, and your application +class, and shipped to CPAN. +Please see L for specific information +about using Roles in combination with Catalyst, and L +for more information about roles in general. =head2 Inheritance and overriding methods -When overriding a method, keep in mind that some day additionally +When overriding a method, keep in mind that some day additional arguments may be provided to the method, if the last parameter is not a flat list. It is thus better to override a method by shifting the invocant off of C<@_> and assign the rest of the used arguments, so @@ -225,8 +229,7 @@ action: sub foo : Local Bar('Baz') { my ($self, $c) = @_; - my $attributes = - $self->action_for('foo')->attributes; + my $attributes = $self->action_for('foo')->attributes; $c->res->body($attributes->{Bar}[0] ); } @@ -235,38 +238,58 @@ array reference. As you can see, you can use attributes to configure your actions. You can specify or alter these attributes via L, or even react on them as soon as Catalyst encounters them by providing your own L. +class|/"Component base classes">. -=head2 Creating custom accessors - -L uses L for accessor -creation. Please refer to the modules documentation for usage -information. - -=head2 Component configuration +=head2 Component Configuration At creation time, the class configuration of your component (the one available via C<$self-Econfig>) will be merged with possible configuration settings from the applications configuration (either -directly or via config file). This is then stored in the controller -object's hash reference. So, if you read possible configurations like: +directly or via config file). This is done by Catalyst, and the +correctly merged configuration is passed to your component's +constructor (i.e. the new method). + +Ergo, if you define an accessor for each configuration value +that your component takes, then the value will be automatically stored +in the controller object's hash reference, and available from the +accessor. + +The C accessor always only contains the original class configuration +and you B call $self->config to get your component configuration, +as the data there is likely to be a subset of the correct config. + +For example: + + package MyApp + use Moose; + + extends 'Catalyst'; + + ... + + __PACKAGE__->config( + 'Controller::Foo' => { some_value => 'bar' }, + ); + + ... - my $model_name = $controller->{model_name}; + package MyApp::Controller::Foo; + use Moose; + use namespace::autoclean; + BEGIN { extends 'Catalyst::Controller' }; -you will get the right value. The C accessor always only -contains the original class configuration and must not be used for -component configuration. + has some_value ( is => 'ro', required => 1 ); -You are advised to create accessors on your component class for your -configuration values. This is good practice and makes it easier to -capture configuration key typos. You can do this with the -C method provided to L via -L: + sub some_method { + my $self = shift; + return "the value of 'some_value' is " . $self->some_value; + } - use base 'Catalyst::Controller'; - __PACKAGE__->mk_ro_accessors('model_name'); ... - my $model_name = $controller->model_name; + + my $controller = $c->controller('Foo'); + warn $controller->some_value; + warn $controller->some_method; =head1 IMPLEMENTATION @@ -290,10 +313,10 @@ methods code. You can surround this by overriding the method in a subclass: package Catalyst::Action::MyFoo; - use strict; - + use Moose; + use namespace::autoclean; use MRO::Compat; - use base 'Catalyst::Action'; + extends 'Catalyst::Action'; sub execute { my $self = shift; @@ -321,10 +344,10 @@ For example, the action class below will make the action only match on Mondays: package Catalyst::Action::OnlyMondays; - use strict; - + use Moose; + use namespace::autoclean; use MRO::Compat; - use base 'Catalyst::Action'; + extends 'Catalyst::Action'; sub match { my $self = shift; @@ -344,7 +367,11 @@ If you are using action classes often or have some specific base classes that you want to specify more conveniently, you can implement a component base class providing an attribute handler. -For further information on action classes, please refer to +It is not possible to use multiple action classes at once, however +L allows you to apply L +to actions. + +For further information on action classes and roles, please refer to L and L. =head2 Component base classes @@ -368,8 +395,10 @@ already provided via the C<+> prefix for action classes. A simple will use C as action class. - package MyApp::Base::Controller::FullClass; use strict; use base - 'Catalyst::Controller'; + package MyApp::Base::Controller::FullClass; + use Moose; + use namespace::autoclean; + BEGIN { extends 'Catalyst::Controller'; } sub _parse_FullClass_attr { my ($self, $app_class, $action_name, $value, $attrs) = @_; @@ -382,8 +411,9 @@ sake. We could use this attribute in a subclass like any other Catalyst attribute: package MyApp::Controller::Foo; - use strict; - use base 'MyApp::Base::Controller::FullClass'; + use Moose; + use namespace::autoclean; + BEGIN { extends 'MyApp::Base::Controller::FullClass'; } sub foo : Local FullClass('MyApp::Action::Bar') { ... } @@ -400,8 +430,10 @@ controller object, or you can even define Catalyst actions which will be inherited by the subclasses. Consider this controller base class: package MyApp::Base::Controller::ModelBase; - use strict; - use base 'Catalyst::Controller'; + use Moose; + use namespace::autoclean; + + BEGIN { extends 'Catalyst::Controller'; } sub list : Chained('base') PathPart('') Args(0) { my ($self, $c) = @_; @@ -409,13 +441,13 @@ be inherited by the subclasses. Consider this controller base class: my $condition = $self->{model_search_condition} || {}; my $attrs = $self->{model_search_attrs} || {}; $c->stash(rs => $model->search($condition, $attrs); - } + } sub load : Chained('base') PathPart('') CaptureArgs(1) { my ($self, $c, $id) = @_; my $model = $c->model( $self->{model_name} ); $c->stash(row => $model->find($id)); - } + } 1; This example implements two simple actions. The C action chains @@ -432,8 +464,10 @@ The class above is not very useful on its own, but we can combine it with some custom actions by sub-classing it: package MyApp::Controller::Foo; - use strict; - use base 'MyApp::Base::Controller::ModelBase'; + use Moose; + use namespace::autoclean; + + BEGIN { extends 'MyApp::Base::Controller::ModelBase'; } __PACKAGE__->config( model_name => 'DB::Foo', model_search_condition=> { is_active => 1 }, @@ -500,9 +534,11 @@ generation. Here is some example code for a fictional view: - package CatalystX::View::MyView; - use strict; - use base 'Catalyst::View'; + package Catalyst::View::MyView; + use Moose; + use namespace::autoclean; + + extends 'Catalyst::View'; sub process { my ($self, $c) = @_; @@ -553,7 +589,7 @@ authentication. B release Catalyst extensions as plugins only to provide some functionality application wide. Design it as a controller -base class or another suiting technique with a smaller scope, so that +base class or another better suited technique with a smaller scope, so that your code only influences those parts of the application where it is needed, and namespace clashes and conflicts are ruled out. @@ -593,7 +629,7 @@ A simple example like this is actually better as a L role, for example: package CatalystX::UriforUndefWarning; use Moose::Role; - use namespace::clean -except => 'meta'; + use namespace::autoclean; after 'uri_for' => sub { my ($c, $arg) = @_; @@ -601,6 +637,9 @@ A simple example like this is actually better as a L role, for example: if (!blessed($_[0]) || !$_[0]->isa('Catalyst::Action')); return $uri; }; + +Note that Catalyst will load any Moose Roles in the plugin list, +and apply them to your application class. =head2 Factory components with COMPONENT() @@ -619,10 +658,10 @@ your component. Here is a stub C method: package CatalystX::Component::Foo; - use strict; - use base 'Catalyst::Component'; - - use MRO::Compat; + use Moose; + use namespace::autoclean; + + extends 'Catalyst::Component'; sub COMPONENT { my $class = shift; @@ -648,20 +687,45 @@ expectations on a component. For more information, please see L. +=head2 Applying roles to parts of the framework + +L will allow you to apply Roles to +the following classes: + +=over + +=item Request + +=item Response + +=item Engine + +=item Dispatcher + +=item Stats + +=back + +These roles can add new methods to these classes, or wrap preexisting methods. + +The namespace for roles like this is C. + +For an example of a CPAN component implemented in this manor, see +L. + =head1 SEE ALSO L, L, L -=head1 AUTHOR +=head1 AUTHORS -Robert Sedlacek C<< >> +Catalyst Contributors, see Catalyst.pm -Jonathan Rockway C<< >> +=head1 COPYRIGHT -=head1 LICENSE AND COPYRIGHT - -This document is free, you can redistribute it and/or modify it under +This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself. =cut +