efd8b33321677aae34e1f784f94b7cc219a5f16d
[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.09
19
20 =cut
21
22 our $VERSION = '0.09';
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. An LWP plugin seems useful and
53 might be developed in the future. If you need to address a resource by it's
54 public path (i.e. the path part trailing C<http://example.com/myapp> then you
55 will need to use L<Catalyst::Plugin::SubRequest> directly, and not this
56 component.
57
58 =head1 STASH FUNCTIONS
59
60 This component does its magic by exporting a C<subinclude> coderef entry to the
61 stash. This way, it's easily accessible by the templates (which is the most
62 common use-case).
63
64 =head2 C<subinclude( $path, @args )>
65
66 This will render and return the body of the included resource (as specified by
67 C<$path>) using the default subinclude plugin.
68
69 =head2 C<subinclude_using( $plugin, $path, @args )>
70
71 This will render and return the body of the included resource (as specified by
72 C<$path>) using the specified subinclude plugin.
73
74 The C<subinclude> function above is implemented basically as a shortcut which
75 calls this function using the default plugin as the first parameter.
76
77 =head1 SUBINCLUDE PLUGINS
78
79 The module comes with two subinclude plugins:
80 L<SubRequest|Catalyst::Plugin::View::Component::SubRequest>,
81 L<Visit|Catalyst::Plugin::View::Component::Visit> and
82 L<ESI|Catalyst::Plugin::View::Component::ESI>.
83
84 By default, the C<SubRequest> plugin will be used. This can be changed in the
85 view's configuration options (either in the config file or in the view module
86 itself).
87
88 Configuration file example:
89
90   <View::TT>
91       subinclude_plugin   ESI
92   </View::TT>
93
94 =head2 C<set_subinclude_plugin( $plugin )>
95
96 This method changes the current active subinclude plugin in runtime. It expects
97 the plugin suffix (e.g. C<ESI> or C<SubRequest>) or a fully-qualified class
98 name in the C<Catalyst::View::Component::SubInclude> namespace.
99
100 =head2 Writing plugins
101
102 If writing your own plugin, keep in kind plugins are required to implement a
103 class method C<generate_subinclude> with the following signature:
104
105   sub generate_subinclude {
106       my ($class, $c, @args) = @_;
107   }
108
109 The default plugin is stored in the C<subinclude_plugin> which can be changed
110 in runtime. It expects a fully qualified class name.
111
112 =cut
113
114 has 'subinclude_plugin' => (
115     is => 'rw',
116     isa => Str,
117 );
118
119 around 'new' => sub {
120     my $next = shift;
121     my $class = shift;
122
123     my $self = $class->$next( @_ );
124
125     my $subinclude_plugin = $self->config->{subinclude_plugin} || 'SubRequest';
126     $self->set_subinclude_plugin( $subinclude_plugin );
127
128     $self;
129 };
130
131 before 'render' => sub {
132     my ($self, $c, @args) = @_;
133
134     $c->stash->{subinclude}       = $self->make_context_closure(sub { $self->_subinclude( @_ ) }, $c);
135     $c->stash->{subinclude_using} = $self->make_context_closure(sub { $self->_subinclude_using( @_ ) }, $c);
136 };
137
138 sub set_subinclude_plugin {
139     my ($self, $plugin) = @_;
140
141     my $subinclude_class = blessed $self->_subinclude_plugin_class_instance( $plugin );
142     $self->subinclude_plugin( $subinclude_class );
143 }
144
145 sub _subinclude {
146     my ($self, $c, @args) = @_;
147     $self->_subinclude_using( $c, $self->subinclude_plugin, @args );
148 }
149
150 sub _subinclude_using {
151     my ($self, $c, $plugin, @args) = @_;
152     $plugin = $self->_subinclude_plugin_class_instance($plugin);
153     $plugin->generate_subinclude( $c, @args );
154 }
155
156 has _subinclude_plugin_class_instance_cache => (
157     isa => HashRef,
158     is => 'ro',
159     default => sub { {} },
160 );
161
162 sub _subinclude_plugin_class_instance {
163     my ($self, $plugin) = @_;
164
165     my $class = $plugin =~ /::/ ? $plugin : __PACKAGE__ . '::' . $plugin;
166
167     my $cache = $self->_subinclude_plugin_class_instance_cache;
168     return $cache->{$plugin} if exists $cache->{$plugin};
169
170     my $plugin_config = Catalyst::Utils::merge_hashes(
171         $self->config->{subinclude}->{ALL}||{},
172         $self->config->{subinclude}->{$plugin}||{}
173     );
174
175     Class::MOP::load_class($class);
176
177     return $cache->{$plugin} = $class->new($plugin_config);
178 }
179
180 =head1 SEE ALSO
181
182 L<Catalyst::Plugin::SubRequest|Catalyst::Plugin::SubRequest>,
183 L<Moose::Role|Moose::Role>, L<Moose|Moose>,
184 L<http://www.catalystframework.org/calendar/2008/17>
185
186 =head1 BUGS
187
188 Please report any bugs or feature requests to
189 C<bug-catalyst-view-component-subinclude at rt.cpan.org>, or through the web interface at
190 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Catalyst-View-Component-SubInclude>.
191 I will be notified, and then you'll automatically be notified of progress on
192 your bug as I make changes.
193
194 =head1 AUTHOR
195
196 Nilson Santos Figueiredo Junior, C<< <nilsonsfj at cpan.org> >>
197
198 =head1 CONTRIBUTORS
199
200 Tomas Doran (t0m) C<< <bobtfish@bobtfish.net >>.
201
202 =head1 SPONSORSHIP
203
204 Development sponsored by Ionzero LLC L<http://www.ionzero.com/>.
205
206 =head1 COPYRIGHT & LICENSE
207
208 Copyright (C) 2010 Nilson Santos Figueiredo Junior and the above contributors.
209
210 Copyright (C) 2009 Nilson Santos Figueiredo Junior.
211
212 Copyright (C) 2009 Ionzero LLC.
213
214 This program is free software; you can redistribute it and/or modify it
215 under the same terms as Perl itself.
216
217 =cut
218
219 1;