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