File Coverage

blib/lib/Catalyst/Plugin/Session/Store/Delegate.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Catalyst::Plugin::Session::Store::Delegate;
4              
5 1     1   31595 use Moose;
  0            
  0            
6             use MRO::Compat;
7             use namespace::clean -except => 'meta';
8              
9             extends 'Catalyst::Plugin::Session::Store';
10             with 'MooseX::Emulate::Class::Accessor::Fast';
11              
12             our $VERSION = "0.06";
13              
14             __PACKAGE__->mk_accessors(qw/_session_store_delegate/);
15              
16             sub session_store_model_name {
17             my $c = shift;
18             $c->_session_plugin_config->{model} || "Sessions";
19             }
20              
21             sub session_store_model {
22             my ( $c, $id ) = @_;
23              
24             # $id may be used in for e.g. keyspace partitioning
25             my $name = $c->session_store_model_name;
26             $c->model( $name, $id ) || die "Couldn't find a model named $name";
27             }
28              
29             sub session_store_delegate {
30             my ( $c, $id ) = @_;
31              
32             my $obj = $c->_session_store_delegate;
33              
34             unless($obj) {
35             unless ($id) {
36             $c->create_session_id_if_needed;
37             $id = $c->sessionid;
38             }
39              
40             $obj = $c->get_session_store_delegate($id);
41             $c->_session_store_delegate($obj)
42             }
43              
44             return $obj;
45             }
46              
47             sub get_session_store_delegate {
48             my ( $c, $id ) = @_;
49              
50             # $model is not necessarily a catalyst model, just something that can
51             # ->get_session_store_delegate($id)
52             my $model = $c->session_store_model($id);
53              
54             # allow methods or arbitrary code refs
55             my $method = $c->_session_plugin_config->{get_delegate} || "get_session_store_delegate";
56             $model->$method($id) || die "couldn't get delegate from model: $model with method: $method";
57             }
58              
59             sub _clear_session_instance_data {
60             my ( $c, @args ) = @_;
61             my $ret = $c->maybe::next::method(@args); # let the session plugin do it's thing
62            
63             my $delegate = $c->_session_store_delegate;
64             $c->_session_store_delegate(undef);
65             $c->finalize_session_delegate($delegate) if $delegate;
66              
67             return $ret;
68             }
69              
70             sub finalize_session_delegate {
71             my ( $c, $obj ) = @_;
72             $obj->flush;
73             }
74              
75             sub session_store_delegate_key_to_accessor {
76             my ( $self, $key, $operation, @args ) = @_;
77             my ( $field, $id ) = split(':', $key, 2);
78             return ( $field, ($operation eq "delete" ? (undef, @args) : @args ) ); # delete is effectively set to undef
79             # return ( join("_", $operation, $field) ); # for (get|set|delete)_foo type accessors
80             # return ( $operation, $field ) # for get("foo"), set("foo") type accessors
81             }
82              
83             sub get_session_data {
84             my ( $c, $key ) = @_;
85             my ( $accessor, @args ) = $c->session_store_delegate_key_to_accessor($key, "get");
86              
87             $c->session_store_delegate->$accessor(@args);
88             }
89              
90             sub store_session_data {
91             my ( $c, $key, $value ) = @_;
92             my ( $accessor, @args ) = $c->session_store_delegate_key_to_accessor($key, "set", $value);
93              
94             $c->session_store_delegate->$accessor(@args);
95             }
96              
97             sub delete_session_data {
98             my ( $c, $key ) = @_;
99             my ( $accessor, @args ) = $c->session_store_delegate_key_to_accessor($key, "delete");
100              
101             $c->session_store_delegate->$accessor(@args);
102             }
103              
104             sub delete_expired_sessions {
105             my $c = shift;
106              
107             my $model = $c->session_store_model;
108              
109             if ( eval { $model->can("delete_expired_sessions") } ) {
110             $model->delete_expired_sessions;
111             }
112             }
113              
114             __PACKAGE__->meta->make_immutable;
115              
116             __PACKAGE__;
117              
118             __END__
119              
120             =pod
121              
122             =head1 NAME
123              
124             Catalyst::Plugin::Session::Store::Delegate - Delegate session storage to an
125             application model object.
126              
127             =head1 SYNOPSIS
128              
129             use Catalyst::Plugin::Session::Store::Delegate;
130              
131             =head1 DESCRIPTION
132              
133             This store plugins makes delegating session storage to a first class object
134             model easy.
135              
136             =head1 THE MODEL
137              
138             The model is used to retrieve the delegate object for a given session ID.
139              
140             This is normally something like DBIC's resultset object.
141              
142             The model must respond to the C<get_delegate> method or closure in the sesion
143             config hash (defaults to C<get_session_store_delegate>).
144              
145             An object B<must always> be returned from this method, even if it means
146             autovivifying. The object may optimize and create itself lazily in the actual
147             store only when ->store methods are actually called.
148              
149             =head1 THE DELEGATE
150              
151             A single delegate belongs to a single session ID. It provides storage space for
152             arbitrary fields.
153              
154             The delegate object must respond to method calls as per the
155             C<session_store_delegate_key_to_accessor> method's return values.
156              
157             Typically this means responding to $obj->$field type accessors.
158              
159             If necessary, the delegate should maintain an internal reference count of the
160             stored fields, so that it can garbage collect itself when all fields have been
161             deleted.
162              
163             The fields are arbitrary, and are goverend by the various session plugins.
164              
165             The basic keys that must be supported are:
166              
167             =over 4
168              
169             =item expires
170              
171             A timestamp indicating when the session will expire.
172              
173             If a store so chooses it may clean up session data after this timestamp, even
174             without being told to delete.
175              
176             =item session
177              
178             The main session data hash.
179              
180             Might not be used, if only C<flash> exists.
181              
182             =item flash
183              
184             A hash much like the main session data hash, which can be created and deleted
185             multiple times per session, as required.
186              
187             =back
188              
189             The delegate must also respond to the C<flush> method which is used to tell the
190             store delegate that no more set/get/delete methods will be invoked on it.
191              
192             =head1 METHODS
193              
194             =over 4
195              
196             =item session_store_delegate_key_to_accessor $key, $operation
197              
198             This method implements the various calling conventions. It accepts a key and an
199             operation name (C<get>, C<set> or C<delete>), and must return a method (could
200             be a string or a code reference), and an optional list of arguments that will
201             be invoked on the delegate.
202              
203             The default version splits $key on the first colon, extracting the field name
204             and the ID. It then returns the unaltered field name, and if the operation is
205             'delete' also provides the extra argument C<undef>. This works with accessor
206             semantics like these:
207              
208             $obj->foo;
209             $obj->foo("bar");
210             $obj->foo(undef);
211              
212             To facilitate a convention like
213            
214             $obj->get_foo;
215             $obj->set_foo("bar");
216             $obj->delete_foo;
217              
218             or
219              
220             $obj->get("foo");
221             $obj->set("foo", "bar");
222             $obj->delete("foo");
223              
224             simply override this method. You may look in the source of this module to find
225             commented out versions which should help you.
226              
227             =item session_store_delegate
228              
229             This method returns the delegate, which may be cached in C<$c>.
230              
231             =item get_session_store_delegate $id
232              
233             This method should get the delegate object for a given ID. See L</"THE MODEL">
234             for more details.
235              
236             =item session_store_model
237              
238             This method should return the model that will provide the delegate object.The
239             default implementation will simply return
240             C<< $c->model( $c->session_store_model_name ) >>.
241              
242             =item session_store_model_name
243              
244             Returns C<< $c->config->{session}{model_name} || "Sessions" >>.
245              
246             =item finalize_session_delegate $delegate
247              
248             Invokes the C<flush> method on the delegate. May be overridden if that behavior
249             is inappropriate.
250              
251             =item get_session_data $key
252              
253             =item store_session_data $key, $value
254              
255             =item delete_session_data $key
256              
257             These methods translate the store API into the delegate API using
258             C<session_store_delegate_key_to_accessor>.
259              
260             =back
261              
262             =cut
263              
264             =head1 AUTHORS
265              
266             Yuval Kogman, C<nothingmuch@woobling.org>
267              
268             Tomas Doran, (t0m) C<bobtfish@bobtfish.net> (current maintainer)
269              
270             =head1 COPYRIGHT & LICENSE
271              
272             Copyright (c) 2006 the aforementioned authors.
273             This program is free software; you can redistribute
274             it and/or modify it under the same terms as Perl itself.
275