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