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