patch to avoid memory leak in subinclude by weakening $c reference
[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 qw/croak/;
6 use Scalar::Util qw/weaken/;
7
8 =head1 NAME
9
10 Catalyst::View::Component::SubInclude - Use subincludes in your Catalyst views
11
12 =head1 VERSION
13
14 Version 0.05
15
16 =cut
17
18 our $VERSION = '0.06';
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 around 'render' => sub {
124     my $next = shift;
125     my ($self, $c, @args) = @_;
126    
127     weaken $c; 
128
129     $c->stash->{subinclude}       = sub { $self->_subinclude( $c, @_ ) };
130     $c->stash->{subinclude_using} = sub { $self->_subinclude_using( $c, @_ ) };
131
132     $self->$next( $c, @args );
133 };
134
135 sub set_subinclude_plugin {
136     my ($self, $plugin) = @_;
137
138     my $subinclude_class = $self->_subinclude_plugin_class_name( $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_name($plugin);
150     $plugin->generate_subinclude( $c, @args );
151 }
152
153 sub _subinclude_plugin_class_name {
154     my ($self, $plugin) = @_;
155     
156     # check if name is already fully qualified
157     my $pkg = __PACKAGE__;
158     return $plugin if $plugin =~ /^$pkg/;
159
160     my $class_name = __PACKAGE__ . '::' . $plugin;
161     
162     eval "require $class_name";
163     croak "Error requiring $class_name: $@" if $@;
164
165     $class_name;
166 }
167
168 =head1 SEE ALSO
169
170 L<Catalyst::Plugin::SubRequest|Catalyst::Plugin::SubRequest>, 
171 L<Moose::Role|Moose::Role>, L<Moose|Moose>,
172 L<http://www.catalystframework.org/calendar/2008/17>
173
174 =head1 BUGS
175
176 Please report any bugs or feature requests to
177 C<bug-catalyst-view-component-subinclude at rt.cpan.org>, or through the web interface at
178 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Catalyst-View-Component-SubInclude>.
179 I will be notified, and then you'll automatically be notified of progress on
180 your bug as I make changes.
181
182 =head1 AUTHOR
183
184 Nilson Santos Figueiredo Junior, C<< <nilsonsfj at cpan.org> >>
185
186 =head1 SPONSORSHIP
187
188 Development sponsored by Ionzero LLC L<http://www.ionzero.com/>.
189
190 =head1 COPYRIGHT & LICENSE
191
192 Copyright (C) 2009 Nilson Santos Figueiredo Junior.
193
194 Copyright (C) 2009 Ionzero LLC.
195
196 This program is free software; you can redistribute it and/or modify it
197 under the same terms as Perl itself.
198
199 =cut
200
201 1;