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