Browse Source

Store the state of an iterator in AbstractCursor

This allows us to advance the underlying iterator without losing access to the current element.
Andreas Braun 10 years ago
parent
commit
68e2076981
1 changed files with 57 additions and 22 deletions
  1. 57 22
      lib/Alcaeus/MongoDbAdapter/AbstractCursor.php

+ 57 - 22
lib/Alcaeus/MongoDbAdapter/AbstractCursor.php

@@ -67,6 +67,26 @@ abstract class AbstractCursor
     protected $startedIterating = false;
     protected $startedIterating = false;
 
 
     /**
     /**
+     * @var bool
+     */
+    protected $cursorNeedsAdvancing = true;
+
+    /**
+     * @var mixed
+     */
+    private $current = null;
+
+    /**
+     * @var mixed
+     */
+    private $key = null;
+
+    /**
+     * @var mixed
+     */
+    private $valid = false;
+
+    /**
      * @var int
      * @var int
      */
      */
     protected $position = 0;
     protected $position = 0;
@@ -118,16 +138,7 @@ abstract class AbstractCursor
      */
      */
     public function current()
     public function current()
     {
     {
-        if (! $this->startedIterating) {
-            return null;
-        }
-
-        $document = $this->ensureIterator()->current();
-        if ($document !== null) {
-            $document = TypeConverter::toLegacy($document);
-        }
-
-        return $document;
+        return $this->current;
     }
     }
 
 
     /**
     /**
@@ -137,11 +148,7 @@ abstract class AbstractCursor
      */
      */
     public function key()
     public function key()
     {
     {
-        if (! $this->startedIterating) {
-            return null;
-        }
-
-        return $this->ensureIterator()->key();
+        return $this->key;
     }
     }
 
 
     /**
     /**
@@ -157,11 +164,15 @@ abstract class AbstractCursor
             $this->ensureIterator();
             $this->ensureIterator();
             $this->startedIterating = true;
             $this->startedIterating = true;
         } else {
         } else {
-            $this->ensureIterator()->next();
+            if ($this->cursorNeedsAdvancing) {
+                $this->ensureIterator()->next();
+            }
+
+            $this->cursorNeedsAdvancing = true;
             $this->position++;
             $this->position++;
         }
         }
 
 
-        return $this->current();
+        return $this->storeIteratorState();
     }
     }
 
 
     /**
     /**
@@ -177,6 +188,7 @@ abstract class AbstractCursor
         $this->startedIterating = true;
         $this->startedIterating = true;
         $this->position = 0;
         $this->position = 0;
         $this->ensureIterator()->rewind();
         $this->ensureIterator()->rewind();
+        $this->storeIteratorState();
     }
     }
 
 
     /**
     /**
@@ -186,11 +198,7 @@ abstract class AbstractCursor
      */
      */
     public function valid()
     public function valid()
     {
     {
-        if (! $this->startedIterating) {
-            return false;
-        }
-
-        return $this->ensureIterator()->valid();
+        return $this->valid;
     }
     }
 
 
     /**
     /**
@@ -375,6 +383,7 @@ abstract class AbstractCursor
         $this->startedIterating = false;
         $this->startedIterating = false;
         $this->cursor = null;
         $this->cursor = null;
         $this->iterator = null;
         $this->iterator = null;
+        $this->storeIteratorState();
     }
     }
 
 
     /**
     /**
@@ -384,4 +393,30 @@ abstract class AbstractCursor
     {
     {
         return ['batchSize', 'connection', 'iterator', 'ns', 'optionNames', 'position', 'startedIterating'];
         return ['batchSize', 'connection', 'iterator', 'ns', 'optionNames', 'position', 'startedIterating'];
     }
     }
+
+    /**
+     * Stores the current cursor element.
+     *
+     * This is necessary because hasNext() might advance the iterator but we still
+     * need to be able to return the current object.
+     */
+    private function storeIteratorState()
+    {
+        if (! $this->startedIterating) {
+            $this->current = null;
+            $this->key = null;
+            $this->valid = false;
+            return null;
+        }
+
+        $this->current = $this->ensureIterator()->current();
+        $this->key = $this->ensureIterator()->key();
+        $this->valid = $this->ensureIterator()->valid();
+
+        if ($this->current !== null) {
+            $this->current = TypeConverter::toLegacy($this->current);
+        }
+
+        return $this->current;
+    }
 }
 }