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