Switch to using contextclosure
[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 namespace::clean -except => 'meta';
6
7 with 'Catalyst::Component::ContextClosure';
8
9 =head1 NAME
10
11 Catalyst::View::Component::SubInclude - Use subincludes in your Catalyst views
12
13 =head1 VERSION
14
15 Version 0.07
16
17 =cut
18
19 our $VERSION = '0.07';
20
21 =head1 SYNOPSIS
22
23   package MyApp::View::TT;
24   use Moose;
25
26   extends 'Catalyst::View::TT';
27   with 'Catalyst::View::Component::SubInclude';
28
29   __PACKAGE__->config( subinclude_plugin => 'SubRequest' );
30
31 Then, somewhere in your templates:
32
33   [% subinclude('/my/widget') %]
34   [% subinclude_using('SubRequest', '/page/footer') %]
35
36 =head1 DESCRIPTION
37
38 C<Catalyst::View::Component::SubInclude> allows you to include content in your
39 templates (or, more generally, somewhere in your view's C<render> processing)
40 which comes from another action in your application. It's implemented as a 
41 L<Moose::Role|Moose::Role>, so using L<Moose|Moose> in your view is required.
42
43 Simply put, it's a way to include the output of a Catalyst sub-request somewhere
44 in your page. 
45
46 It's built in an extensible way so that you're free to use sub-requests, Varnish 
47 ESI (L<http://www.catalystframework.org/calendar/2008/17>) or any other 
48 sub-include plugin you might want to implement. An LWP plugin seems useful and
49 might be developed in the future.
50
51 =head1 STASH FUNCTIONS
52
53 This component does its magic by exporting a C<subinclude> coderef entry to the
54 stash. This way, it's easily accessible by the templates (which is the most 
55 common use-case).
56
57 =head2 C<subinclude( $path, @args )>
58
59 This will render and return the body of the included resource (as specified by 
60 C<$path>) using the default subinclude plugin.
61
62 =head2 C<subinclude_using( $plugin, $path, @args )>
63
64 This will render and return the body of the included resource (as specified by 
65 C<$path>) using the specified subinclude plugin.
66
67 The C<subinclude> function above is implemented basically as a shortcut which 
68 calls this function using the default plugin as the first parameter.
69
70 =head1 SUBINCLUDE PLUGINS
71
72 The module comes with two subinclude plugins: 
73 L<SubRequest|Catalyst::Plugin::View::Component::SubRequest>,
74 L<Visit|Catalyst::Plugin::View::Component::Visit> and 
75 L<ESI|Catalyst::Plugin::View::Component::ESI>.
76
77 By default, the C<SubRequest> plugin will be used. This can be changed in the 
78 view's configuration options (either in the config file or in the view module
79 itself). 
80
81 Configuration file example:
82
83   <View::TT>
84       subinclude_plugin   ESI
85   </View::TT>
86
87 =head2 C<set_subinclude_plugin( $plugin )>
88
89 This method changes the current active subinclude plugin in runtime. It expects
90 the plugin suffix (e.g. C<ESI> or C<SubRequest>) or a fully-qualified class 
91 name in the C<Catalyst::View::Component::SubInclude> namespace.
92
93 =head2 Writing plugins
94
95 If writing your own plugin, keep in kind plugins are required to implement a 
96 class method C<generate_subinclude> with the following signature:
97
98   sub generate_subinclude {
99       my ($class, $c, @args) = @_;
100   }
101
102 The default plugin is stored in the C<subinclude_plugin> which can be changed
103 in runtime. It expects a fully qualified class name.
104
105 =cut
106
107 has 'subinclude_plugin' => (
108     is => 'rw',
109     isa => 'Str'
110 );
111
112 around 'new' => sub {
113     my $next = shift;
114     my $class = shift;
115     
116     my $self = $class->$next( @_ );
117     
118     my $subinclude_plugin = $self->config->{subinclude_plugin} || 'SubRequest';
119     $self->set_subinclude_plugin( $subinclude_plugin );
120     
121     $self;
122 };
123
124 before 'render' => sub {
125     my ($self, $c, @args) = @_;
126
127     $c->stash->{subinclude}       = $self->make_context_closure(sub { $self->_subinclude( @_ ) }, $c);
128     $c->stash->{subinclude_using} = $self->make_context_closure(sub { $self->_subinclude_using( @_ ) }, $c);
129 };
130
131 sub set_subinclude_plugin {
132     my ($self, $plugin) = @_;
133
134     my $subinclude_class = $self->_subinclude_plugin_class_name( $plugin );
135     $self->subinclude_plugin( $subinclude_class );
136 }
137
138 sub _subinclude {
139     my ($self, $c, @args) = @_;
140     $self->_subinclude_using( $c, $self->subinclude_plugin, @args );
141 }
142
143 sub _subinclude_using {
144     my ($self, $c, $plugin, @args) = @_;
145     $plugin = $self->_subinclude_plugin_class_name($plugin);
146     $plugin->generate_subinclude( $c, @args );
147 }
148
149 sub _subinclude_plugin_class_name {
150     my ($self, $plugin) = @_;
151     
152     # check if name is already fully qualified
153     my $pkg = __PACKAGE__;
154     return $plugin if $plugin =~ /^$pkg/;
155
156     my $class_name = __PACKAGE__ . '::' . $plugin;
157     
158     eval "require $class_name";
159     croak "Error requiring $class_name: $@" if $@;
160
161     $class_name;
162 }
163
164 =head1 SEE ALSO
165
166 L<Catalyst::Plugin::SubRequest|Catalyst::Plugin::SubRequest>, 
167 L<Moose::Role|Moose::Role>, L<Moose|Moose>,
168 L<http://www.catalystframework.org/calendar/2008/17>
169
170 =head1 BUGS
171
172 Please report any bugs or feature requests to
173 C<bug-catalyst-view-component-subinclude at rt.cpan.org>, or through the web interface at
174 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Catalyst-View-Component-SubInclude>.
175 I will be notified, and then you'll automatically be notified of progress on
176 your bug as I make changes.
177
178 =head1 AUTHOR
179
180 Nilson Santos Figueiredo Junior, C<< <nilsonsfj at cpan.org> >>
181
182 =head1 SPONSORSHIP
183
184 Development sponsored by Ionzero LLC L<http://www.ionzero.com/>.
185
186 =head1 COPYRIGHT & LICENSE
187
188 Copyright (C) 2009 Nilson Santos Figueiredo Junior.
189
190 Copyright (C) 2009 Ionzero LLC.
191
192 This program is free software; you can redistribute it and/or modify it
193 under the same terms as Perl itself.
194
195 =cut
196
197 1;