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