Sfoglia il codice sorgente

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 9 anni fa
parent
commit
68e2076981
1 ha cambiato i file con 57 aggiunte e 22 eliminazioni
  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;
+    }
 }