no kidding sherlock
[catagits/Catalyst-Plugin-Session-State-Stash.git] / lib / Catalyst / Plugin / Session / State / Stash.pm
1 package Catalyst::Plugin::Session::State::Stash;
2 # ABSTRACT: Maintain session IDs using the stash
3
4 use Moose;
5 use 5.008;
6 use MRO::Compat;
7 use namespace::autoclean;
8
9 extends 'Catalyst::Plugin::Session::State';
10
11 our $VERSION = '0.15';
12
13 has _deleted_session_id => ( is => 'rw' );
14 has _prepared => ( is => 'rw' );
15
16 sub _stash_key_components {
17     my ($c) = @_;
18     my $config = $c->_session_plugin_config;
19     return ($config->{stash_delim}) ?
20         split $config->{stash_delim}, $config->{stash_key} :
21         $config->{stash_key};
22 }
23
24 sub _get_session {
25     my ($c) = @_;
26     # This turns the list of path components into a nested tree of hashrefs for obtaining info/storing in: 123/456 = {123}->{456}
27     my $ref = $c->stash;
28     $ref = ($ref->{$_} ||= {}) foreach $c->_stash_key_components;
29     $ref;
30 }
31
32 sub _set_session {
33     my ( $c,$key,$value) = @_;
34     $c->_get_session->{$key} = $value;
35 }
36
37 sub setup_session {
38     my $c = shift;
39
40     $c->maybe::next::method(@_);
41
42     $c->_session_plugin_config->{stash_key} ||= '_session';
43 }
44
45 sub prepare_action {
46     my $c = shift;
47     my $id = $c->get_session_id;
48     $c->_prepared(1);
49     if ( $id ) {
50         $c->sessionid( $id );
51     }
52     $c->maybe::next::method( @_ );
53 }
54
55 sub get_session_id {
56     my $c = shift;
57     if(!$c->_deleted_session_id and my $session = $c->_get_session) {
58         my $sid = $session->{id};
59         return $sid if $sid;
60     }
61     $c->maybe::next::method(@_);
62 }
63
64 sub set_session_id {
65     my ( $c, $sid ) = @_;
66     $c->_set_session(id => $sid);
67     $c->maybe::next::method($sid);
68 }
69
70 sub get_session_expires {
71     my $c = shift;
72     my $session = $c->_get_session;
73     defined $session->{expires} ? $session->{expires} : undef;
74 }
75
76 sub set_session_expires {
77     my ( $c, $expires ) = @_;
78     $c->_set_session(expires => time() + $expires);
79     $c->maybe::next::method($expires)
80 }
81
82 sub delete_session_id {
83     my ($c, $sid ) = @_;
84     $c->_deleted_session_id(1);
85     #Empty the tip
86     %{$c->_get_session} = ();
87     $c->maybe::next::method($sid);
88 }
89
90
91 1;
92 __END__
93
94 =pod
95
96 =head1 SYNOPSIS
97
98  use Catalyst qw/Session Session::State::Stash Session::Store::Foo/;
99
100 =head1 DESCRIPTION
101
102 An alternative state storage plugin that allows you some more flexibility in
103 dealing with session storage. This plugin loads and saves the session ID from
104 and to the stash.
105
106 =head1 METHODS
107
108 =over 4
109
110 =item delete_session_id
111
112 Deletes the session. Unfortunately I've been unable to squash a bug that will
113 stop you from opening a new session in the same execution, however.
114 Patches welcome!
115
116 =item get_session_id
117
118 Gets the current session id.
119
120 =item set_session_id
121
122 Sets the session id to the C<shift>.
123
124 =item get_session_expires
125
126 Gets when the current session expires.
127
128 =item set_session_expires
129
130 Sets how many seconds from now the session should expire.
131
132 =back
133
134 =head1 EXTENDED METHODS
135
136 =over 4
137
138 =item prepare_action
139
140 Loads the id off the stash.
141
142 =item setup_session
143
144 Defaults the C<stash_key> parameter to C<_session>.
145
146 =back
147
148 =head1 CONFIGURATION
149
150 =over 4
151
152 =item stash_key
153
154 The name of the hash key to use. Defaults to C<_session>.
155
156 =item stash_delim
157
158 If present, splits C<stash_key> at this character to nest. E.g. a C<delim> of '/'
159 and C<stash_key> of '123/456' will store it as $c->stash->{123}->{456}
160
161 =item expires
162
163 How long the session should last in seconds.
164
165 =back
166
167 For example, you could stick this in F<MyApp.pm>:
168
169   __PACKAGE__->config( 'Plugin::Session' => {
170      stash_key  => 'session_id',
171   });
172
173 =head1 BUGS
174
175 You can't delete a session then create a new one. If this is important to you,
176 patches welcome!
177
178 =for stopwords stateful
179
180 If you are writing a stateful web service with
181 L<Catalyst::Plugin::Server::XMLRPC>, you will probably only have to deal with
182 loading, as when saving, the ID will already be on the stash.
183
184 =head1 SEE ALSO
185
186 L<Catalyst>, L<Catalyst::Plugin::Session>, L<Catalyst::Plugin::Session::State>,
187 L<Catalyst::Plugin::Session::State::Cookie> (what you probably want).
188
189 =head1 CONTRIBUTORS
190
191 =begin :list
192
193 * This module is derived from L<Catalyst::Plugin::Session::State::Cookie> code.
194   Thanks to anyone who wrote code for that.
195
196 * Thanks to Kent Fredric for a patch for nested keys
197
198 =end :list
199
200 =cut