Document the method name I actually added, idiot
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Component.pm
CommitLineData
158c88c0 1package Catalyst::Component;
2
a7caa492 3use Moose;
6a7254b5 4use Class::MOP;
74c89dea 5use Class::MOP::Object;
e8b9f2a9 6use Catalyst::Utils;
cb89a296 7use Class::C3::Adopt::NEXT;
6a7254b5 8use MRO::Compat;
9use mro 'c3';
7a5ed4ef 10use Scalar::Util 'blessed';
7a5ed4ef 11use namespace::clean -except => 'meta';
5595dd2f 12
a7caa492 13with 'MooseX::Emulate::Class::Accessor::Fast';
14with 'Catalyst::ClassData';
15
16
158c88c0 17=head1 NAME
18
19Catalyst::Component - Catalyst Component Base Class
20
21=head1 SYNOPSIS
22
23 # lib/MyApp/Model/Something.pm
24 package MyApp::Model::Something;
25
e7f1cf73 26 use base 'Catalyst::Component';
158c88c0 27
28 __PACKAGE__->config( foo => 'bar' );
29
30 sub test {
31 my $self = shift;
32 return $self->{foo};
33 }
34
35 sub forward_to_me {
36 my ( $self, $c ) = @_;
37 $c->response->output( $self->{foo} );
38 }
43c58153 39
158c88c0 40 1;
41
42 # Methods can be a request step
43 $c->forward(qw/MyApp::Model::Something forward_to_me/);
44
45 # Or just methods
46 print $c->comp('MyApp::Model::Something')->test;
47
48 print $c->comp('MyApp::Model::Something')->{foo};
49
50=head1 DESCRIPTION
51
43c58153 52This is the universal base class for Catalyst components
158c88c0 53(Model/View/Controller).
54
55It provides you with a generic new() for instantiation through Catalyst's
56component loader with config() support and a process() method placeholder.
57
7cd1a42b 58=cut
158c88c0 59
46d0346d 60__PACKAGE__->mk_classdata('_plugins');
11b256bc 61__PACKAGE__->mk_classdata('_config');
e8b9f2a9 62
1b79e199 63has _component_name => ( is => 'ro' );
64
2ef59958 65sub BUILDARGS {
7a5ed4ef 66 my $class = shift;
67 my $args = {};
68
69 if (@_ == 1) {
70 $args = $_[0] if ref($_[0]) eq 'HASH';
71 } elsif (@_ == 2) { # is it ($app, $args) or foo => 'bar' ?
72 if (blessed($_[0])) {
73 $args = $_[1] if ref($_[1]) eq 'HASH';
74 } elsif (Class::MOP::is_class_loaded($_[0]) &&
75 $_[0]->isa('Catalyst') && ref($_[1]) eq 'HASH') {
76 $args = $_[1];
77 } elsif ($_[0] == $_[1]) {
78 $args = $_[1];
79 } else {
80 $args = +{ @_ };
81 }
82 } elsif (@_ % 2 == 0) {
83 $args = +{ @_ };
84 }
43c58153 85
7a5ed4ef 86 return $class->merge_config_hashes( $class->config, $args );
2ef59958 87}
4090e3bb 88
22247e54 89sub COMPONENT {
1b79e199 90 my ( $class, $c ) = @_;
22247e54 91
92 # Temporary fix, some components does not pass context to constructor
93 my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
1b79e199 94 if ( my $next = $class->next::can ) {
6a7254b5 95 my ($next_package) = Class::MOP::get_code_info($next);
7e2ec16e 96 warn "There is a COMPONENT method resolving after Catalyst::Component in ${next_package}.\n";
97 warn "This behavior can no longer be supported, and so your application is probably broken.\n";
1cc8db0c 98 warn "Your linearized isa hierarchy is: " . join(', ', @{ mro::get_linear_isa($class) }) . "\n";
7e2ec16e 99 warn "Please see perldoc Catalyst::Upgrading for more information about this issue.\n";
6a7254b5 100 }
1b79e199 101 return $class->new($c, $arguments);
22247e54 102}
103
158c88c0 104sub config {
11b256bc 105 my $self = shift;
106 my $config = $self->_config || {};
107 if (@_) {
108 my $newconfig = { %{@_ > 1 ? {@_} : $_[0]} };
109 $self->_config(
110 $self->merge_config_hashes( $config, $newconfig )
111 );
112 } else {
113 # this is a bit of a kludge, required to make
114 # __PACKAGE__->config->{foo} = 'bar';
edffeb5a 115 # work in a subclass.
7a5ed4ef 116 # TODO maybe this should be a ClassData option?
e106a59f 117 my $class = blessed($self) || $self;
118 my $meta = Class::MOP::get_metaclass_by_name($class);
74c89dea 119 unless ($meta->has_package_symbol('$_config')) {
c03aaf03 120 # Call merge_hashes to ensure we deep copy the parent
121 # config onto the subclass
122 $self->_config( Catalyst::Utils::merge_hashes($config, {}) );
46d0346d 123 }
158c88c0 124 }
7a5ed4ef 125 return $self->_config;
158c88c0 126}
127
7cd1a42b 128sub merge_config_hashes {
129 my ( $self, $lefthash, $righthash ) = @_;
158c88c0 130
7cd1a42b 131 return Catalyst::Utils::merge_hashes( $lefthash, $righthash );
132}
158c88c0 133
134sub process {
135
136 Catalyst::Exception->throw( message => ( ref $_[0] || $_[0] )
137 . " did not override Catalyst::Component::process" );
138}
139
46d0346d 140__PACKAGE__->meta->make_immutable;
7a5ed4ef 141
7cd1a42b 1421;
baf6a3db 143
7cd1a42b 144__END__
baf6a3db 145
7cd1a42b 146=head1 METHODS
baf6a3db 147
7cd1a42b 148=head2 new($c, $arguments)
baf6a3db 149
7cd1a42b 150Called by COMPONENT to instantiate the component; should return an object
151to be stored in the application's component hash.
152
7a5ed4ef 153=head2 COMPONENT
154
155C<< my $component_instance = $component->COMPONENT($app, $arguments); >>
7cd1a42b 156
157If this method is present (as it is on all Catalyst::Component subclasses,
158it is called by Catalyst during setup_components with the application class
159as $c and any config entry on the application for this component (for example,
160in the case of MyApp::Controller::Foo this would be
9779c885 161C<< MyApp->config('Controller::Foo' => \%conf >>).
162The arguments are expected to be a hashref and are merged with the
163C<< __PACKAGE__->config >> hashref before calling C<< ->new >>
164to instantiate the component.
7cd1a42b 165
7a5ed4ef 166You can override it in your components to do custom instantiation, using
167something like this:
168
169 sub COMPONENT {
170 my ($class, $app, $args) = @_;
171 $args = $self->merge_config_hashes($self->config, $args);
172 return $class->new($app, $args);
173 }
174
4d38cb07 175=head2 _component_name
fb0c5b21 176
4d38cb07 177The name of the component within an application. This is used to
178pass the component's name to actions generated (becoming
fb0c5b21 179C<< $action->class >>). This is needed so that the L</COMPONENT> method can
180return an instance of a different class (e.g. a L<Class::MOP> anonymous class),
4d38cb07 181(as finding the component name by C<< ref($self) >> will not work correctly in
182such cases).
fb0c5b21 183
7cd1a42b 184=head2 $c->config
185
186=head2 $c->config($hashref)
187
188=head2 $c->config($key, $value, ...)
189
43c58153 190Accessor for this component's config hash. Config values can be set as
7cd1a42b 191key value pair, or you can specify a hashref. In either case the keys
43c58153 192will be merged with any existing config settings. Each component in
193a Catalyst application has its own config hash.
7cd1a42b 194
195=head2 $c->process()
196
197This is the default method called on a Catalyst component in the dispatcher.
43c58153 198For instance, Views implement this action to render the response body
7cd1a42b 199when you forward to them. The default is an abstract method.
200
201=head2 $c->merge_config_hashes( $hashref, $hashref )
202
203Merges two hashes together recursively, giving right-hand precedence.
204Alias for the method in L<Catalyst::Utils>.
baf6a3db 205
825dbf85 206=head1 OPTIONAL METHODS
207
208=head2 ACCEPT_CONTEXT($c, @args)
209
f9c35d6c 210Catalyst components are normally initialized during server startup, either
825dbf85 211as a Class or a Instance. However, some components require information about
212the current request. To do so, they can implement an ACCEPT_CONTEXT method.
213
214If this method is present, it is called during $c->comp/controller/model/view
215with the current $c and any additional args (e.g. $c->model('Foo', qw/bar baz/)
216would cause your MyApp::Model::Foo instance's ACCEPT_CONTEXT to be called with
217($c, 'bar', 'baz')) and the return value of this method is returned to the
218calling code in the application rather than the component itself.
219
158c88c0 220=head1 SEE ALSO
221
e7f1cf73 222L<Catalyst>, L<Catalyst::Model>, L<Catalyst::View>, L<Catalyst::Controller>.
158c88c0 223
2f381252 224=head1 AUTHORS
158c88c0 225
2f381252 226Catalyst Contributors, see Catalyst.pm
158c88c0 227
228=head1 COPYRIGHT
229
536bee89 230This library is free software. You can redistribute it and/or modify it under
158c88c0 231the same terms as Perl itself.
232
85d9fce6 233=cut