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