Browse Source

Merge pull request #79 from alcaeus/cursor-has-next

Add support for hasNext() in MongoCursor
Andreas 9 năm trước cách đây
mục cha
commit
e3756bf478

+ 0 - 2
README.md

@@ -116,8 +116,6 @@ unserializing them.
 ## MongoCursor
  - The [explain](https://php.net/manual/en/mongocursor.explain.php)
  method is not yet implemented.
- - The [hasNext](https://php.net/manual/en/mongocursor.hasnext.php)
- method is not yet implemented.
  - The [info](https://php.net/manual/en/mongocursor.info.php) method does not
  reliably fill all fields in the cursor information. This includes the `numReturned`
  and `server` keys once the cursor has started iterating. The `numReturned` field

+ 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;
+    }
 }

+ 6 - 2
lib/Mongo/MongoCursor.php

@@ -221,8 +221,12 @@ class MongoCursor extends AbstractCursor implements Iterator
      */
     public function hasNext()
     {
-        $this->errorIfOpened();
-        $this->notImplemented();
+        if ($this->cursorNeedsAdvancing) {
+            $this->ensureIterator()->next();
+            $this->cursorNeedsAdvancing = false;
+        }
+
+        return $this->ensureIterator()->valid();
     }
 
     /**

+ 4 - 0
tests/Alcaeus/MongoDbAdapter/Mongo/MongoCursorTest.php

@@ -67,21 +67,25 @@ class MongoCursorTest extends TestCase
         $collection = $this->getCollection();
         $cursor = $collection->find(['foo' => 'bar']);
 
+        $this->assertTrue($cursor->hasNext());
         $item = $cursor->getNext();
         $this->assertNotNull($item);
         $this->assertInstanceOf('MongoId', $item['_id']);
         $this->assertSame('bar', $item['foo']);
 
+        $this->assertTrue($cursor->hasNext());
         $item = $cursor->getNext();
         $this->assertNotNull($item);
         $this->assertInstanceOf('MongoId', $item['_id']);
         $this->assertSame('bar', $item['foo']);
 
+        $this->assertFalse($cursor->hasNext());
         $item = $cursor->getNext();
         $this->assertNull($item);
 
         $cursor->reset();
 
+        $this->assertTrue($cursor->hasNext());
         $item = $cursor->getNext();
         $this->assertNotNull($item);
         $this->assertInstanceOf('MongoId', $item['_id']);