Fix all the version numbers
[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_03
19
20 =cut
21
22 our $VERSION = '0.07_03';
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 CONTRIBUTORS
196
197 Tomas Doran (t0m) C<< <bobtfish@bobtfish.net >>.
198
199 =head1 SPONSORSHIP
200
201 Development sponsored by Ionzero LLC L<http://www.ionzero.com/>.
202
203 =head1 COPYRIGHT & LICENSE
204
205 Copyright (C) 2010 Nilson Santos Figueiredo Junior and the above contributors.
206
207 Copyright (C) 2009 Nilson Santos Figueiredo Junior.
208
209 Copyright (C) 2009 Ionzero LLC.
210
211 This program is free software; you can redistribute it and/or modify it
212 under the same terms as Perl itself.
213
214 =cut
215
216 1;