Add me as a contributor
[catagits/Catalyst-View-Component-SubInclude.git] / lib / Catalyst / View / Component / SubInclude.pm
CommitLineData
30726632 1package Catalyst::View::Component::SubInclude;
2use Moose::Role;
3
4use Carp qw/croak/;
7094e990 5use Catalyst::Utils ();
956a83d8 6use Class::MOP ();
7use MooseX::Types::Moose qw/Str HashRef/;
f91a7d21 8use namespace::clean -except => 'meta';
30726632 9
d547aa95 10with 'Catalyst::Component::ContextClosure';
11
ada1ae3c 12=head1 NAME
13
14Catalyst::View::Component::SubInclude - Use subincludes in your Catalyst views
15
16=head1 VERSION
17
dcdc4ec8 18Version 0.09
ada1ae3c 19
20=cut
21
b99299ba 22our $VERSION = '0.10';
cc37b7b3 23$VERSION = eval $VERSION;
ada1ae3c 24
25=head1 SYNOPSIS
26
27 package MyApp::View::TT;
28 use Moose;
29
30 extends 'Catalyst::View::TT';
31 with 'Catalyst::View::Component::SubInclude';
32
33 __PACKAGE__->config( subinclude_plugin => 'SubRequest' );
34
35Then, somewhere in your templates:
36
37 [% subinclude('/my/widget') %]
be2a019a 38 [% subinclude_using('SubRequest', '/page/footer') %]
ada1ae3c 39
40=head1 DESCRIPTION
41
42C<Catalyst::View::Component::SubInclude> allows you to include content in your
43templates (or, more generally, somewhere in your view's C<render> processing)
f81dfa28 44which comes from another action in your application. It's implemented as a
4e327756 45L<Moose::Role|Moose::Role>, so using L<Moose|Moose> in your view is required.
ada1ae3c 46
47Simply put, it's a way to include the output of a Catalyst sub-request somewhere
f81dfa28 48in your page.
ada1ae3c 49
6bd0988d 50It's built in an extensible way so that you're free to use sub-requests,
51Varnish ESI (L<http://www.catalystframework.org/calendar/2008/17>) or any other
ada1ae3c 52sub-include plugin you might want to implement. An LWP plugin seems useful and
6bd0988d 53might be developed in the future. If you need to address a resource by it's
54public path (i.e. the path part trailing C<http://example.com/myapp> then you
55will need to use L<Catalyst::Plugin::SubRequest> directly, and not this
56component.
ada1ae3c 57
be2a019a 58=head1 STASH FUNCTIONS
ada1ae3c 59
60This component does its magic by exporting a C<subinclude> coderef entry to the
f81dfa28 61stash. This way, it's easily accessible by the templates (which is the most
ada1ae3c 62common use-case).
63
64=head2 C<subinclude( $path, @args )>
65
f81dfa28 66This will render and return the body of the included resource (as specified by
be2a019a 67C<$path>) using the default subinclude plugin.
68
69=head2 C<subinclude_using( $plugin, $path, @args )>
70
f81dfa28 71This will render and return the body of the included resource (as specified by
be2a019a 72C<$path>) using the specified subinclude plugin.
73
f81dfa28 74The C<subinclude> function above is implemented basically as a shortcut which
be2a019a 75calls this function using the default plugin as the first parameter.
ada1ae3c 76
77=head1 SUBINCLUDE PLUGINS
78
f81dfa28 79The module comes with two subinclude plugins:
e88af283 80L<SubRequest|Catalyst::Plugin::View::Component::SubRequest>,
f81dfa28 81L<Visit|Catalyst::Plugin::View::Component::Visit> and
ada1ae3c 82L<ESI|Catalyst::Plugin::View::Component::ESI>.
83
f81dfa28 84By default, the C<SubRequest> plugin will be used. This can be changed in the
ada1ae3c 85view's configuration options (either in the config file or in the view module
f81dfa28 86itself).
ada1ae3c 87
88Configuration file example:
89
90 <View::TT>
91 subinclude_plugin ESI
92 </View::TT>
93
be2a019a 94=head2 C<set_subinclude_plugin( $plugin )>
95
96This method changes the current active subinclude plugin in runtime. It expects
f81dfa28 97the plugin suffix (e.g. C<ESI> or C<SubRequest>) or a fully-qualified class
be2a019a 98name in the C<Catalyst::View::Component::SubInclude> namespace.
99
100=head2 Writing plugins
101
f81dfa28 102If writing your own plugin, keep in kind plugins are required to implement a
11a93ea1 103class method C<generate_subinclude> with the following signature:
104
105 sub generate_subinclude {
106 my ($class, $c, @args) = @_;
107 }
108
be2a019a 109The default plugin is stored in the C<subinclude_plugin> which can be changed
110in runtime. It expects a fully qualified class name.
111
ada1ae3c 112=cut
113
30726632 114has 'subinclude_plugin' => (
115 is => 'rw',
956a83d8 116 isa => Str,
be2a019a 117);
30726632 118
35ebe0b6 119has subinclude => (
120 is => 'ro',
121 isa => HashRef,
122 default => sub { {} },
123);
124
30726632 125around 'new' => sub {
126 my $next = shift;
127 my $class = shift;
f81dfa28 128
30726632 129 my $self = $class->$next( @_ );
f81dfa28 130
30726632 131 my $subinclude_plugin = $self->config->{subinclude_plugin} || 'SubRequest';
be2a019a 132 $self->set_subinclude_plugin( $subinclude_plugin );
f81dfa28 133
30726632 134 $self;
135};
136
1869d781 137before 'render' => sub {
30726632 138 my ($self, $c, @args) = @_;
ab0b6bbd 139
d547aa95 140 $c->stash->{subinclude} = $self->make_context_closure(sub { $self->_subinclude( @_ ) }, $c);
141 $c->stash->{subinclude_using} = $self->make_context_closure(sub { $self->_subinclude_using( @_ ) }, $c);
30726632 142};
143
be2a019a 144sub set_subinclude_plugin {
145 my ($self, $plugin) = @_;
146
956a83d8 147 my $subinclude_class = blessed $self->_subinclude_plugin_class_instance( $plugin );
be2a019a 148 $self->subinclude_plugin( $subinclude_class );
149}
150
151sub _subinclude {
152 my ($self, $c, @args) = @_;
153 $self->_subinclude_using( $c, $self->subinclude_plugin, @args );
154}
155
156sub _subinclude_using {
157 my ($self, $c, $plugin, @args) = @_;
956a83d8 158 $plugin = $self->_subinclude_plugin_class_instance($plugin);
159 $plugin->generate_subinclude( $c, @args );
be2a019a 160}
161
956a83d8 162has _subinclude_plugin_class_instance_cache => (
163 isa => HashRef,
164 is => 'ro',
165 default => sub { {} },
166);
167
168sub _subinclude_plugin_class_instance {
be2a019a 169 my ($self, $plugin) = @_;
f81dfa28 170
956a83d8 171 my $cache = $self->_subinclude_plugin_class_instance_cache;
172 return $cache->{$plugin} if exists $cache->{$plugin};
be2a019a 173
956a83d8 174 my $plugin_config = Catalyst::Utils::merge_hashes(
35ebe0b6 175 $self->subinclude->{ALL}||{},
176 $self->subinclude->{$plugin}||{}
956a83d8 177 );
b99299ba 178 my $short_class = $plugin_config->{'class'} ?
179 delete $plugin_config->{'class'}
180 : $plugin;
181 my $class = $short_class =~ /::/ ?
182 $short_class
183 : __PACKAGE__ . '::' . $short_class;
f81dfa28 184
956a83d8 185 Class::MOP::load_class($class);
be2a019a 186
b99299ba 187 return $cache->{$class} = $class->new($plugin_config);
be2a019a 188}
189
ada1ae3c 190=head1 SEE ALSO
191
f81dfa28 192L<Catalyst::Plugin::SubRequest|Catalyst::Plugin::SubRequest>,
4e327756 193L<Moose::Role|Moose::Role>, L<Moose|Moose>,
ada1ae3c 194L<http://www.catalystframework.org/calendar/2008/17>
195
196=head1 BUGS
197
198Please report any bugs or feature requests to
199C<bug-catalyst-view-component-subinclude at rt.cpan.org>, or through the web interface at
200L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Catalyst-View-Component-SubInclude>.
201I will be notified, and then you'll automatically be notified of progress on
202your bug as I make changes.
203
204=head1 AUTHOR
205
206Nilson Santos Figueiredo Junior, C<< <nilsonsfj at cpan.org> >>
207
976b0551 208=head1 CONTRIBUTORS
209
210Tomas Doran (t0m) C<< <bobtfish@bobtfish.net >>.
211
c61362ea 212Wallace Reis (wreis) C<< <wreis@cpan.org> >>.
213
ada1ae3c 214=head1 SPONSORSHIP
215
216Development sponsored by Ionzero LLC L<http://www.ionzero.com/>.
217
218=head1 COPYRIGHT & LICENSE
219
976b0551 220Copyright (C) 2010 Nilson Santos Figueiredo Junior and the above contributors.
221
ada1ae3c 222Copyright (C) 2009 Nilson Santos Figueiredo Junior.
223
224Copyright (C) 2009 Ionzero LLC.
225
226This program is free software; you can redistribute it and/or modify it
227under the same terms as Perl itself.
228
229=cut
230
30726632 2311;