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