From 158373dcdbf01cb75c9d57eb66305b55c6e092c4 Mon Sep 17 00:00:00 2001
From: Kyle M Hall <kyle@bywatersolutions.com>
Date: Tue, 17 Feb 2015 10:10:28 -0500
Subject: [PATCH] Bug 13719 - Make Koha::Objects store list of resultant objects on an as needed basis

We can both simplify and improve the functioning of Koha::Objects by
removing out reliance on DBIC for set iteration ( first(), next(),
reset(), etc ). The problem is that DBIC destroys and refetches
results every time reset() is called. For example, take the following
code:

my $borrowers = Koha::Borrowers->search({ firstname => 'Kyle' }).
my $kyle1 = $borrowers->next();
$borrowers->reset();
my $kyle2 = $borrowers->next();

In this case, we would expect $kyle1 and $kyle2 to refer to the exact
same object in memory, but they do *not*. This is simply a limitation of
DBIx::Class.

However, by handling this issue ourselves, we not only solve the
problem, but I believe we also reduce the complexity of our code.

This is all accomplished without changing the external behavior of the
Koha::Objects module.

Test Plan:
1) Apply this patch
2) prove t/db_dependent/Borrowers.t
---
 Koha/Objects.pm |   45 +++++++++++++++++++++++++++++++++++++--------
 1 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/Koha/Objects.pm b/Koha/Objects.pm
index 6b3100a..701e535 100644
--- a/Koha/Objects.pm
+++ b/Koha/Objects.pm
@@ -54,6 +54,8 @@ sub new {
     my ($class) = @_;
     my $self = {};
 
+    $self->{_iterator} = 0;
+
     bless( $self, $class );
 }
 
@@ -67,6 +69,8 @@ sub _new_from_dbic {
     my ( $class, $resultset ) = @_;
     my $self = { _resultset => $resultset };
 
+    $self->{_iterator} = 0;
+
     bless( $self, $class );
 }
 
@@ -136,14 +140,27 @@ Returns undef if there are no more objects to return.
 sub next {
     my ( $self ) = @_;
 
-    my $result = $self->_resultset()->next();
-    return unless $result;
+    my $object = $self->_objects()->[ $self->{_iterator}++ ];
 
-    my $object = $self->object_class()->_new_from_dbic( $result );
+    $self->reset() unless $object;
 
     return $object;
 }
 
+=head3 Koha::Objects->first();
+
+my $object = Koha::Objects->first();
+
+Returns the first object that is part of this set.
+
+=cut
+
+sub first {
+    my ( $self ) = @_;
+
+    return $self->_objects()->[0];
+}
+
 =head3 Koha::Objects->reset();
 
 Koha::Objects->reset();
@@ -156,7 +173,7 @@ with the first object in a set.
 sub reset {
     my ( $self ) = @_;
 
-    $self->_resultset()->reset();
+    $self->{_iterator} = 0;
 
     return $self;
 }
@@ -172,11 +189,23 @@ Returns an arrayref of the objects in this set.
 sub as_list {
     my ( $self ) = @_;
 
-    my @dbic_rows = $self->_resultset()->all();
+    my $objects = $self->_objects();
+
+    return wantarray ? @$objects : $objects;
+}
+
+=head3 Koha::Objects->_objects
+
+Returns an arrayref of all the objects that are part of this Objects set
+
+=cut
+
+sub _objects {
+    my ( $self ) = @_;
 
-    my @objects = $self->_wrap(@dbic_rows);
+    $self->{_objects} ||= $self->_wrap( $self->_resultset()->all() );
 
-    return wantarray ? @objects : \@objects;
+    return $self->{_objects};
 }
 
 =head3 Koha::Objects->_wrap
@@ -190,7 +219,7 @@ sub _wrap {
 
     my @objects = map { $self->object_class()->_new_from_dbic( $_ ) } @dbic_rows;
 
-    return @objects;
+    return wantarray ? @objects : \@objects;;
 }
 
 =head3 Koha::Objects->_resultset
-- 
1.7.2.5