diff --git a/core/routes.php b/core/routes.php index 76cf03c367..74be880612 100644 --- a/core/routes.php +++ b/core/routes.php @@ -7,7 +7,8 @@ */ // Post installation check -/** @var $this OC_Router */ + +/** @var $this OCP\Route\IRouter */ $this->create('post_setup_check', '/post-setup-check') ->action('OC_Setup', 'postSetupCheck'); diff --git a/lib/private/route/cachingrouter.php b/lib/private/route/cachingrouter.php new file mode 100644 index 0000000000..ad25372391 --- /dev/null +++ b/lib/private/route/cachingrouter.php @@ -0,0 +1,43 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Route; + +class CachingRouter extends Router { + /** + * @var \OCP\ICache + */ + protected $cache; + + /** + * @param \OCP\ICache $cache + */ + public function __construct($cache) { + $this->cache = $cache; + parent::__construct(); + } + + /** + * Generate url based on $name and $parameters + * + * @param string $name Name of the route to use. + * @param array $parameters Parameters for the route + * @param bool $absolute + * @return string + */ + public function generate($name, $parameters = array(), $absolute = false) { + $key = $name . json_encode($parameters) . $absolute; + if ($this->cache->hasKey($key)) { + return $this->cache->get($key); + } else { + $url = parent::generate($name, $parameters, $absolute); + $this->cache->set($key, $url, 3600); + return $url; + } + } +} diff --git a/lib/private/route/router.php b/lib/private/route/router.php index 60ba587840..bad74c925f 100644 --- a/lib/private/route/router.php +++ b/lib/private/route/router.php @@ -47,6 +47,8 @@ class Router implements IRouter { protected $loaded = false; + protected $loadedApps = array(); + public function __construct() { $baseUrl = \OC_Helper::linkTo('', 'index.php'); if (!\OC::$CLI) { @@ -93,27 +95,46 @@ class Router implements IRouter { /** * loads the api routes */ - public function loadRoutes() { + public function loadRoutes($app = null) { if ($this->loaded) { return; } - $this->loaded = true; - foreach ($this->getRoutingFiles() as $app => $file) { - $this->useCollection($app); - require_once $file; - $collection = $this->getCollection($app); - $collection->addPrefix('/apps/' . $app); + if (is_null($app)) { + $this->loaded = true; + $routingFiles = $this->getRoutingFiles(); + } else { + if (isset($this->loadedApps[$app])) { + return; + } + $file = \OC_App::getAppPath($app) . '/appinfo/routes.php'; + if (file_exists($file)) { + $routingFiles = array($app => $file); + } else { + $routingFiles = array(); + } + } + foreach ($routingFiles as $app => $file) { + if (!$this->loadedApps[$app]) { + $this->loadedApps[$app] = true; + $this->useCollection($app); + require_once $file; + $collection = $this->getCollection($app); + $collection->addPrefix('/apps/' . $app); + $this->root->addCollection($collection); + } + } + if (!isset($this->loadedApps['core'])) { + $this->loadedApps['core'] = true; + $this->useCollection('root'); + require_once 'settings/routes.php'; + require_once 'core/routes.php'; + + // include ocs routes + require_once 'ocs/routes.php'; + $collection = $this->getCollection('ocs'); + $collection->addPrefix('/ocs'); $this->root->addCollection($collection); } - $this->useCollection('root'); - require_once 'settings/routes.php'; - require_once 'core/routes.php'; - - // include ocs routes - require_once 'ocs/routes.php'; - $collection = $this->getCollection('ocs'); - $collection->addPrefix('/ocs'); - $this->root->addCollection($collection); } /** @@ -152,12 +173,21 @@ class Router implements IRouter { } /** - * Find the route matching $url. + * Find the route matching $url * * @param string $url The url to find * @throws \Exception */ public function match($url) { + if (substr($url, 0, 6) === '/apps/') { + // empty string / 'apps' / $app / rest of the route + list(, , $app,) = explode('/', $url, 4); + $this->loadRoutes($app); + } else if (substr($url, 0, 6) === '/core/' or substr($url, 0, 5) === '/ocs/' or substr($url, 0, 10) === '/settings/') { + $this->loadRoutes('core'); + } else { + $this->loadRoutes(); + } $matcher = new UrlMatcher($this->root, $this->context); $parameters = $matcher->match($url); if (isset($parameters['action'])) { @@ -196,6 +226,7 @@ class Router implements IRouter { * @return string */ public function generate($name, $parameters = array(), $absolute = false) { + $this->loadRoutes(); return $this->getGenerator()->generate($name, $parameters, $absolute); } diff --git a/lib/private/server.php b/lib/private/server.php index 8c9ea39c56..5c83f3ef49 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -159,7 +159,15 @@ class Server extends SimpleContainer implements IServerContainer { return new \OC\BackgroundJob\JobList($c->getDatabaseConnection(), $config); }); $this->registerService('Router', function ($c){ - $router = new \OC\Route\Router(); + /** + * @var Server $c + */ + $cacheFactory = $c->getMemCacheFactory(); + if ($cacheFactory->isAvailable()) { + $router = new \OC\Route\CachingRouter($cacheFactory->create('route')); + } else { + $router = new \OC\Route\Router(); + } return $router; }); } @@ -327,7 +335,7 @@ class Server extends SimpleContainer implements IServerContainer { /** * Returns an \OCP\CacheFactory instance * - * @return \OCP\CacheFactory + * @return \OCP\ICacheFactory */ function getMemCacheFactory() { return $this->query('MemCacheFactory'); @@ -375,8 +383,6 @@ class Server extends SimpleContainer implements IServerContainer { * @return \OCP\Route\IRouter */ function getRouter(){ - $router = $this->query('Router'); - $router->loadRoutes(); - return $router; + return $this->query('Router'); } } diff --git a/lib/public/route/irouter.php b/lib/public/route/irouter.php index d6b0750ba6..125cd29e81 100644 --- a/lib/public/route/irouter.php +++ b/lib/public/route/irouter.php @@ -10,8 +10,6 @@ namespace OCP\Route; interface IRouter { - public function __construct(); - /** * Get the files to load the routes from * @@ -24,7 +22,7 @@ interface IRouter { /** * loads the api routes */ - public function loadRoutes(); + public function loadRoutes($app = null); /** * Sets the collection to use for adding routes diff --git a/settings/routes.php b/settings/routes.php index 6954bd3823..a8bb0d981e 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ -/** @var $this OC_Router */ +/** @var $this OCP\Route\IRouter */ // Settings pages $this->create('settings_help', '/settings/help')