Commit 0d5b7c48 authored by Jeremy Mikola's avatar Jeremy Mikola

PHPLIB-81: Move CachingIterator to MongoDB\Model

parent 9f677306
<?php
namespace MongoDB;
class CachingIterator implements \Iterator, \Countable
/*
* Copyright 2017 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace MongoDB\Model;
use Countable;
use Generator;
use Iterator;
use Traversable;
/**
* Iterator for wrapping a Traversable and caching its results.
*
* By caching results, this iterators allows a Traversable to be counted and
* rewound multiple times, even if the wrapped object does not natively support
* those operations (e.g. MongoDB\Driver\Cursor).
*
* @internal
*/
class CachingIterator implements Countable, Iterator
{
/**
* @var \Traversable
*/
private $items;
private $iterator;
/**
* @var array
*/
private $items = [];
/**
* @var bool
*/
private $iteratorExhausted = false;
/**
* @param \Traversable $iterator
* @param Traversable $traversable
*/
public function __construct(\Traversable $iterator)
public function __construct(Traversable $traversable)
{
$this->iterator = $this->wrapTraversable($iterator);
$this->iterator = $this->wrapTraversable($traversable);
$this->storeCurrentItem();
}
/**
* @return int
* @see http://php.net/countable.count
* @return integer
*/
public function count()
{
$this->exhaustIterator();
return count($this->items);
}
/**
* @see http://php.net/iterator.current
* @return mixed
*/
public function current()
......@@ -46,6 +67,7 @@ class CachingIterator implements \Iterator, \Countable
}
/**
* @see http://php.net/iterator.mixed
* @return mixed
*/
public function key()
......@@ -54,11 +76,12 @@ class CachingIterator implements \Iterator, \Countable
}
/**
* @see http://php.net/iterator.next
* @return void
*/
public function next()
{
if (! $this->iteratorExhausted) {
if ( ! $this->iteratorExhausted) {
$this->iterator->next();
$this->storeCurrentItem();
}
......@@ -67,6 +90,7 @@ class CachingIterator implements \Iterator, \Countable
}
/**
* @see http://php.net/iterator.rewind
* @return void
*/
public function rewind()
......@@ -76,7 +100,9 @@ class CachingIterator implements \Iterator, \Countable
}
/**
* @return bool
*
* @see http://php.net/iterator.valid
* @return boolean
*/
public function valid()
{
......@@ -84,21 +110,23 @@ class CachingIterator implements \Iterator, \Countable
}
/**
* Ensures the original iterator is fully consumed and all items cached
* Ensures that the inner iterator is fully consumed and cached.
*/
private function exhaustIterator()
{
while (!$this->iteratorExhausted) {
while ( ! $this->iteratorExhausted) {
$this->next();
}
}
/**
* Stores the current item
* Stores the current item in the cache.
*/
private function storeCurrentItem()
{
if (null === $key = $this->iterator->key()) {
$key = $this->iterator->key();
if ($key === null) {
return;
}
......@@ -106,14 +134,17 @@ class CachingIterator implements \Iterator, \Countable
}
/**
* @param \Traversable $traversable
* @return \Generator
* Wraps the Traversable with a Generator.
*
* @param Traversable $traversable
* @return Generator
*/
private function wrapTraversable(\Traversable $traversable)
private function wrapTraversable(Traversable $traversable)
{
foreach ($traversable as $key => $value) {
yield $key => $value;
}
$this->iteratorExhausted = true;
}
}
<?php
namespace MongoDB\Tests;
namespace MongoDB\Tests\Model;
use MongoDB\CachingIterator;
use MongoDB\Model\CachingIterator;
class CachingIteratorTest extends \PHPUnit_Framework_TestCase
{
/**
* Sanity check for all following tests
* Sanity check for all following tests.
*
* @expectedException \Exception
* @expectedExceptionMessage Cannot traverse an already closed generator
*/
public function testTraverseGeneratorConsumesIt()
public function testTraversingGeneratorConsumesIt()
{
$iterator = $this->getTraversable([1, 2, 3]);
$this->assertSame([1, 2, 3], iterator_to_array($iterator));
$this->assertSame([1, 2, 3], iterator_to_array($iterator));
}
public function testIterateOverItems()
public function testIteration()
{
$iterator = new CachingIterator($this->getTraversable([1, 2, 3]));
$expectedKey = 0;
$expectedItem = 1;
foreach ($iterator as $key => $item) {
$this->assertSame($expectedKey++, $key);
$this->assertSame($expectedItem++, $item);
}
$this->assertFalse($iterator->valid());
}
public function testIteratePartiallyThenRewind()
public function testRewindAfterPartialIteration()
{
$iterator = new CachingIterator($this->getTraversable([1, 2, 3]));
......@@ -47,7 +50,7 @@ class CachingIteratorTest extends \PHPUnit_Framework_TestCase
$this->assertCount(3, $iterator);
}
public function testCountAfterPartiallyIterating()
public function testCountAfterPartialIteration()
{
$iterator = new CachingIterator($this->getTraversable([1, 2, 3]));
$iterator->next();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment