Commit f0b86ce9 authored by webchick's avatar webchick

Issue #2363537 by dawehner, znerol: Update CMF routing to 1.3 and remove old code.

parent 45f2030a
......@@ -1586,17 +1586,16 @@
},
{
"name": "symfony-cmf/routing",
"version": "1.2.0",
"target-dir": "Symfony/Cmf/Component/Routing",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony-cmf/Routing.git",
"reference": "c67258b875eef3cb08009bf1428499d0f01ce5e7"
"reference": "8e87981d72c6930a27585dcd3119f3199f6cb2a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony-cmf/Routing/zipball/c67258b875eef3cb08009bf1428499d0f01ce5e7",
"reference": "c67258b875eef3cb08009bf1428499d0f01ce5e7",
"url": "https://api.github.com/repos/symfony-cmf/Routing/zipball/8e87981d72c6930a27585dcd3119f3199f6cb2a6",
"reference": "8e87981d72c6930a27585dcd3119f3199f6cb2a6",
"shasum": ""
},
"require": {
......@@ -1607,7 +1606,7 @@
},
"require-dev": {
"symfony/config": "~2.2",
"symfony/dependency-injection": "~2.0",
"symfony/dependency-injection": "~2.0@stable",
"symfony/event-dispatcher": "~2.1"
},
"suggest": {
......@@ -1616,12 +1615,12 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Cmf\\Component\\Routing": ""
"psr-4": {
"Symfony\\Cmf\\Component\\Routing\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
......@@ -1640,7 +1639,7 @@
"database",
"routing"
],
"time": "2014-05-08 19:37:14"
"time": "2014-10-20 20:55:17"
},
{
"name": "symfony/class-loader",
......
<?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);
}
}
......@@ -9,6 +9,8 @@
use Drupal\Component\Utility\String;
use Drupal\Core\State\StateInterface;
use Symfony\Cmf\Component\Routing\PagedRouteCollection;
use Symfony\Cmf\Component\Routing\PagedRouteProviderInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
......@@ -20,7 +22,7 @@
/**
* A Route Provider front-end for all Drupal-stored routes.
*/
class RouteProvider implements RouteProviderInterface, EventSubscriberInterface {
class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterface, EventSubscriberInterface {
/**
* The database connection from which to read route information.
......@@ -306,7 +308,7 @@ protected function getRoutesByPath($path) {
* {@inheritdoc}
*/
public function getAllRoutes() {
return new LazyLoadingRouteCollection($this->connection, $this->tableName);
return new PagedRouteCollection($this);
}
/**
......@@ -324,4 +326,32 @@ static function getSubscribedEvents() {
return $events;
}
/**
* {@inheritdoc}
*/
public function getRoutesPaged($offset, $length = NULL) {
$select = $this->connection->select($this->tableName, 'router')
->fields('router', ['name', 'route']);
if (isset($length)) {
$select->range($offset, $length);
}
$routes = $select->execute()->fetchAllKeyed();
$result = [];
foreach ($routes as $name => $route) {
$result[$name] = unserialize($route);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function getRoutesCount() {
return $this->connection->query("SELECT COUNT(*) FROM {" . $this->connection->escapeTable($this->tableName) . "}")->fetchField();
}
}
......@@ -461,4 +461,31 @@ public function testGetRoutesByPatternWithLongPatterns() {
$this->assertEqual(count($candidates), 7);
}
/**
* Tests getRoutesPaged().
*/
public function testGetRoutesPaged() {
$connection = Database::getConnection();
$provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes');
$this->fixtures->createTables($connection);
$dumper = new MatcherDumper($connection, $this->state, 'test_routes');
$dumper->addRoutes($this->fixtures->sampleRouteCollection());
$dumper->dump();
$fixture_routes = $this->fixtures->staticSampleRouteCollection();
// Query all the routes.
$routes = $provider->getRoutesPaged(0);
$this->assertEqual(array_keys($routes), array_keys($fixture_routes));
// Query non routes.
$routes = $provider->getRoutesPaged(0, 0);
$this->assertEqual(array_keys($routes), []);
// Query a limited sets of routes.
$routes = $provider->getRoutesPaged(1, 2);
$this->assertEqual(array_keys($routes), array_slice(array_keys($fixture_routes), 1, 2));
}
}
<?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;
/**
* @coversDefaultClass \Drupal\Core\Routing\LazyLoadingRouteCollection
* @group Routing
*/
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;
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;
}
}
......@@ -24,7 +24,6 @@
'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'),
'Symfony\\Cmf\\Component\\Routing' => array($vendorDir . '/symfony-cmf/routing'),
'Stack' => array($vendorDir . '/stack/builder/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'Gliph' => array($vendorDir . '/sdboyer/gliph/src'),
......
......@@ -6,6 +6,7 @@
$baseDir = dirname(dirname($vendorDir));
return array(
'Symfony\\Cmf\\Component\\Routing\\' => array($vendorDir . '/symfony-cmf/routing'),
'React\\Promise\\' => array($vendorDir . '/react/promise/src'),
'GuzzleHttp\\Stream\\' => array($vendorDir . '/guzzlehttp/streams/src'),
'GuzzleHttp\\Ring\\' => array($vendorDir . '/guzzlehttp/ringphp/src'),
......
This source diff could not be displayed because it is too large. You can view the blob instead.
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
env:
- SYMFONY_VERSION=2.2.*
- SYMFONY_VERSION=2.3.*
- SYMFONY_VERSION=2.4.*
- SYMFONY_VERSION=dev-master
env:
- SYMFONY_VERSION=2.5.*
before_script:
matrix:
allow_failures:
- php: hhvm
include:
- php: 5.5
env: SYMFONY_VERSION=2.3.*
- php: 5.5
env: SYMFONY_VERSION=2.4.*
- php: 5.5
env: SYMFONY_VERSION=2.*
before_install:
- composer require symfony/routing:${SYMFONY_VERSION} --prefer-source
script: phpunit --coverage-text
......@@ -19,7 +29,3 @@ script: phpunit --coverage-text
notifications:
irc: "irc.freenode.org#symfony-cmf"
email: "symfony-cmf-devs@googlegroups.com"
matrix:
allow_failures:
- env: SYMFONY_VERSION=dev-master
Changelog
=========
* **2014-09-29**: ChainRouter does not require a RouterInterface, as a
RequestMatcher and UrlGenerator is fine too. Fixed chain router interface to
not force a RouterInterface.
* **2014-09-29**: Deprecated DynamicRouter::match in favor of matchRequest.
1.3.0-RC1
---------
* **2014-08-20**: Added an interface for the ChainRouter
* **2014-06-06**: Updated to PSR-4 autoloading
1.2.0
-----
......
......@@ -24,7 +24,7 @@ interface CandidatesInterface
/**
* @param Request $request
*
* @return array a list of PHPCR-ODM ids
* @return array a list of paths
*/
public function getCandidates(Request $request);
......
......@@ -12,6 +12,7 @@
namespace Symfony\Cmf\Component\Routing;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RequestContextAwareInterface;
......@@ -24,17 +25,15 @@
use Psr\Log\LoggerInterface;
/**
* ChainRouter
*
* Allows access to a lot of different routers.
* The ChainRouter allows to combine several routers to try in a defined order.
*
* @author Henrik Bjornskov <henrik@bjrnskov.dk>
* @author Magnus Nordlander <magnus@e-butik.se>
*/
class ChainRouter implements RouterInterface, RequestMatcherInterface, WarmableInterface
class ChainRouter implements ChainRouterInterface, WarmableInterface
{
/**
* @var \Symfony\Component\Routing\RequestContext
* @var RequestContext
*/
private $context;
......@@ -45,17 +44,17 @@ class ChainRouter implements RouterInterface, RequestMatcherInterface, WarmableI
private $routers = array();
/**
* @var \Symfony\Component\Routing\RouterInterface[] Array of routers, sorted by priority
* @var RouterInterface[] Array of routers, sorted by priority
*/
private $sortedRouters;
/**
* @var \Symfony\Component\Routing\RouteCollection
* @var RouteCollection
*/
private $routeCollection;
/**
* @var null|\Psr\Log\LoggerInterface
* @var null|LoggerInterface
*/
protected $logger;
......@@ -76,13 +75,15 @@ public function getContext()
}
/**
* Add a Router to the index
*
* @param RouterInterface $router The router instance
* @param integer $priority The priority
* {@inheritdoc}
*/
public function add(RouterInterface $router, $priority = 0)
public function add($router, $priority = 0)
{
if (!$router instanceof RouterInterface
&& !($router instanceof RequestMatcherInterface && $router instanceof UrlGeneratorInterface)
) {
throw new \InvalidArgumentException(sprintf('%s is not a valid router.', get_class($router)));
}
if (empty($this->routers[$priority])) {
$this->routers[$priority] = array();
}
......@@ -92,9 +93,7 @@ public function add(RouterInterface $router, $priority = 0)
}
/**
* Sorts the routers and flattens them.
*
* @return RouterInterface[]
* {@inheritdoc}
*/
public function all()
{
......@@ -164,21 +163,26 @@ public function matchRequest(Request $request)
*
* @param string $url
* @param Request $request
*
* @return array An array of parameters
*
* @throws ResourceNotFoundException If no router matched.
*/
private function doMatch($url, Request $request = null)
{
$methodNotAllowed = null;
$requestForMatching = $request;
foreach ($this->all() as $router) {
try {
// the request/url match logic is the same as in Symfony/Component/HttpKernel/EventListener/RouterListener.php
// matching requests is more powerful than matching URLs only, so try that first
if ($router instanceof RequestMatcherInterface) {
if (null === $request) {
$request = Request::create($url);
if (empty($requestForMatching)) {
$requestForMatching = Request::create($url);
}
return $router->matchRequest($request);
return $router->matchRequest($requestForMatching);
}
// every router implements the match method
return $router->match($url);
......@@ -212,15 +216,14 @@ public function generate($name, $parameters = array(), $absolute = false)
$debug = array();
foreach ($this->all() as $router) {
// if $router does not implement ChainedRouterInterface and $name is not a string, continue
if ($name && !$router instanceof ChainedRouterInterface) {
if (! is_string($name)) {
continue;
}
// if $router does not announce it is capable of handling
// non-string routes and $name is not a string, continue
if ($name && !is_string($name) && !$router instanceof VersatileGeneratorInterface) {
continue;
}
// If $router implements ChainedRouterInterface but doesn't support this route name, continue
if ($router instanceof ChainedRouterInterface && !$router->supports($name)) {
// If $router is versatile and doesn't support this route name, continue
if ($router instanceof VersatileGeneratorInterface && !$router->supports($name)) {
continue;
}
......
<?php
/*
* This file is part of the Symfony CMF package.
*
* (c) 2011-2014 Symfony CMF
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Cmf\Component\Routing;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
/**
* Interface for a router that proxies routing to other routers.
*
* @author Daniel Wehner <dawehner@googlemail.com>
*/
interface ChainRouterInterface extends RouterInterface, RequestMatcherInterface
{
/**
* Add a Router to the index.
*
* @param RouterInterface $router The router instance. Instead of RouterInterface, may also
* be RequestMatcherInterface and UrlGeneratorInterface.
* @param integer $priority The priority
*/
public function add($router, $priority = 0);
/**
* Sorts the routers and flattens them.
*
* @return RouterInterface[] or RequestMatcherInterface and UrlGeneratorInterface.
*/
public function all();
}
......@@ -14,7 +14,7 @@
use Symfony\Component\Routing\RouterInterface;
/**
* Interface to combine the VersatileGeneratorInterface with the RouterInterface
* Interface to combine the VersatileGeneratorInterface with the RouterInterface.
*/
interface ChainedRouterInterface extends RouterInterface, VersatileGeneratorInterface
{
......
......@@ -198,6 +198,7 @@ public function supports($name)
* @throws MethodNotAllowedException If the resource was found but the
* request method is not allowed