Преглед изворни кода

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 година
родитељ
комит
68e2076981
1 измењених фајлова са 57 додато и 22 уклоњено
  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;
 
     /**
+     * @var bool
+     */
+    protected $cursorNeedsAdvancing = true;
+
+    /**
+     * @var mixed
+     */
+    private $current = null;
+
+    /**
+     * @var mixed
+     */
+    private $key = null;
+
+    /**
+     * @var mixed
+     */
+    private $valid = false;
+
+    /**
      * @var int
      */
     protected $position = 0;
@@ -118,16 +138,7 @@ abstract class AbstractCursor
      */
     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()
     {
-        if (! $this->startedIterating) {
-            return null;
-        }
-
-        return $this->ensureIterator()->key();
+        return $this->key;
     }
 
     /**
@@ -157,11 +164,15 @@ abstract class AbstractCursor
             $this->ensureIterator();
             $this->startedIterating = true;
         } else {
-            $this->ensureIterator()->next();
+            if ($this->cursorNeedsAdvancing) {
+                $this->ensureIterator()->next();
+            }
+
+            $this->cursorNeedsAdvancing = true;
             $this->position++;
         }
 
-        return $this->current();
+        return $this->storeIteratorState();
     }
 
     /**
@@ -177,6 +188,7 @@ abstract class AbstractCursor
         $this->startedIterating = true;
         $this->position = 0;
         $this->ensureIterator()->rewind();
+        $this->storeIteratorState();
     }
 
     /**
@@ -186,11 +198,7 @@ abstract class AbstractCursor
      */
     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->cursor = null;
         $this->iterator = null;
+        $this->storeIteratorState();
     }
 
     /**
@@ -384,4 +393,30 @@ abstract class AbstractCursor
     {
         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;
+    }
 }