reverting (most of) the whitespace changes
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Component.pm
1 package Catalyst::Component;
2
3 use Moose;
4 use MooseX::Adopt::Class::Accessor::Fast;
5 use Catalyst::Utils;
6
7
8 with 'MooseX::Emulate::Class::Accessor::Fast';
9 with 'Catalyst::ClassData';
10
11
12 =head1 NAME
13
14 Catalyst::Component - Catalyst Component Base Class
15
16 =head1 SYNOPSIS
17
18     # lib/MyApp/Model/Something.pm
19     package MyApp::Model::Something;
20
21     use base 'Catalyst::Component';
22
23     __PACKAGE__->config( foo => 'bar' );
24
25     sub test {
26         my $self = shift;
27         return $self->{foo};
28     }
29
30     sub forward_to_me {
31         my ( $self, $c ) = @_;
32         $c->response->output( $self->{foo} );
33     }
34     
35     1;
36
37     # Methods can be a request step
38     $c->forward(qw/MyApp::Model::Something forward_to_me/);
39
40     # Or just methods
41     print $c->comp('MyApp::Model::Something')->test;
42
43     print $c->comp('MyApp::Model::Something')->{foo};
44
45 =head1 DESCRIPTION
46
47 This is the universal base class for Catalyst components 
48 (Model/View/Controller).
49
50 It provides you with a generic new() for instantiation through Catalyst's
51 component loader with config() support and a process() method placeholder.
52
53 =cut
54
55 __PACKAGE__->mk_classdata($_) for qw/_config _plugins/;
56
57 around new => sub {
58     my $orig = shift;
59     my ( $self, $c ) = @_;
60
61     # Temporary fix, some components does not pass context to constructor
62     my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
63
64     my $args =  $self->merge_config_hashes( $self->config, $arguments );
65     return $self->$orig( $args );
66 };
67
68 sub COMPONENT {
69     my ( $self, $c ) = @_;
70
71     # Temporary fix, some components does not pass context to constructor
72     my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
73     $self->new($c, $arguments);
74
75 #     if ( my $new = $self->NEXT::COMPONENT( $c, $arguments ) ) {
76 #         return $new;
77 #     }
78 #     else {
79 #         if ( my $new = $self->new( $c, $arguments ) ) {
80 #             return $new;
81 #         }
82 #         else {
83 #             my $class = ref $self || $self;
84 #             my $new   = $self->merge_config_hashes(
85 #                 $self->config, $arguments );
86 #             return bless $new, $class;
87 #         }
88 #     }
89 }
90
91 sub config {
92     my $self = shift;
93     my $config_sub = $self->can('_config');
94     my $config = $self->$config_sub() || {};
95     if (@_) {
96         my $newconfig = { %{@_ > 1 ? {@_} : $_[0]} };
97         $self->_config(
98             $self->merge_config_hashes( $config, $newconfig )
99         );
100     } else {
101         # this is a bit of a kludge, required to make
102         # __PACKAGE__->config->{foo} = 'bar';
103         # work in a subclass. Calling the Class::Data::Inheritable setter
104         # will create a new _config method in the current class if it's
105         # currently inherited from the superclass. So, the can() call will
106         # return a different subref in that case and that means we know to
107         # copy and reset the value stored in the class data.
108
109         $self->_config( $config );
110
111         if ((my $config_sub_now = $self->can('_config')) ne $config_sub) {
112
113             $config = $self->merge_config_hashes( $config, {} );
114             $self->$config_sub_now( $config );
115         }
116     }
117     return $config;
118 }
119
120 sub merge_config_hashes {
121     my ( $self, $lefthash, $righthash ) = @_;
122
123     return Catalyst::Utils::merge_hashes( $lefthash, $righthash );
124 }
125
126 sub process {
127
128     Catalyst::Exception->throw( message => ( ref $_[0] || $_[0] )
129           . " did not override Catalyst::Component::process" );
130 }
131
132 1;
133
134 __END__
135
136 =head1 METHODS
137
138 =head2 new($c, $arguments)
139
140 Called by COMPONENT to instantiate the component; should return an object
141 to be stored in the application's component hash.
142
143 =head2 COMPONENT($c, $arguments)
144
145 If this method is present (as it is on all Catalyst::Component subclasses,
146 it is called by Catalyst during setup_components with the application class
147 as $c and any config entry on the application for this component (for example,
148 in the case of MyApp::Controller::Foo this would be
149 MyApp->config->{'Controller::Foo'}). The arguments are expected to be a 
150 hashref and are merged with the __PACKAGE__->config hashref before calling 
151 ->new to instantiate the component.
152
153 =head2 $c->config
154
155 =head2 $c->config($hashref)
156
157 =head2 $c->config($key, $value, ...)
158
159 Accessor for this component's config hash. Config values can be set as 
160 key value pair, or you can specify a hashref. In either case the keys
161 will be merged with any existing config settings. Each component in 
162 a Catalyst application has it's own config hash.
163
164 =head2 $c->process()
165
166 This is the default method called on a Catalyst component in the dispatcher.
167 For instance, Views implement this action to render the response body 
168 when you forward to them. The default is an abstract method.
169
170 =head2 $c->merge_config_hashes( $hashref, $hashref )
171
172 Merges two hashes together recursively, giving right-hand precedence.
173 Alias for the method in L<Catalyst::Utils>.
174
175 =head1 OPTIONAL METHODS
176
177 =head2 ACCEPT_CONTEXT($c, @args)
178
179 Catalyst components are normally initalized during server startup, either
180 as a Class or a Instance. However, some components require information about
181 the current request. To do so, they can implement an ACCEPT_CONTEXT method.
182
183 If this method is present, it is called during $c->comp/controller/model/view
184 with the current $c and any additional args (e.g. $c->model('Foo', qw/bar baz/)
185 would cause your MyApp::Model::Foo instance's ACCEPT_CONTEXT to be called with
186 ($c, 'bar', 'baz')) and the return value of this method is returned to the
187 calling code in the application rather than the component itself.
188
189 =head1 SEE ALSO
190
191 L<Catalyst>, L<Catalyst::Model>, L<Catalyst::View>, L<Catalyst::Controller>.
192
193 =head1 AUTHOR
194
195 Sebastian Riedel, C<sri@cpan.org>
196 Marcus Ramberg, C<mramberg@cpan.org>
197 Matt S Trout, C<mst@shadowcatsystems.co.uk>
198
199 =head1 COPYRIGHT
200
201 This program is free software, you can redistribute it and/or modify it under
202 the same terms as Perl itself.
203
204 =cut