existing Plack conventions.
- Modify Catayst::Response->from_psgi_response to allow the first argument to
be an object that does ->as_psgi.
+ - Modified Catayst::Middleware::Stash to be a shallow copy in $env. Added some
+ docs. Added a test case to make sure stash keys added in a child application
+ don't bubble back up to the main application.
5.90073 - 2014-09-23
- Fixed a regression caused by the last release where we broke what happened
# stash is automatically passed to the view for use in a template
$c->forward( 'MyApp::View::TT' );
+The stash hash is currently stored in the PSGI C<$env> and is managed by
+L<Catalyst::Middleware::Stash>. Since it's part of the C<$env> items in
+the stash can be accessed in sub applications mounted under your main
+L<Catalyst> application. For example if you delegate the response of an
+action to another L<Catalyst> application, that sub application will have
+access to all the stash keys of the main one, and if can of course add
+more keys of its own. However those new keys will not 'bubble' back up
+to the main application.
+
+For more information the best thing to do is to review the test case:
+t/middleware-stash.t in the distribution /t directory.
+
=cut
sub stash {
our @EXPORT_OK = qw(stash get_stash);
-sub PSGI_KEY { 'Catalyst.Stash.v1' };
+sub PSGI_KEY () { 'Catalyst.Stash.v1' }
sub get_stash {
my $env = shift;
- return $env->{&PSGI_KEY} ||
- _init_stash_in($env);
+ return $env->{+PSGI_KEY} ||
+ croak "You requested a stash, but one does not exist.";
}
sub stash {
};
}
-sub _init_stash_in {
- my ($env) = @_;
- return $env->{&PSGI_KEY} ||=
- _create_stash;
-}
-
sub call {
my ($self, $env) = @_;
- _init_stash_in($env);
- return $self->app->($env);
+ my $new_env = +{ %$env };
+ my %stash = %{ ($env->{+PSGI_KEY} || sub {})->() || +{} };
+
+ $new_env->{+PSGI_KEY} = _create_stash( \%stash );
+ return $self->app->($new_env);
}
=head1 TITLE
We store a coderef under the C<PSGI_KEY> which can be dereferenced with
key values or nothing to access the underly hashref.
+The stash middleware is designed so that you can 'nest' applications that
+use it. If for example you have a L<Catalyst> application that is called
+by a controller under a parent L<Catalyst> application, the child application
+will inherit the full stash of the parent BUT any new keys added by the child
+will NOT bubble back up to the parent. However, children of children will.
+
+For more information the current test case t/middleware-stash.t is the best
+documentation.
+
=head1 SUBROUTINES
This class defines the following subroutines.
["I found $stashed in the stash!"]];
};
-If the stash does not yet exist, we initialize one and return that.
+If the stash does not yet exist, an exception is thrown.
=head1 METHODS
--- /dev/null
+use warnings;
+use strict;
+
+{
+
+ package MyAppChild::Controller::User;
+ $INC{'MyAppChild/Controller/User.pm'} = __FILE__;
+
+ use base 'Catalyst::Controller';
+ use Test::More;
+
+ sub stash :Local {
+ my ($self, $c) = @_;
+ $c->stash->{inner} = "inner";
+ $c->res->body( "inner: ${\$c->stash->{inner}}, outer: ${\$c->stash->{outer}}");
+
+ is_deeply [sort {$a cmp $b} keys($c->stash)], ['inner','outer'], 'both keys in stash';
+ }
+
+ package MyAppChild;
+ $INC{'MyAppChild.pm'} = __FILE__;
+
+ use Catalyst;
+ MyAppChild->setup;
+
+ package MyAppParent::Controller::User;
+ $INC{'MyAppParent/Controller/User.pm'} = __FILE__;
+
+ use base 'Catalyst::Controller';
+ use Test::More;
+
+ sub stash :Local {
+ my ($self, $c) = @_;
+ $c->stash->{outer} = "outer";
+ $c->res->from_psgi_response( MyAppChild->to_app->($c->req->env) );
+
+ is_deeply [keys($c->stash)], ['outer'], 'only one key in stash';
+ }
+
+ package MyAppParent;
+ use Catalyst;
+ MyAppParent->setup;
+
+}
+
+use Test::More;
+use Catalyst::Test 'MyAppParent';
+
+my $res = request '/user/stash';
+is $res->content, 'inner: inner, outer: outer', 'got expected response';
+
+done_testing;