Refactored Middleware::Session to call ->state and ->store inside more
[catagits/Web-Session.git] / lib / Plack / Middleware / Session.pm
index 6a8fac3..2d11bbc 100644 (file)
@@ -5,7 +5,6 @@ use warnings;
 our $VERSION   = '0.03';
 our $AUTHORITY = 'cpan:STEVAN';
 
-use Plack::Session;
 use Plack::Request;
 use Plack::Response;
 use Plack::Util;
@@ -22,11 +21,11 @@ use Plack::Util::Accessor qw(
 sub prepare_app {
     my $self = shift;
 
-    $self->session_class( 'Plack::Session' ) unless $self->session_class;
-    $self->state( 'Cookie' )                 unless $self->state;
-
+    $self->state( 'Cookie' ) unless $self->state;
     $self->state( $self->inflate_backend('Plack::Session::State', $self->state) );
     $self->store( $self->inflate_backend('Plack::Session::Store', $self->store) );
+
+    Plack::Util::load_class($self->session_class) if $self->session_class;
 }
 
 sub inflate_backend {
@@ -41,29 +40,83 @@ sub inflate_backend {
     Plack::Util::load_class(@class)->new();
 }
 
-sub fetch_or_create_session {
-    my($self, $req) = @_;
-    $self->session_class->fetch_or_create($req, $self);
-}
-
 sub call {
     my $self = shift;
     my $env  = shift;
 
-    my $session = $self->fetch_or_create_session(Plack::Request->new($env));
+    my $request = Plack::Request->new($env);
+
+    my($id, $session) = $self->get_session($request);
+    if ($id && $session) {
+        $env->{'psgix.session'} = $session;
+    } else {
+        $id = $self->generate_id($request);
+        $env->{'psgix.session'} = {};
+    }
+
+    $env->{'psgix.session.options'} = { id => $id };
 
-    $env->{'psgix.session'} = $env->{'plack.session'} = $session;
+    if ($self->session_class) {
+        $env->{'plack.session'} = $self->session_class->new($env);
+    }
 
     my $res = $self->app->($env);
     $self->response_cb($res, sub {
         my $res = Plack::Response->new(@{$_[0]});
-        $env->{'psgix.session'}->finalize($res);
+        $self->finalize($request, $res);
         $res = $res->finalize;
         $_[0]->[0] = $res->[0];
         $_[0]->[1] = $res->[1];
     });
 }
 
+sub get_session {
+    my($self, $request) = @_;
+
+    my $id = $self->state->extract($request) or return;
+    my $session = $self->store->fetch($id)   or return;
+
+    return ($id, $session);
+}
+
+sub generate_id {
+    my($self, $request) = @_;
+    $self->state->generate($request);
+}
+
+sub commit {
+    my($self, $session, $options) = @_;
+    if ($options->{expire}) {
+        $self->store->cleanup($options->{id});
+    } else {
+        $self->store->store($options->{id}, $session);
+    }
+}
+
+sub finalize {
+    my($self, $request, $response) = @_;
+
+    my $session = $request->env->{'psgix.session'};
+    my $options = $request->env->{'psgix.session.options'};
+
+    $self->commit($session, $options) unless $options->{no_store};
+    if ($options->{expire}) {
+        $self->expire_session($options->{id}, $response, $session, $options);
+    } else {
+        $self->save_state($options->{id}, $response, $session, $options);
+    }
+}
+
+sub expire_session {
+    my($self, $id, $res, $session, $options) = @_;
+    $self->state->expire_session_id($options->{id}, $res, $options);
+}
+
+sub save_state {
+    my($self, $id, $res, $session, $options) = @_;
+    $self->state->finalize($id, $res, $options);
+}
+
 1;
 
 __END__
@@ -80,10 +133,11 @@ Plack::Middleware::Session - Middleware for session management
 
   my $app = sub {
       my $env = shift;
+      my $session = $env->{'psgix.session'};
       return [
           200,
           [ 'Content-Type' => 'text/plain' ],
-          [ 'Hello, your Session ID is ' . $env->{'psgix.session'}->id ]
+          [ "Hello, you've been here for ", $session->{counter}++, "th time!" ],
       ];
   };
 
@@ -106,16 +160,15 @@ default it will use cookies to keep session state and store data in
 memory. This distribution also comes with other state and store
 solutions. See perldoc for these backends how to use them.
 
-It should be noted that we store the current session in the
-C<psgix.session> key inside the C<$env> where you can access it
-as needed. Additionally, as of version 0.09, you can call the
-C<session> method of a L<Plack::Request> instance to fetch
-whatever is stored in C<psgix.session>.
+It should be noted that we store the current session as a hash
+reference in the C<psgix.session> key inside the C<$env> where you can
+access it as needed.
+
+B<NOTE:> As of version 0.04 the session is stored in C<psgix.session>
+instead of C<plack.session>.
 
-B<NOTE:> As of version 0.02 the session is stored in C<psgix.session>
-instead of C<plack.session>. We still keep a copy of it in
-C<plack.session>, but this is deprecated and will be removed
-in future versions.
+Also, if you set I<session_class> option (see below), we create a
+session object out of the hash reference in C<plack.session>.
 
 =head2 State
 
@@ -185,9 +238,10 @@ L<Plack::Session::Store::Cache>.
 
 =item I<session_class>
 
-This can be used to override the actual session class. It currently
-defaults to L<Plack::Session> but you can substitute any class which
-implements the same interface.
+This can be used to create an actual session object in
+C<plack.session> environment. Defaults to none, which means the
+session object is not created but you can set C<Plack::Session> to
+create an object for you.
 
 =back