Stop calling class data methods on instances + commented out warning
[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
8f6cebb2 63has catalyst_component_name => ( is => 'ro' ); # Cannot be required => 1 as context
d2598ac8 64 # class @ISA component - HATE
65# Make accessor callable as a class method, as we need to call setup_actions
66# on the application class, which we don't have an instance of, ewwwww
e65d000f 67# Also, naughty modules like Catalyst::View::JSON try to write to _everything_,
68# so spit a warning, ignore that (and try to do the right thing anyway) here..
8f6cebb2 69around catalyst_component_name => sub {
d2598ac8 70 my ($orig, $self) = (shift, shift);
8f6cebb2 71 Carp::cluck("Tried to write to the catalyst_component_name accessor - is your component broken or just mad? (Write ignored - using default value.)") if scalar @_;
e65d000f 72 blessed($self) ? $self->$orig() || blessed($self) : $self;
d2598ac8 73};
1b79e199 74
2ef59958 75sub BUILDARGS {
7a5ed4ef 76 my $class = shift;
77 my $args = {};
78
79 if (@_ == 1) {
80 $args = $_[0] if ref($_[0]) eq 'HASH';
81 } elsif (@_ == 2) { # is it ($app, $args) or foo => 'bar' ?
82 if (blessed($_[0])) {
83 $args = $_[1] if ref($_[1]) eq 'HASH';
84 } elsif (Class::MOP::is_class_loaded($_[0]) &&
85 $_[0]->isa('Catalyst') && ref($_[1]) eq 'HASH') {
86 $args = $_[1];
87 } elsif ($_[0] == $_[1]) {
88 $args = $_[1];
89 } else {
90 $args = +{ @_ };
91 }
92 } elsif (@_ % 2 == 0) {
93 $args = +{ @_ };
94 }
43c58153 95
7a5ed4ef 96 return $class->merge_config_hashes( $class->config, $args );
2ef59958 97}
4090e3bb 98
22247e54 99sub COMPONENT {
1b79e199 100 my ( $class, $c ) = @_;
22247e54 101
102 # Temporary fix, some components does not pass context to constructor
103 my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
1b79e199 104 if ( my $next = $class->next::can ) {
6a7254b5 105 my ($next_package) = Class::MOP::get_code_info($next);
7e2ec16e 106 warn "There is a COMPONENT method resolving after Catalyst::Component in ${next_package}.\n";
107 warn "This behavior can no longer be supported, and so your application is probably broken.\n";
1cc8db0c 108 warn "Your linearized isa hierarchy is: " . join(', ', @{ mro::get_linear_isa($class) }) . "\n";
7e2ec16e 109 warn "Please see perldoc Catalyst::Upgrading for more information about this issue.\n";
6a7254b5 110 }
1b79e199 111 return $class->new($c, $arguments);
22247e54 112}
113
158c88c0 114sub config {
11b256bc 115 my $self = shift;
df960201 116 # Uncomment once sane to do so
117 #Carp::cluck("config method called on instance") if ref $self;
11b256bc 118 my $config = $self->_config || {};
119 if (@_) {
120 my $newconfig = { %{@_ > 1 ? {@_} : $_[0]} };
121 $self->_config(
122 $self->merge_config_hashes( $config, $newconfig )
123 );
124 } else {
125 # this is a bit of a kludge, required to make
126 # __PACKAGE__->config->{foo} = 'bar';
edffeb5a 127 # work in a subclass.
7a5ed4ef 128 # TODO maybe this should be a ClassData option?
e106a59f 129 my $class = blessed($self) || $self;
130 my $meta = Class::MOP::get_metaclass_by_name($class);
74c89dea 131 unless ($meta->has_package_symbol('$_config')) {
c03aaf03 132 # Call merge_hashes to ensure we deep copy the parent
133 # config onto the subclass
134 $self->_config( Catalyst::Utils::merge_hashes($config, {}) );
46d0346d 135 }
158c88c0 136 }
7a5ed4ef 137 return $self->_config;
158c88c0 138}
139
7cd1a42b 140sub merge_config_hashes {
141 my ( $self, $lefthash, $righthash ) = @_;
158c88c0 142
7cd1a42b 143 return Catalyst::Utils::merge_hashes( $lefthash, $righthash );
144}
158c88c0 145
146sub process {
147
148 Catalyst::Exception->throw( message => ( ref $_[0] || $_[0] )
149 . " did not override Catalyst::Component::process" );
150}
151
46d0346d 152__PACKAGE__->meta->make_immutable;
7a5ed4ef 153
7cd1a42b 1541;
baf6a3db 155
7cd1a42b 156__END__
baf6a3db 157
7cd1a42b 158=head1 METHODS
baf6a3db 159
7cd1a42b 160=head2 new($c, $arguments)
baf6a3db 161
7cd1a42b 162Called by COMPONENT to instantiate the component; should return an object
163to be stored in the application's component hash.
164
7a5ed4ef 165=head2 COMPONENT
166
167C<< my $component_instance = $component->COMPONENT($app, $arguments); >>
7cd1a42b 168
169If this method is present (as it is on all Catalyst::Component subclasses,
170it is called by Catalyst during setup_components with the application class
171as $c and any config entry on the application for this component (for example,
172in the case of MyApp::Controller::Foo this would be
9779c885 173C<< MyApp->config('Controller::Foo' => \%conf >>).
174The arguments are expected to be a hashref and are merged with the
175C<< __PACKAGE__->config >> hashref before calling C<< ->new >>
176to instantiate the component.
7cd1a42b 177
7a5ed4ef 178You can override it in your components to do custom instantiation, using
179something like this:
180
181 sub COMPONENT {
182 my ($class, $app, $args) = @_;
183 $args = $self->merge_config_hashes($self->config, $args);
184 return $class->new($app, $args);
185 }
186
7cd1a42b 187=head2 $c->config
188
189=head2 $c->config($hashref)
190
191=head2 $c->config($key, $value, ...)
192
43c58153 193Accessor for this component's config hash. Config values can be set as
7cd1a42b 194key value pair, or you can specify a hashref. In either case the keys
43c58153 195will be merged with any existing config settings. Each component in
196a Catalyst application has its own config hash.
7cd1a42b 197
198=head2 $c->process()
199
200This is the default method called on a Catalyst component in the dispatcher.
43c58153 201For instance, Views implement this action to render the response body
7cd1a42b 202when you forward to them. The default is an abstract method.
203
204=head2 $c->merge_config_hashes( $hashref, $hashref )
205
206Merges two hashes together recursively, giving right-hand precedence.
207Alias for the method in L<Catalyst::Utils>.
baf6a3db 208
825dbf85 209=head1 OPTIONAL METHODS
210
211=head2 ACCEPT_CONTEXT($c, @args)
212
f9c35d6c 213Catalyst components are normally initialized during server startup, either
825dbf85 214as a Class or a Instance. However, some components require information about
215the current request. To do so, they can implement an ACCEPT_CONTEXT method.
216
217If this method is present, it is called during $c->comp/controller/model/view
218with the current $c and any additional args (e.g. $c->model('Foo', qw/bar baz/)
219would cause your MyApp::Model::Foo instance's ACCEPT_CONTEXT to be called with
220($c, 'bar', 'baz')) and the return value of this method is returned to the
221calling code in the application rather than the component itself.
222
158c88c0 223=head1 SEE ALSO
224
e7f1cf73 225L<Catalyst>, L<Catalyst::Model>, L<Catalyst::View>, L<Catalyst::Controller>.
158c88c0 226
2f381252 227=head1 AUTHORS
158c88c0 228
2f381252 229Catalyst Contributors, see Catalyst.pm
158c88c0 230
231=head1 COPYRIGHT
232
536bee89 233This library is free software. You can redistribute it and/or modify it under
158c88c0 234the same terms as Perl itself.
235
85d9fce6 236=cut