diff --git a/LazyRouteCollection.php b/LazyRouteCollection.php index 28b02acd..4011f9ac 100644 --- a/LazyRouteCollection.php +++ b/LazyRouteCollection.php @@ -29,6 +29,14 @@ public function __construct(RouteProviderInterface $provider) $this->provider = $provider; } + /** + * {@inheritdoc} + */ + public function getIterator() + { + return new \ArrayIterator($this->all()); + } + /** * Gets the number of Routes in this collection. * diff --git a/PagedRouteCollection.php b/PagedRouteCollection.php new file mode 100644 index 00000000..dba573e0 --- /dev/null +++ b/PagedRouteCollection.php @@ -0,0 +1,126 @@ +provider = $pagedRouteProvider; + $this->routesBatchSize = $routesBatchSize; + } + + /** + * Loads the next routes into the elements array. + * + * @param int $offset The offset used in the db query. + */ + protected function loadNextElements($offset) + { + // If the last batch was smaller than the batch size, this means there + // are no more routes available. + if (isset($this->currentRoutes) && count($this->currentRoutes) < $this->routesBatchSize) { + $this->currentRoutes = array(); + } else { + $this->currentRoutes = $this->provider->getRoutesPaged($offset, $this->routesBatchSize); + } + } + + /** + * {@inheritdoc} + */ + public function current() + { + return current($this->currentRoutes); + } + + /** + * {@inheritdoc} + */ + public function next() + { + $result = next($this->currentRoutes); + if (false === $result) { + $this->loadNextElements($this->current + 1); + } + $this->current++; + } + + /** + * {@inheritdoc} + */ + public function key() + { + return key($this->currentRoutes); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return key($this->currentRoutes); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + $this->current = 0; + $this->currentRoutes = NULL; + $this->loadNextElements($this->current); + } + + /** + * Gets the number of Routes in this collection. + * + * @return int The number of routes + */ + public function count() + { + return $this->provider->getRoutesCount(); + } +} diff --git a/PagedRouteProviderInterface.php b/PagedRouteProviderInterface.php new file mode 100644 index 00000000..970ec781 --- /dev/null +++ b/PagedRouteProviderInterface.php @@ -0,0 +1,42 @@ +getMock('Symfony\Cmf\Component\Routing\RouteProviderInterface'); + $testRoutes = array( + 'route_1' => new Route('/route-1'), + 'route_2"' => new Route('/route-2'), + ); + $routeProvider->expects($this->exactly(2)) + ->method('getRoutesByNames') + ->with(null) + ->will($this->returnValue($testRoutes)); + $lazyRouteCollection = new LazyRouteCollection($routeProvider); + $this->assertEquals($testRoutes, iterator_to_array($lazyRouteCollection->getIterator())); + $this->assertEquals($testRoutes, $lazyRouteCollection->all()); + } +} diff --git a/Tests/Routing/PagedRouteCollectionTest.php b/Tests/Routing/PagedRouteCollectionTest.php new file mode 100644 index 00000000..741beaa5 --- /dev/null +++ b/Tests/Routing/PagedRouteCollectionTest.php @@ -0,0 +1,132 @@ +routeProvider = $this->getMock('Symfony\Cmf\Component\Routing\PagedRouteProviderInterface'); + } + + /** + * Tests iterating a small amount of routes. + * + * @dataProvider providerIterator + */ + public function testIterator($amountRoutes, $routesLoadedInParallel, $expectedCalls = array()) + { + $routes = array(); + for ($i = 0; $i < $amountRoutes; $i++) { + $routes['test_' . $i] = new Route("/example-$i"); + } + $names = array_keys($routes); + + foreach ($expectedCalls as $i => $range) + { + $this->routeProvider->expects($this->at($i)) + ->method('getRoutesPaged') + ->with($range[0], $range[1]) + ->will($this->returnValue(array_slice($routes, $range[0], $range[1]))); + } + + $route_collection = new PagedRouteCollection($this->routeProvider, $routesLoadedInParallel); + + $counter = 0; + foreach ($route_collection as $route_name => $route) { + // Ensure the route did not changed. + $this->assertEquals($routes[$route_name], $route); + // Ensure that the order did not changed. + $this->assertEquals($route_name, $names[$counter]); + $counter++; + } + } + + /** + * Provides test data for testIterator(). + */ + public function providerIterator() + { + $data = array(); + // Non total routes. + $data[] = array(0, 20, array(array(0, 20))); + // Less total routes than loaded in parallel. + $data[] = array(10, 20, array(array(0, 20))); + // Exact the same amount of routes then loaded in parallel. + $data[] = array(20, 20, array(array(0, 20), array(20, 20))); + // Less than twice the amount. + $data[] = array(39, 20, array(array(0, 20), array(20, 20))); + // More total routes than loaded in parallel. + $data[] = array(40, 20, array(array(0, 20), array(20, 20), array(40, 20))); + $data[] = array(41, 20, array(array(0, 20), array(20, 20), array(40, 20))); + // why not. + $data[] = array(42, 23, array(array(0, 23), array(23, 23))); + return $data; + } + + /** + * Tests the count() method. + */ + public function testCount() + { + $this->routeProvider->expects($this->once()) + ->method('getRoutesCount') + ->will($this->returnValue(12)); + $routeCollection = new PagedRouteCollection($this->routeProvider); + $this->assertEquals(12, $routeCollection->count()); + } + + /** + * Tests the rewind method once the iterator is at the end. + */ + public function testIteratingAndRewind() + { + $routes = array(); + for ($i = 0; $i < 30; $i++) { + $routes['test_' . $i] = new Route("/example-$i"); + } + $this->routeProvider->expects($this->any()) + ->method('getRoutesPaged') + ->will($this->returnValueMap(array( + array(0, 10, array_slice($routes, 0, 10)), + array(10, 10, array_slice($routes, 9, 10)), + array(20, 10, array()), + ))); + + $routeCollection = new PagedRouteCollection($this->routeProvider, 10); + + // Force the iterating process. + $routeCollection->rewind(); + for ($i = 0; $i < 29; $i++) { + $routeCollection->next(); + } + $routeCollection->rewind(); + + $this->assertEquals('test_0', $routeCollection->key()); + $this->assertEquals($routes['test_0'], $routeCollection->current()); + } +}