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