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