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