1f1fbb509f5b6cb0930dc59f4f6c3809c7b936e5
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Component.pm
1 package Catalyst::Component;
2
3 use Moose;
4 use Class::MOP;
5 use MooseX::Adopt::Class::Accessor::Fast;
6 use Catalyst::Utils;
7 use MRO::Compat;
8 use mro 'c3';
9
10 with 'MooseX::Emulate::Class::Accessor::Fast';
11 with 'Catalyst::ClassData';
12
13
14 =head1 NAME
15
16 Catalyst::Component - Catalyst Component Base Class
17
18 =head1 SYNOPSIS
19
20     # lib/MyApp/Model/Something.pm
21     package MyApp::Model::Something;
22
23     use base 'Catalyst::Component';
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     }
36     
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
49 This is the universal base class for Catalyst components 
50 (Model/View/Controller).
51
52 It provides you with a generic new() for instantiation through Catalyst's
53 component loader with config() support and a process() method placeholder.
54
55 =cut
56
57 __PACKAGE__->mk_classdata('_plugins');
58 __PACKAGE__->mk_classdata('_config');
59
60 sub BUILDARGS {
61     my ($self) = @_;
62     
63     # Temporary fix, some components does not pass context to constructor
64     my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
65
66     my $args =  $self->merge_config_hashes( $self->config, $arguments );
67     
68     return $args;
69 }
70
71 no Moose;
72
73 sub 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] : {};
78     if( my $next = $self->next::can ){
79       my $class = blessed $self || $self;
80       my ($next_package) = Class::MOP::get_code_info($next);
81       warn "There is a COMPONENT method resolving after Catalyst::Component in ${next_package}. This behavior is deprecated and will stop working in future releases.";
82       return $next->($self, $arguments);
83     }
84     return $self->new($c, $arguments);
85 }
86
87 sub config {
88     my $self = shift;
89     my $config = $self->_config || {};
90     if (@_) {
91         my $newconfig = { %{@_ > 1 ? {@_} : $_[0]} };
92         $self->_config(
93             $self->merge_config_hashes( $config, $newconfig )
94         );
95     } else {
96         # this is a bit of a kludge, required to make
97         # __PACKAGE__->config->{foo} = 'bar';
98         # work in a subclass. If we don't have the package symbol in the
99         # current class we know we need to copy up to ours, which calling
100         # the setter will do for us.
101
102         unless ($self->meta->has_package_symbol('$_config')) {
103
104             $config = $self->merge_config_hashes( $config, {} );
105             $self->_config( $config );
106         }
107     }
108     return $config;
109 }
110
111 sub merge_config_hashes {
112     my ( $self, $lefthash, $righthash ) = @_;
113
114     return Catalyst::Utils::merge_hashes( $lefthash, $righthash );
115 }
116
117 sub process {
118
119     Catalyst::Exception->throw( message => ( ref $_[0] || $_[0] )
120           . " did not override Catalyst::Component::process" );
121 }
122
123
124 __PACKAGE__->meta->make_immutable;
125 1;
126
127 __END__
128
129 =head1 METHODS
130
131 =head2 new($c, $arguments)
132
133 Called by COMPONENT to instantiate the component; should return an object
134 to be stored in the application's component hash.
135
136 =head2 COMPONENT($c, $arguments)
137
138 If this method is present (as it is on all Catalyst::Component subclasses,
139 it is called by Catalyst during setup_components with the application class
140 as $c and any config entry on the application for this component (for example,
141 in the case of MyApp::Controller::Foo this would be
142 MyApp->config->{'Controller::Foo'}). The arguments are expected to be a 
143 hashref and are merged with the __PACKAGE__->config hashref before calling 
144 ->new to instantiate the component.
145
146 =head2 $c->config
147
148 =head2 $c->config($hashref)
149
150 =head2 $c->config($key, $value, ...)
151
152 Accessor for this component's config hash. Config values can be set as 
153 key value pair, or you can specify a hashref. In either case the keys
154 will be merged with any existing config settings. Each component in 
155 a Catalyst application has it's own config hash.
156
157 =head2 $c->process()
158
159 This is the default method called on a Catalyst component in the dispatcher.
160 For instance, Views implement this action to render the response body 
161 when you forward to them. The default is an abstract method.
162
163 =head2 $c->merge_config_hashes( $hashref, $hashref )
164
165 Merges two hashes together recursively, giving right-hand precedence.
166 Alias for the method in L<Catalyst::Utils>.
167
168 =head1 OPTIONAL METHODS
169
170 =head2 ACCEPT_CONTEXT($c, @args)
171
172 Catalyst components are normally initalized during server startup, either
173 as a Class or a Instance. However, some components require information about
174 the current request. To do so, they can implement an ACCEPT_CONTEXT method.
175
176 If this method is present, it is called during $c->comp/controller/model/view
177 with the current $c and any additional args (e.g. $c->model('Foo', qw/bar baz/)
178 would cause your MyApp::Model::Foo instance's ACCEPT_CONTEXT to be called with
179 ($c, 'bar', 'baz')) and the return value of this method is returned to the
180 calling code in the application rather than the component itself.
181
182 =head1 SEE ALSO
183
184 L<Catalyst>, L<Catalyst::Model>, L<Catalyst::View>, L<Catalyst::Controller>.
185
186 =head1 AUTHOR
187
188 Sebastian Riedel, C<sri@cpan.org>
189 Marcus Ramberg, C<mramberg@cpan.org>
190 Matt S Trout, C<mst@shadowcatsystems.co.uk>
191
192 =head1 COPYRIGHT
193
194 This program is free software, you can redistribute it and/or modify it under
195 the same terms as Perl itself.
196
197 =cut