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