my $self = shift;
my $env = shift;
- $env->{'psgix.session'} = $env->{'plack.session'} = $self->session_class->new(
- state => $self->state,
- store => $self->store,
- request => Plack::Request->new( $env )
- );
+ my $session = $self->session_class->fetch_or_create( Plack::Request->new($env), $self );
+
+ $env->{'psgix.session'} = $env->{'plack.session'} = $session;
my $res = $self->app->($env);
$self->response_cb($res, sub {
our $VERSION = '0.03';
our $AUTHORITY = 'cpan:STEVAN';
-use Plack::Util::Accessor qw[
- id
- store
- state
-];
+use Plack::Util::Accessor qw( id is_new manager );
+
+sub fetch_or_create {
+ my($class, $request, $manager) = @_;
+
+ my $id = $manager->state->extract($request);
+ if ($id) {
+ my $store = $manager->store->fetch($id);
+ return $class->new( id => $id, _stash => $store, manager => $manager );
+ } else {
+ $id = $manager->state->generate($request);
+ return $class->new( id => $id, _stash => {}, manager => $manager, is_new => 1 );
+ }
+}
sub new {
my ($class, %params) = @_;
- my $request = delete $params{'request'};
- $params{'id'} = $params{'state'}->get_session_id( $request );
bless { %params } => $class;
}
## Data Managment
+sub dump {
+ my $self = shift;
+ $self->{_stash};
+}
+
sub get {
my ($self, $key) = @_;
- $self->store->fetch( $self->id, $key )
+ $self->{_stash}{$key};
}
sub set {
my ($self, $key, $value) = @_;
- $self->store->store( $self->id, $key, $value );
+ $self->{_stash}{$key} = $value;
}
sub remove {
my ($self, $key) = @_;
- $self->store->delete( $self->id, $key );
+ delete $self->{_stash}{$key};
+}
+
+sub keys {
+ my $self = shift;
+ keys %{$self->{_stash}};
}
## Lifecycle Management
sub expire {
my $self = shift;
- $self->store->cleanup( $self->id );
- $self->state->expire_session_id( $self->id );
+ $self->{_stash} = {};
+ $self->manager->store->cleanup( $self->id );
+ $self->manager->state->expire_session_id( $self->id );
}
sub finalize {
my ($self, $response) = @_;
- $self->store->persist( $self->id, $response );
- $self->state->finalize( $self->id, $response );
+ $self->manager->store->store( $self->id, $self );
+ $self->manager->state->finalize( $self->id, $response );
}
1;
=back
-=head2 Session Data Storage
+=head2 Session Data Management
-These methods delegate to appropriate methods on the C<store>
-to manage your session data.
+These methods allows you to read and write the session data like
+Perl's normal hash. The operation is not synced to the storage until
+you call C<finalize> on it.
=over 4
=item B<remove ( $key )>
+=item B<keys>
+
=back
=head2 Session Lifecycle Management
=item B<finalize ( $response )>
This method should be called at the end of the response cycle. It
-will call the C<persist> method on the C<store> and the
+will call the C<store> method on the C<store> and the
C<expire_session_id> method on the C<state>, passing both of them
the session id. The C<$response> is expected to be a L<Plack::Response>
instance or an object with an equivalent interface.
sub get_session_id {
my ($self, $request) = @_;
- $self->extract( $request )
- ||
- $self->generate( $request )
-}
-
-sub get_session_id_from_request {
- my ($self, $request) = @_;
- $request->param( $self->session_key );
+ return $request->param( $self->session_key );
}
sub extract {
my ($self, $request) = @_;
- my $id = $self->get_session_id_from_request( $request );
+ my $id = $self->get_session_id( $request );
return unless defined $id;
$self->validate_session_id( $id )
=item B<get_session_id ( $request )>
-Given a C<$request> this will first attempt to extract the session,
-if the is expired or does not exist, it will then generate a new
-session. The C<$request> is expected to be a L<Plack::Request> instance
-or an object with an equivalent interface.
-
-=item B<get_session_id_from_request ( $request )>
-
This is the method used to extract the session id from a C<$request>.
Subclasses will often only need to override this method and the
C<finalize> method.
$self->expires( 0 );
}
-sub get_session_id_from_request {
+sub get_session_id {
my ($self, $request) = @_;
( $request->cookie( $self->session_key ) || return )->value;
}
}
sub fetch {
- my ($self, $session_id, $key) = @_;
- $self->_stash->{ $session_id }->{ $key }
+ my ($self, $session_id) = @_;
+ $self->_stash->{ $session_id };
}
sub store {
- my ($self, $session_id, $key, $data) = @_;
- $self->_stash->{ $session_id }->{ $key } = $data;
-}
-
-sub delete {
- my ($self, $session_id, $key) = @_;
- delete $self->_stash->{ $session_id }->{ $key };
+ my ($self, $session_id, $session) = @_;
+ $self->_stash->{ $session_id } = $session->dump;
}
sub cleanup {
delete $self->_stash->{ $session_id }
}
-sub persist {
- my ($self, $session_id, $response) = @_;
- ()
-}
-
-sub dump_session {
- my ($self, $session_id) = @_;
- $self->_stash->{ $session_id } || {};
-}
-
1;
__END__
=head2 Session Data Management
-These methods fetch data from the session storage. It can only fetch,
-store or delete a single key at a time.
+These methods fetch data from the session storage. It's designed to
+store or delete multiple keys at a time.
=over 4
-=item B<fetch ( $session_id, $key )>
-
-=item B<store ( $session_id, $key, $data )>
+=item B<fetch ( $session_id )>
-=item B<delete ( $session_id, $key )>
+=item B<store ( $session_id, $data )>
=back
=over 4
-=item B<persist ( $session_id, $response )>
-
-This method will perform any data persistence nessecary to maintain
-data across requests. This method is called by the L<Plack::Session>
-C<finalize> method. The C<$response> is expected to be a L<Plack::Response>
-instance or an object with an equivalent interface.
-
=item B<cleanup ( $session_id )>
This method is called by the L<Plack::Session> C<expire> method and
is used to remove any session data.
-=item B<dump_session ( $session_id )>
-
-This method is mostly for debugging purposes, it will always return
-a HASH ref, even if no data is actually being stored (in which case
-the HASH ref will be empty).
-
=back
=head1 BUGS
}
sub fetch {
- my ($self, $session_id, $key) = @_;
- my $cache = $self->cache->get($session_id);
- return unless $cache;
- return $cache->{ $key };
+ my ($self, $session_id ) = @_;
+ $self->cache->get($session_id);
}
sub store {
- my ($self, $session_id, $key, $data) = @_;
- my $cache = $self->cache->get($session_id);
- if ( !$cache ) {
- $cache = {$key => $data};
- }
- else {
- $cache->{$key} = $data;
- }
- $self->cache->set($session_id => $cache);
-}
-
-sub delete {
- my ($self, $session_id, $key) = @_;
- my $cache = $self->cache->get($session_id);
- return unless exists $cache->{$key};
-
- delete $cache->{ $key };
- $self->cache->set($session_id => $cache);
+ my ($self, $session_id, $session) = @_;
+ $self->cache->set($session_id => $session->dump);
}
sub cleanup {
$self->cache->remove($session_id);
}
-sub dump_session {
- my ($self, $session_id) = @_;
- $self->cache->get( $session_id ) || {};
-}
-
1;
__END__
}
sub fetch {
- my ($self, $session_id, $key) = @_;
- my $store = $self->_deserialize( $session_id );
- return unless exists $store->{ $key };
- return $store->{ $key };
+ my ($self, $session_id) = @_;
+ return $self->_deserialize( $session_id );
}
sub store {
- my ($self, $session_id, $key, $data) = @_;
- my $store = $self->_deserialize( $session_id );
- $store->{ $key } = $data;
- $self->_serialize( $session_id, $store );
-}
-
-sub delete {
- my ($self, $session_id, $key) = @_;
- my $store = $self->_deserialize( $session_id );
- return unless exists $store->{ $key };
- delete $store->{ $key };
- $self->_serialize( $session_id, $store );
+ my ($self, $session_id, $session) = @_;
+ $self->_serialize( $session_id, $session->dump );
}
sub cleanup {
$self->deserializer->( $file_path );
}
-sub dump_session {
- my ($self, $session_id) = @_;
- my $file_path = $self->_get_session_file_path( $session_id );
- return {} unless -f $file_path;
- $self->deserializer->( $file_path );
-}
-
-
1;
__END__
sub new { bless {} => shift }
sub fetch {}
sub store {}
-sub delete {}
sub cleanup {}
-sub persist {}
-
-sub dump_session { +{} }
1;
use Plack::Session;
use Plack::Session::State;
use Plack::Session::Store::Null;
+use Plack::Middleware::Session;
my $storage = Plack::Session::Store::Null->new;
my $state = Plack::Session::State->new;
+my $m = Plack::Middleware::Session->new(store => $storage, state => $state);
my $request_creator = sub {
open my $in, '<', \do { my $d };
my $env = {
{
my $r = $request_creator->();
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
ok($s->id, '... got a session id');
$s->set( foo => 'bar' );
} '... set the value successfully in session';
- ok(!$s->get('foo'), '... still no value stored in foo for session (null store)');
+ is($s->get('foo'), 'bar', 'No store, but session works in the session lifetime');
lives_ok {
$s->remove('foo');
use Test::More;
use Test::Exception;
+use Plack::Middleware::Session;
sub run_all_tests {
my %params = @_;
response_test
]};
+ my $m = Plack::Middleware::Session->new(state => $state, store => $storage);
+
$response_test = sub {
my ($response, $session_id, $check_expired) = @_;
};
{
my $r = $request_creator->();
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
push @sids, $s->id;
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[0] ), { foo => 'bar', bar => 'baz' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { foo => 'bar', bar => 'baz' }, '... got the session dump we expected');
$response_test->( $resp, $sids[0] );
}
{
my $r = $request_creator->();
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
push @sids, $s->id;
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[1] ), { foo => 'baz' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { foo => 'baz' }, '... got the session dump we expected');
$response_test->( $resp, $sids[1] );
}
{
my $r = $request_creator->({ plack_session => $sids[0] });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
is($s->id, $sids[0], '... got a basic session id');
is($s->get('foo'), 'bar', '... got the value for foo back successfully from session');
+
lives_ok {
$s->remove( 'foo' );
} '... removed the foo value successfully from session';
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[0] ), { bar => 'baz' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { bar => 'baz' }, '... got the session dump we expected');
$response_test->( $resp, $sids[0] );
}
{
my $r = $request_creator->({ plack_session => $sids[1] });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
is($s->id, $sids[1], '... got a basic session id');
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[1] ), { foo => 'baz' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { foo => 'baz' }, '... got the session dump we expected');
$response_test->( $resp, $sids[1] );
}
{
my $r = $request_creator->({ plack_session => $sids[0] });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
is($s->id, $sids[0], '... got a basic session id');
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[0] ), { bar => 'baz', baz => 'gorch' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { bar => 'baz', baz => 'gorch' }, '... got the session dump we expected');
$response_test->( $resp, $sids[0] );
}
{
my $r = $request_creator->({ plack_session => $sids[0] });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
is($s->get('bar'), 'baz', '... got the bar value back successfully from session');
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[0] ), {}, '... got the session dump we expected');
+ is_deeply( $s->dump, {}, '... got the session dump we expected');
$response_test->( $resp, $sids[0], 1 );
}
{
my $r = $request_creator->({ plack_session => $sids[0] });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
push @sids, $s->id;
isnt($s->id, $sids[0], 'expired ... got a new session id');
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[2] ), {}, '... got the session dump we expected');
+ is_deeply( $s->dump, {}, '... got the session dump we expected');
$response_test->( $resp, $sids[2] );
}
{
my $r = $request_creator->({ plack_session => $sids[1] });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
+ my $s = Plack::Session->fetch_or_create($r, $m);
is($s->id, $sids[1], '... got a basic session id');
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $sids[1] ), { foo => 'baz' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { foo => 'baz' }, '... got the session dump we expected');
$response_test->( $resp, $sids[1] );
}
# wrong format session_id
my $r = $request_creator->({ plack_session => '../wrong' });
- my $s = Plack::Session->new(
- state => $state,
- store => $storage,
- request => $r,
- );
-
+ my $s = Plack::Session->fetch_or_create($r, $m);
isnt('../wrong' => $s->id, '... regenerate session id');
$s->finalize( $resp );
} '... finalized session successfully';
- is_deeply( $s->store->dump_session( $s->id ), { foo => 'baz' }, '... got the session dump we expected');
+ is_deeply( $s->dump, { foo => 'baz' }, '... got the session dump we expected');
$response_test->( $resp, $s );
}