Merge github.com:wreis/catalyst-view-component-subinclude
[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
dcdc4ec8 22our $VERSION = '0.09';
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 $class = $plugin =~ /::/ ? $plugin : __PACKAGE__ . '::' . $plugin;
172
173 my $cache = $self->_subinclude_plugin_class_instance_cache;
174 return $cache->{$plugin} if exists $cache->{$plugin};
be2a019a 175
956a83d8 176 my $plugin_config = Catalyst::Utils::merge_hashes(
35ebe0b6 177 $self->subinclude->{ALL}||{},
178 $self->subinclude->{$plugin}||{}
956a83d8 179 );
f81dfa28 180
956a83d8 181 Class::MOP::load_class($class);
be2a019a 182
956a83d8 183 return $cache->{$plugin} = $class->new($plugin_config);
be2a019a 184}
185
ada1ae3c 186=head1 SEE ALSO
187
f81dfa28 188L<Catalyst::Plugin::SubRequest|Catalyst::Plugin::SubRequest>,
4e327756 189L<Moose::Role|Moose::Role>, L<Moose|Moose>,
ada1ae3c 190L<http://www.catalystframework.org/calendar/2008/17>
191
192=head1 BUGS
193
194Please report any bugs or feature requests to
195C<bug-catalyst-view-component-subinclude at rt.cpan.org>, or through the web interface at
196L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Catalyst-View-Component-SubInclude>.
197I will be notified, and then you'll automatically be notified of progress on
198your bug as I make changes.
199
200=head1 AUTHOR
201
202Nilson Santos Figueiredo Junior, C<< <nilsonsfj at cpan.org> >>
203
976b0551 204=head1 CONTRIBUTORS
205
206Tomas Doran (t0m) C<< <bobtfish@bobtfish.net >>.
207
ada1ae3c 208=head1 SPONSORSHIP
209
210Development sponsored by Ionzero LLC L<http://www.ionzero.com/>.
211
212=head1 COPYRIGHT & LICENSE
213
976b0551 214Copyright (C) 2010 Nilson Santos Figueiredo Junior and the above contributors.
215
ada1ae3c 216Copyright (C) 2009 Nilson Santos Figueiredo Junior.
217
218Copyright (C) 2009 Ionzero LLC.
219
220This program is free software; you can redistribute it and/or modify it
221under the same terms as Perl itself.
222
223=cut
224
30726632 2251;