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