Commit | Line | Data |
6f28db48 |
1 | package Plack::Session::Store::DBI; |
2 | use strict; |
3 | use warnings; |
4 | |
5 | # XXX Is there a notion of auto-expiry? |
6 | |
7 | our $VERSION = '0.10'; |
8 | our $AUTHORITY = 'cpan:STEVAN'; |
9 | |
6f28db48 |
10 | use MIME::Base64 (); |
11 | use Storable (); |
12 | |
13 | use parent 'Plack::Session::Store'; |
14 | |
15 | use Plack::Util::Accessor qw[ dbh table_name serializer deserializer ]; |
16 | |
17 | sub new { |
18 | my ($class, %params) = @_; |
19 | |
7c2aa126 |
20 | if (! $params{dbh} ) { |
21 | die "DBI instance was not available in the argument list"; |
6f28db48 |
22 | } |
23 | |
24 | $params{table_name} ||= 'sessions'; |
25 | $params{serializer} ||= |
26 | sub { MIME::Base64::encode_base64( Storable::nfreeze( $_[0] ) ) }; |
27 | $params{deserializer} ||= |
28 | sub { Storable::thaw( MIME::Base64::decode_base64( $_[0] ) ) }; |
29 | |
30 | my $self = bless { %params }, $class; |
6f28db48 |
31 | return $self; |
32 | } |
33 | |
39d453e4 |
34 | sub _dbh { |
35 | shift->{dbh}; |
6f28db48 |
36 | } |
37 | |
38 | sub fetch { |
39 | my ($self, $session_id) = @_; |
39d453e4 |
40 | my $table_name = $self->{table_name}; |
41 | my $dbh = $self->_dbh; |
42 | my $sth = $dbh->prepare_cached("SELECT session_data FROM $table_name WHERE id = ?"); |
6f28db48 |
43 | $sth->execute( $session_id ); |
44 | my ($data) = $sth->fetchrow_array(); |
45 | $sth->finish; |
46 | return $data ? $self->deserializer->( $data ) : (); |
47 | } |
48 | |
49 | sub store { |
50 | my ($self, $session_id, $session) = @_; |
39d453e4 |
51 | my $table_name = $self->{table_name}; |
6f28db48 |
52 | |
53 | # XXX To be honest, I feel like there should be a transaction |
54 | # call here.... but Catalyst didn't have it, so I'm not so sure |
55 | |
39d453e4 |
56 | my $sth = $self->_dbh->prepare_cached("SELECT 1 FROM $table_name WHERE id = ?"); |
6f28db48 |
57 | $sth->execute($session_id); |
58 | |
59 | # need to fetch. on some DBD's execute()'s return status and |
60 | # rows() is not reliable |
61 | my ($exists) = $sth->fetchrow_array(); |
62 | |
63 | $sth->finish; |
64 | |
39d453e4 |
65 | if ($exists) { |
66 | my $sth = $self->_dbh->prepare_cached("UPDATE $table_name SET session_data = ? WHERE id = ?"); |
67 | $sth->execute( $self->serializer->($session), $session_id ); |
68 | } |
69 | else { |
70 | my $sth = $self->_dbh->prepare_cached("INSERT INTO $table_name (id, session_data) VALUES (?, ?)"); |
71 | $sth->execute( $session_id , $self->serializer->($session) ); |
72 | } |
73 | |
6f28db48 |
74 | } |
75 | |
76 | sub remove { |
77 | my ($self, $session_id) = @_; |
39d453e4 |
78 | my $table_name = $self->{table_name}; |
79 | my $sth = $self->_dbh->prepare_cached("DELETE FROM $table_name WHERE id = ?"); |
6f28db48 |
80 | $sth->execute( $session_id ); |
81 | $sth->finish; |
82 | } |
83 | |
84 | 1; |
85 | |
86 | __END__ |
87 | |
7c2aa126 |
88 | =head1 NAME |
89 | |
90 | Plack::Session::Store::DBI - DBI-based session store |
91 | |
92 | =head1 SYNOPSIS |
93 | |
94 | use Plack::Builder; |
95 | use Plack::Middleware::Session; |
96 | use Plack::Session::Store::DBI; |
97 | |
98 | my $app = sub { |
99 | return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello Foo' ] ]; |
100 | }; |
101 | |
102 | builder { |
103 | enable 'Session', |
104 | store => Plack::Session::Store::DBI->new( |
105 | dbh => DBI->connect( @connect_args ) |
106 | ); |
107 | $app; |
108 | }; |
109 | |
110 | # with custom serializer/deserializer |
111 | |
112 | builder { |
113 | enable 'Session', |
0e9a58b8 |
114 | store => Plack::Session::Store::DBI->new( |
7c2aa126 |
115 | dbh => DBI->connect( @connect_args ) |
116 | # YAML takes it's args the opposite order |
117 | serializer => sub { YAML::DumpFile( reverse @_ ) }, |
118 | deserializer => sub { YAML::LoadFile( @_ ) }, |
119 | ); |
120 | $app; |
121 | }; |
122 | |
123 | =head1 DESCRIPTION |
124 | |
125 | This implements a DBI based storage for session data. By |
126 | default it will use L<Storable> and L<MIME::Base64> to serialize and |
127 | deserialize the data, but this can be configured easily. |
128 | |
129 | This is a subclass of L<Plack::Session::Store> and implements |
c4b2fb0e |
130 | its full interface. |
7c2aa126 |
131 | |
132 | =head1 SESSION TABLE SCHEMA |
133 | |
6f28db48 |
134 | Your session table must have at least the following schema structure: |
135 | |
136 | CREATE TABLE sessions ( |
137 | id CHAR(72) PRIMARY KEY, |
138 | session_data TEXT |
139 | ); |
140 | |
141 | Note that MySQL TEXT fields only store 64KB, so if your session data |
142 | will exceed that size you'll want to move to MEDIUMTEXT, MEDIUMBLOB, |
143 | or larger. |
6f28db48 |
144 | |
145 | =head1 AUTHORS |
146 | |
147 | Many aspects of this module were partially based upon Catalyst::Plugin::Session::Store::DBI |
148 | |
7c2aa126 |
149 | Daisuke Maki |
150 | |
151 | =head1 COPYRIGHT AND LICENSE |
152 | |
153 | Copyright 2009, 2010 Daisuke Maki C<< <daisuke@endeworks.jp> >> |
154 | |
155 | This library is free software; you can redistribute it and/or modify |
156 | it under the same terms as Perl itself. |
157 | =cut |
158 | |