use Carp qw/croak/;
use namespace::clean qw/croak/;
+use Scalar::Util qw/weaken/;
=head1 NAME
=head1 VERSION
-Version 0.01
+Version 0.05
=cut
-our $VERSION = '0.01';
+our $VERSION = '0.06';
=head1 SYNOPSIS
Then, somewhere in your templates:
[% subinclude('/my/widget') %]
+ [% subinclude_using('SubRequest', '/page/footer') %]
=head1 DESCRIPTION
C<Catalyst::View::Component::SubInclude> allows you to include content in your
templates (or, more generally, somewhere in your view's C<render> processing)
which comes from another action in your application. It's implemented as a
-L<Moose::Role>, so using L<Moose> in your view is required.
+L<Moose::Role|Moose::Role>, so using L<Moose|Moose> in your view is required.
Simply put, it's a way to include the output of a Catalyst sub-request somewhere
in your page.
sub-include plugin you might want to implement. An LWP plugin seems useful and
might be developed in the future.
-=head1 STASH FUNCTION
+=head1 STASH FUNCTIONS
This component does its magic by exporting a C<subinclude> coderef entry to the
stash. This way, it's easily accessible by the templates (which is the most
=head2 C<subinclude( $path, @args )>
-This will return the body of the requested resource (as specified by C<$path>).
+This will render and return the body of the included resource (as specified by
+C<$path>) using the default subinclude plugin.
+
+=head2 C<subinclude_using( $plugin, $path, @args )>
+
+This will render and return the body of the included resource (as specified by
+C<$path>) using the specified subinclude plugin.
+
+The C<subinclude> function above is implemented basically as a shortcut which
+calls this function using the default plugin as the first parameter.
=head1 SUBINCLUDE PLUGINS
The module comes with two subinclude plugins:
-L<SubRequest|Catalyst::Plugin::View::Component::SubRequest> and
+L<SubRequest|Catalyst::Plugin::View::Component::SubRequest>,
+L<Visit|Catalyst::Plugin::View::Component::Visit> and
L<ESI|Catalyst::Plugin::View::Component::ESI>.
-By default, the SubRequest plugin will be used. This can be changed in the
+By default, the C<SubRequest> plugin will be used. This can be changed in the
view's configuration options (either in the config file or in the view module
itself).
subinclude_plugin ESI
</View::TT>
+=head2 C<set_subinclude_plugin( $plugin )>
+
+This method changes the current active subinclude plugin in runtime. It expects
+the plugin suffix (e.g. C<ESI> or C<SubRequest>) or a fully-qualified class
+name in the C<Catalyst::View::Component::SubInclude> namespace.
+
+=head2 Writing plugins
+
+If writing your own plugin, keep in kind plugins are required to implement a
+class method C<generate_subinclude> with the following signature:
+
+ sub generate_subinclude {
+ my ($class, $c, @args) = @_;
+ }
+
+The default plugin is stored in the C<subinclude_plugin> which can be changed
+in runtime. It expects a fully qualified class name.
+
=cut
has 'subinclude_plugin' => (
is => 'rw',
- isa => 'ClassName'
-);
+ isa => 'Str'
+);
around 'new' => sub {
my $next = shift;
my $self = $class->$next( @_ );
my $subinclude_plugin = $self->config->{subinclude_plugin} || 'SubRequest';
- my $subinclude_class = __PACKAGE__ . '::' . $subinclude_plugin;
-
- eval "require $subinclude_class";
- croak "Error requiring $subinclude_class: $@" if $@;
-
- $self->subinclude_plugin( $subinclude_class );
+ $self->set_subinclude_plugin( $subinclude_plugin );
$self;
};
around 'render' => sub {
my $next = shift;
my ($self, $c, @args) = @_;
-
- $c->stash->{subinclude} = sub {
- $self->subinclude_plugin->generate_subinclude( $c, @_ );
- };
+
+ weaken $c;
+
+ $c->stash->{subinclude} = sub { $self->_subinclude( $c, @_ ) };
+ $c->stash->{subinclude_using} = sub { $self->_subinclude_using( $c, @_ ) };
$self->$next( $c, @args );
};
+sub set_subinclude_plugin {
+ my ($self, $plugin) = @_;
+
+ my $subinclude_class = $self->_subinclude_plugin_class_name( $plugin );
+ $self->subinclude_plugin( $subinclude_class );
+}
+
+sub _subinclude {
+ my ($self, $c, @args) = @_;
+ $self->_subinclude_using( $c, $self->subinclude_plugin, @args );
+}
+
+sub _subinclude_using {
+ my ($self, $c, $plugin, @args) = @_;
+ $plugin = $self->_subinclude_plugin_class_name($plugin);
+ $plugin->generate_subinclude( $c, @args );
+}
+
+sub _subinclude_plugin_class_name {
+ my ($self, $plugin) = @_;
+
+ # check if name is already fully qualified
+ my $pkg = __PACKAGE__;
+ return $plugin if $plugin =~ /^$pkg/;
+
+ my $class_name = __PACKAGE__ . '::' . $plugin;
+
+ eval "require $class_name";
+ croak "Error requiring $class_name: $@" if $@;
+
+ $class_name;
+}
+
=head1 SEE ALSO
-L<Catalyst::Plugin::SubRequest>, L<Moose::Role>, L<Moose>,
+L<Catalyst::Plugin::SubRequest|Catalyst::Plugin::SubRequest>,
+L<Moose::Role|Moose::Role>, L<Moose|Moose>,
L<http://www.catalystframework.org/calendar/2008/17>
=head1 BUGS