b5d3958de629a6205eddaa9947ade3d91dbf738e
[catagits/Catalyst-Authentication-Store-DBIx-Class.git] / lib / Catalyst / Plugin / Authentication / Store / DBIx / Class / User.pm
1 package Catalyst::Plugin::Authentication::Store::DBIx::Class::User;
2
3 use strict;
4 use warnings;
5 use base qw/Catalyst::Plugin::Authentication::User/;
6 use base qw/Class::Accessor::Fast/;
7
8 BEGIN {
9     __PACKAGE__->mk_accessors(qw/config resultset _user _roles/);
10 }
11
12 sub new {
13     my ( $class, $config, $c) = @_;
14
15     my $self = {
16         resultset => $c->model($config->{'user_class'}),
17         config => $config,
18         _roles => undef,
19         _user => undef
20     };
21     
22     bless $self, $class;
23     
24
25     if (!exists($self->config->{'id_field'})) {
26         $self->config->{'id_field'} = 'id';
27     }
28     
29     ## if we have lazyloading turned on - we should not query the DB unless something gets read.
30     ## that's the idea anyway - still have to work out how to manage that - so for now we always force
31     ## lazyload to off.
32     $self->config->{lazyload} = 0;
33     
34 #    if (!$self->config->{lazyload}) {
35 #        return $self->load_user($authinfo, $c);
36 #    } else {
37 #        ## what do we do with a lazyload?
38 #        ## presumably this is coming out of session storage.  
39 #        ## use $authinfo to fill in the user in that case?
40 #    }
41
42     return $self;
43 }
44
45
46 sub load {
47     my ($self, $authinfo, $c) = @_;
48     
49     my $dbix_class_config = 0;
50     
51     if (exists($authinfo->{'dbix_class'})) {
52         $authinfo = $authinfo->{'dbix_class'};
53         $dbix_class_config = 1;
54     }
55     
56     ## User can provide an arrayref containing the arguments to search on the user class.
57     ## or even provide a prepared resultset, allowing maximum flexibility for user retreival.
58     ## these options are only available when using the dbix_class authinfo hash. 
59     if ($dbix_class_config && exists($authinfo->{'resultset'})) {
60         $self->_user($authinfo->{'resultset'}->first);
61     } elsif ($dbix_class_config && exists($authinfo->{'searchargs'})) {
62         $self->_user($self->resultset->search(@{$authinfo->{'searchargs'}})->first);    
63     } else {
64         ## merge the ignore fields array into a hash - so we can do an easy check while building the query
65         my %ignorefields = map { $_ => 1} @{$self->config->{'ignore_fields_in_find'}};                                    
66         my $searchargs = {};
67         
68         # now we walk all the fields passed in, and build up a search hash.
69         foreach my $key (grep {!$ignorefields{$_}} keys %{$authinfo}) {
70             if ($self->resultset->result_source->has_column($key)) {
71                 $searchargs->{$key} = $authinfo->{$key};
72             }
73         }
74         $self->_user($self->resultset->search($searchargs)->first);
75     }
76
77     if ($self->get_object) {
78         return $self;
79     } else {
80         return undef;
81     }
82     #$c->log->debug(dumper($self->{'user'}));
83
84 }
85
86 sub supported_features {
87     my $self = shift;
88
89     return {
90         session         => 1,
91         roles           => 1,
92     };
93 }
94
95
96 sub roles {
97     my ( $self ) = shift;
98     ## this used to load @wantedroles - but that doesn't seem to be used by the roles plugin, so I dropped it.
99
100     ## shortcut if we have already retrieved them
101     if (ref $self->_roles eq 'ARRAY') {
102         return(@{$self->_roles});
103     }
104     
105     my @roles = ();
106     if (exists($self->config->{'role_column'})) {
107         @roles = split /[ ,\|]+/, $self->get($self->config->{'role_column'});
108         $self->_roles(\@roles);
109     } elsif (exists($self->config->{'role_relation'})) {
110         my $relation = $self->config->{'role_relation'};
111         if ($self->_user->$relation->result_source->has_column($self->config->{'role_field'})) {
112             @roles = map { $_->get_column($self->config->{'role_field'}) } $self->_user->$relation->search(undef, { columns => [ $self->config->{'role_field'}]})->all();
113             $self->_roles(\@roles);
114         } else {
115             Catalyst::Exception->throw("role table does not have a column called " . $self->config->{'role_field'});
116         }
117     } else {
118         Catalyst::Exception->throw("user->roles accessed, but no role configuration found");
119     }
120
121     return @{$self->_roles};
122 }
123
124 sub for_session {
125     my $self = shift;
126     
127     return $self->get($self->config->{'id_field'});
128 }
129
130 sub from_session {
131     my ($self, $frozenuser, $c) = @_;
132     
133     # this could be a lot better.  But for now it just assumes $frozenuser is an id and uses find_user
134     # XXX: hits the database on every request?  Not good...
135     return $self->load( { $self->config->{'id_field'} => $frozenuser }, $c);
136 }
137
138 sub get {
139     my ($self, $field) = @_;
140     
141     if ($self->_user->can($field)) {
142         return $self->_user->$field;
143     } else {
144         return undef;
145     }
146 }
147
148 sub get_object {
149     my $self = shift;
150     
151     return $self->_user;
152 }
153
154 sub obj {
155     my $self = shift;
156     
157     return $self->get_object;
158 }
159
160 sub AUTOLOAD {
161     my $self = shift;
162     (my $method) = (our $AUTOLOAD =~ /([^:]+)$/);
163     return if $method eq "DESTROY";
164
165     $self->_user->$method(@_);
166 }
167
168 1;
169 __END__
170
171 =head1 NAME
172
173 Catalyst::Plugin::Authentication::Store::DBIx::Class::User - The backing user
174 class for the Catalyst::Plugin::Authentication::Store::DBIx::Class storage
175 module.
176
177 =head1 VERSION
178
179 This documentation refers to version 0.02.
180
181 =head1 SYNOPSIS
182
183 Internal - not used directly, please see
184 L<Catalyst::Plugin::Authentication::Store::DBIx::Class> for details on how to
185 use this module. If you need more information than is present there, read the
186 source.
187
188                 
189
190 =head1 DESCRIPTION
191
192 The Catalyst::Plugin::Authentication::Store::DBIx::Class::User class implements user storage
193 connected to an underlying DBIx::Class schema object.
194
195 =head1 SUBROUTINES / METHODS
196
197 =head2 new 
198
199 Constructor.
200
201 =head2 load ( $authinfo, $c ) 
202
203 Retrieves a user from storage using the information provided in $authinfo.
204
205 =head2 supported_features
206
207 Indicates the features supported by this class.  These are currently Roles and Session.
208
209 =head2 roles
210
211 Returns an array of roles associated with this user, if roles are configured for this user class.
212
213 =head2 for_session
214
215 Returns a serialized user for storage in the session.  Currently, this is the value of the field
216 specified by the 'id_field' config variable.
217
218 =head2 from_session
219
220 Revives a serialized user from storage in the session.  Currently, this uses the serialized data as the
221 value of the 'id_field' config variable.
222
223 =head2 get ( $fieldname )
224
225 Returns the value of $fieldname for the user in question.  Roughly translates to a call to 
226 the DBIx::Class::Row's get_column( $fieldname ) routine.
227
228 =head2 get_object 
229
230 Retrieves the DBIx::Class object that corresponds to this user
231
232 =head2 obj (method)
233
234 Synonym for get_object
235
236 =head1 BUGS AND LIMITATIONS
237
238 None known currently, please email the author if you find any.
239
240 =head1 AUTHOR
241
242 Jason Kuri (jayk@cpan.org)
243
244 =head1 LICENSE
245
246 Copyright (c) 2007 the aforementioned authors. All rights
247 reserved. This program is free software; you can redistribute
248 it and/or modify it under the same terms as Perl itself.
249
250 =cut