Fix calling User->can() as a class method. RT#90715
[catagits/Catalyst-Authentication-Store-DBIx-Class.git] / lib / Catalyst / Authentication / Store / DBIx / Class / User.pm
index 5c5c93f..18282a4 100644 (file)
@@ -72,9 +72,11 @@ sub load {
     }
 
     ## User can provide an arrayref containing the arguments to search on the user class.
-    ## or even provide a prepared resultset, allowing maximum flexibility for user retreival.
+    ## or even provide a prepared resultset, allowing maximum flexibility for user retrieval.
     ## these options are only available when using the dbix_class authinfo hash.
-    if ($dbix_class_config && exists($authinfo->{'resultset'})) {
+    if ($dbix_class_config && exists($authinfo->{'result'})) {
+       $self->_user($authinfo->{'result'});
+    } elsif ($dbix_class_config && exists($authinfo->{'resultset'})) {
         $self->_user($authinfo->{'resultset'}->first);
     } elsif ($dbix_class_config && exists($authinfo->{'searchargs'})) {
         $self->_user($self->resultset->search(@{$authinfo->{'searchargs'}})->first);
@@ -163,7 +165,14 @@ sub for_session {
     #return $frozenuser;
 
     my %userdata = $self->_user->get_columns();
-    return \%userdata;
+
+    # If use_userdata_from_session is set, then store all of the columns of the user obj in the session
+    if (exists($self->config->{'use_userdata_from_session'}) && $self->config->{'use_userdata_from_session'} != 0) {
+        return \%userdata;
+    } else { # Otherwise, we just need the PKs for load() to use.
+        my %pk_fields = map { ($_ => $userdata{$_}) } @{ $self->config->{id_field} };
+        return \%pk_fields;
+    }
 }
 
 sub from_session {
@@ -180,7 +189,17 @@ sub from_session {
 #
 ## if use_userdata_from_session is defined in the config, we fill in the user data from the session.
     if (exists($self->config->{'use_userdata_from_session'}) && $self->config->{'use_userdata_from_session'} != 0) {
-        my $obj = $self->resultset->new_result({ %$frozenuser });
+
+        # We need to use inflate_result here since we -are- inflating a
+        # result object from cached data, not creating a fresh one.
+        # Components such as EncodedColumn wrap new() to ensure that a
+        # provided password is hashed on the way in, and re-running the
+        # hash function on data being restored is expensive and incorrect.
+
+        my $class = $self->resultset->result_class;
+        my $source = $self->resultset->result_source;
+        my $obj = $class->inflate_result($source, { %$frozenuser });
+
         $obj->in_storage(1);
         $self->_user($obj);
         return $self;
@@ -242,7 +261,11 @@ sub can {
     my $self = shift;
     return $self->SUPER::can(@_) || do {
         my ($method) = @_;
-        if (my $code = $self->_user->can($method)) {
+        if (not ref $self) {
+            undef;
+        } elsif (not $self->_user) {
+            undef;
+        } elsif (my $code = $self->_user->can($method)) {
             sub { shift->_user->$code(@_) }
         } elsif (my $accessor =
             try { $self->_user->result_source->column_info($method)->{accessor} }) {
@@ -258,6 +281,8 @@ sub AUTOLOAD {
     (my $method) = (our $AUTOLOAD =~ /([^:]+)$/);
     return if $method eq "DESTROY";
 
+    return unless ref $self;
+
     if (my $code = $self->_user->can($method)) {
         return $self->_user->$code(@_);
     }
@@ -283,7 +308,7 @@ module.
 
 =head1 VERSION
 
-This documentation refers to version 0.1401.
+This documentation refers to version 0.1503.
 
 =head1 SYNOPSIS
 
@@ -363,11 +388,11 @@ that method (probably in your schema file)
 
 =head2 AUTOLOAD
 
-Delegates method calls to the underlieing user row.
+Delegates method calls to the underlying user row.
 
 =head2 can
 
-Delegates handling of the C<< can >> method to the underlieing user row.
+Delegates handling of the C<< can >> method to the underlying user row.
 
 =head1 BUGS AND LIMITATIONS