diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php index 9417a6eeb8..06e454b7d7 100644 --- a/apps/files_sharing/appinfo/routes.php +++ b/apps/files_sharing/appinfo/routes.php @@ -1,5 +1,5 @@ create('core_ajax_public_preview', '/publicpreview.png')->action( function() { require_once __DIR__ . '/../ajax/publicpreview.php'; diff --git a/lib/base.php b/lib/base.php index 6ad3a84bca..73553ff641 100644 --- a/lib/base.php +++ b/lib/base.php @@ -73,11 +73,6 @@ class OC { */ public static $CLI = false; - /** - * @var OC_Router - */ - protected static $router = null; - /** * @var \OC\Session\Session */ @@ -387,19 +382,6 @@ class OC { return OC_Config::getValue('session_lifetime', 60 * 60 * 24); } - /** - * @return OC_Router - */ - public static function getRouter() { - if (!isset(OC::$router)) { - OC::$router = new OC_Router(); - OC::$router->loadRoutes(); - } - - return OC::$router; - } - - public static function loadAppClassPaths() { foreach (OC_APP::getEnabledApps() as $app) { $file = OC_App::getAppPath($app) . '/appinfo/classpath.php'; @@ -727,7 +709,7 @@ class OC { OC_App::loadApps(); } self::checkSingleUserMode(); - OC::getRouter()->match(OC_Request::getRawPathInfo()); + OC::$server->getRouter()->match(OC_Request::getRawPathInfo()); return; } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) { //header('HTTP/1.0 404 Not Found'); diff --git a/lib/private/api.php b/lib/private/api.php index e8e54e375e..b3b5eb1067 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -65,8 +65,8 @@ class OC_API { $name = strtolower($method).$url; $name = str_replace(array('/', '{', '}'), '_', $name); if(!isset(self::$actions[$name])) { - OC::getRouter()->useCollection('ocs'); - OC::getRouter()->create($name, $url) + OC::$server->getRouter()->useCollection('ocs'); + OC::$server->getRouter()->create($name, $url) ->method($method) ->defaults($defaults) ->requirements($requirements) diff --git a/lib/private/appframework/routing/routeconfig.php b/lib/private/appframework/routing/routeconfig.php index 716358444a..35bee75cc4 100644 --- a/lib/private/appframework/routing/routeconfig.php +++ b/lib/private/appframework/routing/routeconfig.php @@ -23,6 +23,7 @@ namespace OC\AppFramework\routing; use OC\AppFramework\DependencyInjection\DIContainer; +use OCP\Route\IRouter; /** * Class RouteConfig @@ -36,10 +37,10 @@ class RouteConfig { /** * @param \OC\AppFramework\DependencyInjection\DIContainer $container - * @param \OC_Router $router + * @param \OCP\Route\IRouter $router * @internal param $appName */ - public function __construct(DIContainer $container, \OC_Router $router, $routes) { + public function __construct(DIContainer $container, IRouter $router, $routes) { $this->routes = $routes; $this->container = $container; $this->router = $router; @@ -47,7 +48,7 @@ class RouteConfig { } /** - * The routes and resource will be registered to the \OC_Router + * The routes and resource will be registered to the \OCP\Route\IRouter */ public function register() { diff --git a/lib/private/route.php b/lib/private/route/route.php similarity index 90% rename from lib/private/route.php rename to lib/private/route/route.php index fb7da456b6..6ade9ec15f 100644 --- a/lib/private/route.php +++ b/lib/private/route/route.php @@ -6,13 +6,17 @@ * See the COPYING-README file. */ -use Symfony\Component\Routing\Route; +namespace OC\Route; -class OC_Route extends Route { +use OCP\Route\IRoute; +use Symfony\Component\Routing\Route as SymfonyRoute; + +class Route extends SymfonyRoute implements IRoute { /** * Specify the method when this route is to be used * * @param string $method HTTP method (uppercase) + * @return \OC\Route\Route */ public function method($method) { $this->setRequirement('_method', strtoupper($method)); @@ -63,6 +67,7 @@ class OC_Route extends Route { * Defaults to use for this route * * @param array $defaults The defaults + * @return \OC\Route\Route */ public function defaults($defaults) { $action = $this->getDefault('action'); @@ -78,6 +83,7 @@ class OC_Route extends Route { * Requirements for this route * * @param array $requirements The requirements + * @return \OC\Route\Route */ public function requirements($requirements) { $method = $this->getRequirement('_method'); @@ -93,8 +99,10 @@ class OC_Route extends Route { /** * The action to execute when this route matches + * * @param string|callable $class the class or a callable * @param string $function the function to use with the class + * @return \OC\Route\Route * * This function is called with $class set to a callable or * to the class with $function diff --git a/lib/private/router.php b/lib/private/route/router.php similarity index 62% rename from lib/private/router.php rename to lib/private/route/router.php index 918e3b1320..60ba587840 100644 --- a/lib/private/router.php +++ b/lib/private/route/router.php @@ -6,68 +6,103 @@ * See the COPYING-README file. */ +namespace OC\Route; + +use OCP\Route\IRouter; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; -//use Symfony\Component\Routing\Route; -class OC_Router { +class Router implements IRouter { + /** + * @var \Symfony\Component\Routing\RouteCollection[] + */ protected $collections = array(); + + /** + * @var \Symfony\Component\Routing\RouteCollection + */ protected $collection = null; + + /** + * @var \Symfony\Component\Routing\RouteCollection + */ protected $root = null; + /** + * @var \Symfony\Component\Routing\Generator\UrlGenerator + */ protected $generator = null; - protected $routing_files; - protected $cache_key; + + /** + * @var string[] + */ + protected $routingFiles; + + /** + * @var string + */ + protected $cacheKey; + + protected $loaded = false; public function __construct() { - $baseUrl = OC_Helper::linkTo('', 'index.php'); - if ( !OC::$CLI) { + $baseUrl = \OC_Helper::linkTo('', 'index.php'); + if (!\OC::$CLI) { $method = $_SERVER['REQUEST_METHOD']; - }else{ + } else { $method = 'GET'; } - $host = OC_Request::serverHost(); - $schema = OC_Request::serverProtocol(); + $host = \OC_Request::serverHost(); + $schema = \OC_Request::serverProtocol(); $this->context = new RequestContext($baseUrl, $method, $host, $schema); // TODO cache $this->root = $this->getCollection('root'); } + /** + * Get the files to load the routes from + * + * @return string[] + */ public function getRoutingFiles() { - if (!isset($this->routing_files)) { - $this->routing_files = array(); - foreach(OC_APP::getEnabledApps() as $app) { - $file = OC_App::getAppPath($app).'/appinfo/routes.php'; - if(file_exists($file)) { - $this->routing_files[$app] = $file; + if (!isset($this->routingFiles)) { + $this->routingFiles = array(); + foreach (\OC_APP::getEnabledApps() as $app) { + $file = \OC_App::getAppPath($app) . '/appinfo/routes.php'; + if (file_exists($file)) { + $this->routingFiles[$app] = $file; } } } - return $this->routing_files; + return $this->routingFiles; } public function getCacheKey() { - if (!isset($this->cache_key)) { + if (!isset($this->cacheKey)) { $files = $this->getRoutingFiles(); $files[] = 'settings/routes.php'; $files[] = 'core/routes.php'; $files[] = 'ocs/routes.php'; - $this->cache_key = OC_Cache::generateCacheKeyFromFiles($files); + $this->cacheKey = \OC_Cache::generateCacheKeyFromFiles($files); } - return $this->cache_key; + return $this->cacheKey; } /** * loads the api routes */ public function loadRoutes() { - foreach($this->getRoutingFiles() as $app => $file) { + 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); + $collection->addPrefix('/apps/' . $app); $this->root->addCollection($collection); } $this->useCollection('root'); @@ -81,6 +116,10 @@ class OC_Router { $this->root->addCollection($collection); } + /** + * @param string $name + * @return \Symfony\Component\Routing\RouteCollection + */ protected function getCollection($name) { if (!isset($this->collections[$name])) { $this->collections[$name] = new RouteCollection(); @@ -91,22 +130,23 @@ class OC_Router { /** * Sets the collection to use for adding routes * - * @param string $name Name of the colletion to use. + * @param string $name Name of the collection to use. */ public function useCollection($name) { $this->collection = $this->getCollection($name); } /** - * Create a OC_Route. + * Create a \OC\Route\Route. * * @param string $name Name of the route to create. * @param string $pattern The pattern to match - * @param array $defaults An array of default parameter values - * @param array $requirements An array of requirements for parameters (regexes) + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + * @return \OC\Route\Route */ public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { - $route = new OC_Route($pattern, $defaults, $requirements); + $route = new Route($pattern, $defaults, $requirements); $this->collection->add($name, $route); return $route; } @@ -115,6 +155,7 @@ class OC_Router { * Find the route matching $url. * * @param string $url The url to find + * @throws \Exception */ public function match($url) { $matcher = new UrlMatcher($this->root, $this->context); @@ -123,14 +164,14 @@ class OC_Router { $action = $parameters['action']; if (!is_callable($action)) { var_dump($action); - throw new Exception('not a callable action'); + throw new \Exception('not a callable action'); } unset($parameters['action']); call_user_func($action, $parameters); } elseif (isset($parameters['file'])) { include $parameters['file']; } else { - throw new Exception('no action available'); + throw new \Exception('no action available'); } } @@ -138,8 +179,7 @@ class OC_Router { * Get the url generator * */ - public function getGenerator() - { + public function getGenerator() { if (null !== $this->generator) { return $this->generator; } @@ -152,9 +192,10 @@ class OC_Router { * * @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) - { + public function generate($name, $parameters = array(), $absolute = false) { return $this->getGenerator()->generate($name, $parameters, $absolute); } diff --git a/lib/private/server.php b/lib/private/server.php index 7696fc207f..8c9ea39c56 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -158,6 +158,10 @@ class Server extends SimpleContainer implements IServerContainer { $config = $c->getConfig(); return new \OC\BackgroundJob\JobList($c->getDatabaseConnection(), $config); }); + $this->registerService('Router', function ($c){ + $router = new \OC\Route\Router(); + return $router; + }); } /** @@ -364,4 +368,15 @@ class Server extends SimpleContainer implements IServerContainer { function getJobList(){ return $this->query('JobList'); } + + /** + * Returns a router for generating and matching urls + * + * @return \OCP\Route\IRouter + */ + function getRouter(){ + $router = $this->query('Router'); + $router->loadRoutes(); + return $router; + } } diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php index 60da34f2d6..44b46ef670 100644 --- a/lib/private/urlgenerator.php +++ b/lib/private/urlgenerator.php @@ -39,7 +39,7 @@ class URLGenerator implements IURLGenerator { * Returns a url to the given app and file. */ public function linkToRoute($route, $parameters = array()) { - $urlLinkTo = \OC::getRouter()->generate($route, $parameters); + $urlLinkTo = \OC::$server->getRouter()->generate($route, $parameters); return $urlLinkTo; } diff --git a/lib/public/appframework/app.php b/lib/public/appframework/app.php index 90150245c4..2161232787 100644 --- a/lib/public/appframework/app.php +++ b/lib/public/appframework/app.php @@ -67,7 +67,7 @@ class App { * $a = new TasksApp(); * $a->registerRoutes($this, $routes); * - * @param \OC_Router $router + * @param \OCP\Route\IRouter $router * @param array $routes */ public function registerRoutes($router, $routes) { diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 5fb51f9ecd..dc3aff663d 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -190,4 +190,10 @@ interface IServerContainer { */ function getJobList(); + /** + * Returns a router for generating and matching urls + * + * @return \OCP\Route\IRouter + */ + function getRouter(); } diff --git a/lib/public/route/iroute.php b/lib/public/route/iroute.php new file mode 100644 index 0000000000..66fdb84182 --- /dev/null +++ b/lib/public/route/iroute.php @@ -0,0 +1,79 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OCP\Route; + +interface IRoute { + /** + * Specify PATCH as the method to use with this route + */ + public function patch(); + + /** + * Specify the method when this route is to be used + * + * @param string $method HTTP method (uppercase) + * @return \OCP\Route\IRoute + */ + public function method($method); + + /** + * The action to execute when this route matches, includes a file like + * it is called directly + * + * @param $file + */ + public function actionInclude($file); + + /** + * Specify GET as the method to use with this route + */ + public function get(); + + /** + * Specify POST as the method to use with this route + */ + public function post(); + + /** + * Specify DELETE as the method to use with this route + */ + public function delete(); + + /** + * The action to execute when this route matches + * + * @param string|callable $class the class or a callable + * @param string $function the function to use with the class + * @return \OCP\Route\IRoute + * + * This function is called with $class set to a callable or + * to the class with $function + */ + public function action($class, $function = null); + + /** + * Defaults to use for this route + * + * @param array $defaults The defaults + * @return \OCP\Route\IRoute + */ + public function defaults($defaults); + + /** + * Requirements for this route + * + * @param array $requirements The requirements + * @return \OCP\Route\IRoute + */ + public function requirements($requirements); + + /** + * Specify PUT as the method to use with this route + */ + public function put(); +} diff --git a/lib/public/route/irouter.php b/lib/public/route/irouter.php new file mode 100644 index 0000000000..d6b0750ba6 --- /dev/null +++ b/lib/public/route/irouter.php @@ -0,0 +1,71 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP\Route; + +interface IRouter { + + public function __construct(); + + /** + * Get the files to load the routes from + * + * @return string[] + */ + public function getRoutingFiles(); + + public function getCacheKey(); + + /** + * loads the api routes + */ + public function loadRoutes(); + + /** + * Sets the collection to use for adding routes + * + * @param string $name Name of the collection to use. + */ + public function useCollection($name); + + /** + * Create a \OCP\Route\IRoute. + * + * @param string $name Name of the route to create. + * @param string $pattern The pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + * @return \OCP\Route\IRoute + */ + public function create($name, $pattern, array $defaults = array(), array $requirements = array()); + + /** + * Find the route matching $url. + * + * @param string $url The url to find + * @throws \Exception + */ + public function match($url); + + /** + * Get the url generator + * + */ + public function getGenerator(); + + /** + * 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); + +} diff --git a/ocs/v1.php b/ocs/v1.php index 4cbc857bbc..5d360c530a 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -26,7 +26,7 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\MethodNotAllowedException; try { - OC::getRouter()->match('/ocs'.OC_Request::getRawPathInfo()); + OC::$server->getRouter()->match('/ocs'.OC_Request::getRawPathInfo()); } catch (ResourceNotFoundException $e) { OC_API::setContentType(); OC_OCS::notFound(); diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php index d0244cf251..9f2675bf0b 100644 --- a/tests/lib/appframework/routing/RoutingTest.php +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -46,7 +46,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase )); // router mock - $router = $this->getMock("\OC_Router", array('create')); + $router = $this->getMock("\OC\Route\Router", array('create')); // load route configuration $container = new DIContainer('app1'); @@ -91,7 +91,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase $route = $this->mockRoute($verb, $controllerName, $actionName); // router mock - $router = $this->getMock("\OC_Router", array('create')); + $router = $this->getMock("\OC\Route\Router", array('create')); // we expect create to be called once: $router @@ -116,7 +116,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName) { // router mock - $router = $this->getMock("\OC_Router", array('create')); + $router = $this->getMock("\OC\Route\Router", array('create')); // route mocks $indexRoute = $this->mockRoute('GET', $controllerName, 'index'); @@ -174,7 +174,7 @@ class RouteConfigTest extends \PHPUnit_Framework_TestCase private function mockRoute($verb, $controllerName, $actionName) { $container = new DIContainer('app1'); - $route = $this->getMock("\OC_Route", array('method', 'action'), array(), '', false); + $route = $this->getMock("\OC\Route\Route", array('method', 'action'), array(), '', false); $route ->expects($this->exactly(1)) ->method('method')