Issue #2098197 by dawehner, vijaycs85, damiankloip, tstoeckler: Add getAllRoutes() method to RouteProvider .

8.0.x
webchick 2013-12-10 22:50:17 -08:00
parent 9145204f16
commit 6819e5e0d6
5 changed files with 285 additions and 0 deletions

View File

@ -0,0 +1,147 @@
<?php
/**
* @file
* Contains \Drupal\Core\Routing\LazyLoadingRouteCollection.
*/
namespace Drupal\Core\Routing;
use Drupal\Core\Database\Connection;
use Iterator;
/**
* Provides a route collection that lists all routes of drupal.
*
* Internally this does load multiple routes over time, so it never have all the
* routes stored in memory.
*/
class LazyLoadingRouteCollection implements Iterator {
/**
* Stores the current loaded routes.
*
* @var \Symfony\Component\Routing\Route[]
*/
protected $elements;
/**
* Contains the amount of route which are loaded on each sql query.
*/
const ROUTE_LOADED_PER_TIME = 50;
/**
* Contains the current item the iterator points to.
*
* @var int
*/
protected $currentRoute = 0;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The name of the SQL table from which to read the routes.
*
* @var string
*/
protected $tableName;
/**
* The number of routes in the router table.
*
* @var int
*/
protected $count;
/**
* Creates a LazyLoadingRouteCollection instance.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
* @param string $table
* (optional) The table to retrieve the route information.
*/
public function __construct(Connection $database, $table = 'router') {
$this->database = $database;
$this->tableName = $table;
}
/**
* Loads the next routes into the elements array.
*
* @param int $offset
* The offset used in the db query.
*/
protected function loadNextElements($offset) {
$this->elements = array();
$query = $this->database->select($this->tableName);
$query->addField($this->tableName, 'name');
$query->addField($this->tableName, 'route');
$query->orderBy('name', 'ASC');
$query->range($offset, static::ROUTE_LOADED_PER_TIME);
$result = $query->execute()->fetchAllKeyed();
$routes = array();
foreach ($result as $name => $route) {
$routes[$name] = unserialize($route);
}
$this->elements = $routes;
}
/**
* {inheritdoc}
*/
public function count() {
if (!isset($this->count)) {
$this->count = (int) $this->database->select($this->tableName)->countQuery()->execute();
}
return $this->count;
}
/**
* {@inheritdoc}
*/
public function current() {
return current($this->elements);
}
/**
* {@inheritdoc}
*/
public function next() {
$result = next($this->elements);
if ($result === FALSE) {
$this->loadNextElements($this->currentRoute + 1);
}
$this->currentRoute++;
}
/**
* {@inheritdoc}
*/
public function key() {
return key($this->elements);
}
/**
* {@inheritdoc}
*/
public function valid() {
return key($this->elements);
}
/**
* {@inheritdoc}
*/
public function rewind() {
$this->currentRoute = 0;
$this->loadNextElements($this->currentRoute);
}
}

View File

@ -262,4 +262,11 @@ class RouteProvider implements RouteProviderInterface {
return $collection; return $collection;
} }
/**
* {@inheritdoc}
*/
public function getAllRoutes() {
return new LazyLoadingRouteCollection($this->connection, $this->tableName);
}
} }

View File

@ -28,4 +28,16 @@ interface RouteProviderInterface extends RouteProviderBaseInterface {
*/ */
public function getRoutesByPattern($pattern); public function getRoutesByPattern($pattern);
/**
* Returns all the routes on the system.
*
* Usage of this method is discouraged for performance reasons. If possible,
* use RouteProviderInterface::getRoutesByNames() or
* RouteProviderInterface::getRoutesByPattern() instead.
*
* @return \Symfony\Component\Routing\Route[]
* An iterator of routes keyed by route name.
*/
public function getAllRoutes();
} }

View File

@ -75,5 +75,11 @@ class MockRouteProvider implements RouteProviderInterface {
return new RouteCollection(); return new RouteCollection();
} }
/**
* @inheritdoc}
*/
public function getAllRoutes() {
return $this->routes->all();
}
} }

View File

@ -0,0 +1,113 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Routing\LazyLoadingRouteCollectionTest.
*/
namespace Drupal\Tests\Core\Routing;
use Drupal\Core\Routing\LazyLoadingRouteCollection;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\Routing\Route;
/**
* Tests the lazy loaded route collection.
*
* @group \Drupal
*
* @see \Drupal\Core\Routing\LazyLoadingRouteCollection
*/
class LazyLoadingRouteCollectionTest extends UnitTestCase {
/**
* Stores all the routes used in the test.
*
* @var array
*/
protected $routes = array();
/**
* The tested route collection.
*
* @var \Drupal\Core\Routing\LazyLoadingRouteCollection
*/
protected $routeCollection;
public static function getInfo() {
return array(
'name' => 'Lazy loaded route collection',
'description' => 'Tests the lazy loaded route collection.',
'group' => 'Routing',
);
}
protected function setUp() {
for ($i = 0; $i < 20; $i++) {
$this->routes['test_route_' . $i] = new Route('/test-route-' . $i);
}
$this->routeCollection = new TestRouteCollection($this->routes);
}
/**
* Tests iterating the lazy loading route collection.
*
* @see \Drupal\Core\Routing\LazyLoadingRouteCollection::current()
* @see \Drupal\Core\Routing\LazyLoadingRouteCollection::key()
* @see \Drupal\Core\Routing\LazyLoadingRouteCollection::rewind()
*/
public function testIterating() {
// Execute the foreach loop twice to ensure that rewind is called.
for ($i = 0; $i < 2; $i++) {
$route_names = array_keys($this->routes);
$count = 0;
foreach ($this->routeCollection as $route_name => $route) {
$this->assertEquals($route_names[$count], $route_name);
$this->assertEquals($this->routes[$route_names[$count]], $route);
$count++;
}
}
}
}
/**
* Wrapper class to "inject" loaded routes.
*/
class TestRouteCollection extends LazyLoadingRouteCollection {
/**
* {@inheritdoc}
*/
const ROUTE_LOADED_PER_TIME = 2;
/**
* Stores all elements.
*
* @var \Symfony\Component\Routing\Route[]
*/
protected $allRoutes;
/**
* Creates a TestCollection instance.
*
* @param \Symfony\Component\Routing\Route[] $all_routes
* Contains all the routes used in the test.
*/
public function __construct(array $all_routes) {
$this->allRoutes = $all_routes;
$this->loadNextElements($this->currentRoute);
}
/**
* {@inheritdoc}
*/
protected function loadNextElements($offset) {
$elements = array_slice($this->allRoutes, $offset, static::ROUTE_LOADED_PER_TIME);
$this->elements = $elements;
}
}