Re-write Roadmap to not be lies, change warns on component resolution to mention...
[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';
e106a59f 10use Scalar::Util qw/blessed/;
5595dd2f 11
a7caa492 12with 'MooseX::Emulate::Class::Accessor::Fast';
13with 'Catalyst::ClassData';
14
15
158c88c0 16=head1 NAME
17
18Catalyst::Component - Catalyst Component Base Class
19
20=head1 SYNOPSIS
21
22 # lib/MyApp/Model/Something.pm
23 package MyApp::Model::Something;
24
e7f1cf73 25 use base 'Catalyst::Component';
158c88c0 26
27 __PACKAGE__->config( foo => 'bar' );
28
29 sub test {
30 my $self = shift;
31 return $self->{foo};
32 }
33
34 sub forward_to_me {
35 my ( $self, $c ) = @_;
36 $c->response->output( $self->{foo} );
37 }
ac5c933b 38
158c88c0 39 1;
40
41 # Methods can be a request step
42 $c->forward(qw/MyApp::Model::Something forward_to_me/);
43
44 # Or just methods
45 print $c->comp('MyApp::Model::Something')->test;
46
47 print $c->comp('MyApp::Model::Something')->{foo};
48
49=head1 DESCRIPTION
50
ac5c933b 51This is the universal base class for Catalyst components
158c88c0 52(Model/View/Controller).
53
54It provides you with a generic new() for instantiation through Catalyst's
55component loader with config() support and a process() method placeholder.
56
7cd1a42b 57=cut
158c88c0 58
46d0346d 59__PACKAGE__->mk_classdata('_plugins');
11b256bc 60__PACKAGE__->mk_classdata('_config');
e8b9f2a9 61
2ef59958 62sub BUILDARGS {
63 my ($self) = @_;
64
158c88c0 65 # Temporary fix, some components does not pass context to constructor
66 my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
e8b9f2a9 67
a7caa492 68 my $args = $self->merge_config_hashes( $self->config, $arguments );
2ef59958 69
70 return $args;
71}
4090e3bb 72
22247e54 73sub COMPONENT {
74 my ( $self, $c ) = @_;
75
76 # Temporary fix, some components does not pass context to constructor
77 my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
6a7254b5 78 if( my $next = $self->next::can ){
79 my $class = blessed $self || $self;
80 my ($next_package) = Class::MOP::get_code_info($next);
7e2ec16e 81 warn "There is a COMPONENT method resolving after Catalyst::Component in ${next_package}.\n";
82 warn "This behavior can no longer be supported, and so your application is probably broken.\n";
83 warn "Your linearised isa hierarchy is: " . join(', ', mro::get_linear_isa($class)) . "\n";
84 warn "Please see perldoc Catalyst::Upgrading for more information about this issue.\n";
6a7254b5 85 }
4090e3bb 86 return $self->new($c, $arguments);
22247e54 87}
88
158c88c0 89sub config {
11b256bc 90 my $self = shift;
91 my $config = $self->_config || {};
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. If we don't have the package symbol in the
101 # current class we know we need to copy up to ours, which calling
102 # the setter will do for us.
e106a59f 103 my $class = blessed($self) || $self;
104 my $meta = Class::MOP::get_metaclass_by_name($class);
74c89dea 105 unless ($meta->has_package_symbol('$_config')) {
11b256bc 106
107 $config = $self->merge_config_hashes( $config, {} );
108 $self->_config( $config );
46d0346d 109 }
158c88c0 110 }
11b256bc 111 return $config;
158c88c0 112}
113
7cd1a42b 114sub merge_config_hashes {
115 my ( $self, $lefthash, $righthash ) = @_;
158c88c0 116
7cd1a42b 117 return Catalyst::Utils::merge_hashes( $lefthash, $righthash );
118}
158c88c0 119
120sub process {
121
122 Catalyst::Exception->throw( message => ( ref $_[0] || $_[0] )
123 . " did not override Catalyst::Component::process" );
124}
125
213cf5bb 126no Moose;
46d0346d 127
128__PACKAGE__->meta->make_immutable;
7cd1a42b 1291;
baf6a3db 130
7cd1a42b 131__END__
baf6a3db 132
7cd1a42b 133=head1 METHODS
baf6a3db 134
7cd1a42b 135=head2 new($c, $arguments)
baf6a3db 136
7cd1a42b 137Called by COMPONENT to instantiate the component; should return an object
138to be stored in the application's component hash.
139
140=head2 COMPONENT($c, $arguments)
141
142If this method is present (as it is on all Catalyst::Component subclasses,
143it is called by Catalyst during setup_components with the application class
144as $c and any config entry on the application for this component (for example,
145in the case of MyApp::Controller::Foo this would be
ac5c933b 146MyApp->config->{'Controller::Foo'}). The arguments are expected to be a
147hashref and are merged with the __PACKAGE__->config hashref before calling
7cd1a42b 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
ac5c933b 156Accessor for this component's config hash. Config values can be set as
7cd1a42b 157key value pair, or you can specify a hashref. In either case the keys
ac5c933b 158will be merged with any existing config settings. Each component in
7cd1a42b 159a Catalyst application has it's own config hash.
160
161=head2 $c->process()
162
163This is the default method called on a Catalyst component in the dispatcher.
ac5c933b 164For instance, Views implement this action to render the response body
7cd1a42b 165when you forward to them. The default is an abstract method.
166
167=head2 $c->merge_config_hashes( $hashref, $hashref )
168
169Merges two hashes together recursively, giving right-hand precedence.
170Alias for the method in L<Catalyst::Utils>.
baf6a3db 171
825dbf85 172=head1 OPTIONAL METHODS
173
174=head2 ACCEPT_CONTEXT($c, @args)
175
176Catalyst components are normally initalized during server startup, either
177as a Class or a Instance. However, some components require information about
178the current request. To do so, they can implement an ACCEPT_CONTEXT method.
179
180If this method is present, it is called during $c->comp/controller/model/view
181with the current $c and any additional args (e.g. $c->model('Foo', qw/bar baz/)
182would 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
184calling code in the application rather than the component itself.
185
158c88c0 186=head1 SEE ALSO
187
e7f1cf73 188L<Catalyst>, L<Catalyst::Model>, L<Catalyst::View>, L<Catalyst::Controller>.
158c88c0 189
2f381252 190=head1 AUTHORS
158c88c0 191
2f381252 192Catalyst Contributors, see Catalyst.pm
158c88c0 193
194=head1 COPYRIGHT
195
196This program is free software, you can redistribute it and/or modify it under
197the same terms as Perl itself.
198
85d9fce6 199=cut