Merge pull request #13714 from nextcloud/feature/noid/ocs-resources
Allow OCS resources as well
This commit is contained in:
commit
0d33302350
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
/**
|
/**
|
||||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||||
*
|
*
|
||||||
|
@ -84,42 +85,37 @@ class RouteConfig {
|
||||||
// parse ocs simple routes
|
// parse ocs simple routes
|
||||||
$this->processOCS($this->routes);
|
$this->processOCS($this->routes);
|
||||||
|
|
||||||
|
// parse ocs simple routes
|
||||||
|
$this->processOCSResources($this->routes);
|
||||||
|
|
||||||
$this->router->useCollection($oldCollection);
|
$this->router->useCollection($oldCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function processOCS(array $routes) {
|
private function processOCS(array $routes): void {
|
||||||
$ocsRoutes = isset($routes['ocs']) ? $routes['ocs'] : [];
|
$ocsRoutes = $routes['ocs'] ?? [];
|
||||||
foreach ($ocsRoutes as $ocsRoute) {
|
foreach ($ocsRoutes as $ocsRoute) {
|
||||||
$name = $ocsRoute['name'];
|
$name = $ocsRoute['name'];
|
||||||
$postfix = '';
|
$postfix = $ocsRoute['postfix'] ?? '';
|
||||||
|
$root = $ocsRoute['root'] ?? '/apps/' . $this->appName;
|
||||||
if (isset($ocsRoute['postfix'])) {
|
|
||||||
$postfix = $ocsRoute['postfix'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($ocsRoute['root'])) {
|
|
||||||
$root = $ocsRoute['root'];
|
|
||||||
} else {
|
|
||||||
$root = '/apps/'.$this->appName;
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = $root . $ocsRoute['url'];
|
$url = $root . $ocsRoute['url'];
|
||||||
$verb = isset($ocsRoute['verb']) ? strtoupper($ocsRoute['verb']) : 'GET';
|
$verb = strtoupper($ocsRoute['verb'] ?? 'GET');
|
||||||
|
|
||||||
$split = explode('#', $name, 2);
|
$split = explode('#', $name, 2);
|
||||||
if (count($split) != 2) {
|
if (count($split) !== 2) {
|
||||||
throw new \UnexpectedValueException('Invalid route name');
|
throw new \UnexpectedValueException('Invalid route name');
|
||||||
}
|
}
|
||||||
$controller = $split[0];
|
list($controller, $action) = $split;
|
||||||
$action = $split[1];
|
|
||||||
|
|
||||||
$controllerName = $this->buildControllerName($controller);
|
$controllerName = $this->buildControllerName($controller);
|
||||||
$actionName = $this->buildActionName($action);
|
$actionName = $this->buildActionName($action);
|
||||||
|
|
||||||
|
$routeName = 'ocs.' . $this->appName . '.' . $controller . '.' . $action . $postfix;
|
||||||
|
|
||||||
// register the route
|
// register the route
|
||||||
$handler = new RouteActionHandler($this->container, $controllerName, $actionName);
|
$handler = new RouteActionHandler($this->container, $controllerName, $actionName);
|
||||||
|
|
||||||
$router = $this->router->create('ocs.'.$this->appName.'.'.$controller.'.'.$action . $postfix, $url)
|
$router = $this->router->create($routeName, $url)
|
||||||
->method($verb)
|
->method($verb)
|
||||||
->action($handler);
|
->action($handler);
|
||||||
|
|
||||||
|
@ -142,33 +138,29 @@ class RouteConfig {
|
||||||
* @param array $routes
|
* @param array $routes
|
||||||
* @throws \UnexpectedValueException
|
* @throws \UnexpectedValueException
|
||||||
*/
|
*/
|
||||||
private function processSimpleRoutes($routes)
|
private function processSimpleRoutes(array $routes): void {
|
||||||
{
|
$simpleRoutes = $routes['routes'] ?? [];
|
||||||
$simpleRoutes = isset($routes['routes']) ? $routes['routes'] : array();
|
|
||||||
foreach ($simpleRoutes as $simpleRoute) {
|
foreach ($simpleRoutes as $simpleRoute) {
|
||||||
$name = $simpleRoute['name'];
|
$name = $simpleRoute['name'];
|
||||||
$postfix = '';
|
$postfix = $simpleRoute['postfix'] ?? '';
|
||||||
|
|
||||||
if (isset($simpleRoute['postfix'])) {
|
|
||||||
$postfix = $simpleRoute['postfix'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = $simpleRoute['url'];
|
$url = $simpleRoute['url'];
|
||||||
$verb = isset($simpleRoute['verb']) ? strtoupper($simpleRoute['verb']) : 'GET';
|
$verb = strtoupper($simpleRoute['verb'] ?? 'GET');
|
||||||
|
|
||||||
$split = explode('#', $name, 2);
|
$split = explode('#', $name, 2);
|
||||||
if (count($split) != 2) {
|
if (count($split) !== 2) {
|
||||||
throw new \UnexpectedValueException('Invalid route name');
|
throw new \UnexpectedValueException('Invalid route name');
|
||||||
}
|
}
|
||||||
$controller = $split[0];
|
list($controller, $action) = $split;
|
||||||
$action = $split[1];
|
|
||||||
|
|
||||||
$controllerName = $this->buildControllerName($controller);
|
$controllerName = $this->buildControllerName($controller);
|
||||||
$actionName = $this->buildActionName($action);
|
$actionName = $this->buildActionName($action);
|
||||||
|
|
||||||
|
$routeName = $this->appName . '.' . $controller . '.' . $action . $postfix;
|
||||||
|
|
||||||
// register the route
|
// register the route
|
||||||
$handler = new RouteActionHandler($this->container, $controllerName, $actionName);
|
$handler = new RouteActionHandler($this->container, $controllerName, $actionName);
|
||||||
$router = $this->router->create($this->appName.'.'.$controller.'.'.$action . $postfix, $url)
|
$router = $this->router->create($routeName, $url)
|
||||||
->method($verb)
|
->method($verb)
|
||||||
->action($handler);
|
->action($handler);
|
||||||
|
|
||||||
|
@ -187,41 +179,90 @@ class RouteConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For a given name and url restful routes are created:
|
* For a given name and url restful OCS routes are created:
|
||||||
* - index
|
* - index
|
||||||
* - show
|
* - show
|
||||||
* - new
|
|
||||||
* - create
|
* - create
|
||||||
* - update
|
* - update
|
||||||
* - destroy
|
* - destroy
|
||||||
*
|
*
|
||||||
* @param array $routes
|
* @param array $routes
|
||||||
*/
|
*/
|
||||||
private function processResources($routes)
|
private function processOCSResources(array $routes): void {
|
||||||
{
|
|
||||||
// declaration of all restful actions
|
// declaration of all restful actions
|
||||||
$actions = array(
|
$actions = [
|
||||||
array('name' => 'index', 'verb' => 'GET', 'on-collection' => true),
|
['name' => 'index', 'verb' => 'GET', 'on-collection' => true],
|
||||||
array('name' => 'show', 'verb' => 'GET'),
|
['name' => 'show', 'verb' => 'GET'],
|
||||||
array('name' => 'create', 'verb' => 'POST', 'on-collection' => true),
|
['name' => 'create', 'verb' => 'POST', 'on-collection' => true],
|
||||||
array('name' => 'update', 'verb' => 'PUT'),
|
['name' => 'update', 'verb' => 'PUT'],
|
||||||
array('name' => 'destroy', 'verb' => 'DELETE'),
|
['name' => 'destroy', 'verb' => 'DELETE'],
|
||||||
);
|
];
|
||||||
|
|
||||||
$resources = isset($routes['resources']) ? $routes['resources'] : array();
|
$resources = $routes['ocs-resources'] ?? [];
|
||||||
|
foreach ($resources as $resource => $config) {
|
||||||
|
$root = $config['root'] ?? '/apps/' . $this->appName;
|
||||||
|
|
||||||
|
// the url parameter used as id to the resource
|
||||||
|
foreach($actions as $action) {
|
||||||
|
$url = $root . $config['url'];
|
||||||
|
$method = $action['name'];
|
||||||
|
$verb = strtoupper($action['verb'] ?? 'GET');
|
||||||
|
$collectionAction = $action['on-collection'] ?? false;
|
||||||
|
if (!$collectionAction) {
|
||||||
|
$url .= '/{id}';
|
||||||
|
}
|
||||||
|
if (isset($action['url-postfix'])) {
|
||||||
|
$url .= '/' . $action['url-postfix'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$controller = $resource;
|
||||||
|
|
||||||
|
$controllerName = $this->buildControllerName($controller);
|
||||||
|
$actionName = $this->buildActionName($method);
|
||||||
|
|
||||||
|
$routeName = 'ocs.' . $this->appName . '.' . strtolower($resource) . '.' . strtolower($method);
|
||||||
|
|
||||||
|
$this->router->create($routeName, $url)->method($verb)->action(
|
||||||
|
new RouteActionHandler($this->container, $controllerName, $actionName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a given name and url restful routes are created:
|
||||||
|
* - index
|
||||||
|
* - show
|
||||||
|
* - create
|
||||||
|
* - update
|
||||||
|
* - destroy
|
||||||
|
*
|
||||||
|
* @param array $routes
|
||||||
|
*/
|
||||||
|
private function processResources(array $routes): void {
|
||||||
|
// declaration of all restful actions
|
||||||
|
$actions = [
|
||||||
|
['name' => 'index', 'verb' => 'GET', 'on-collection' => true],
|
||||||
|
['name' => 'show', 'verb' => 'GET'],
|
||||||
|
['name' => 'create', 'verb' => 'POST', 'on-collection' => true],
|
||||||
|
['name' => 'update', 'verb' => 'PUT'],
|
||||||
|
['name' => 'destroy', 'verb' => 'DELETE'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$resources = $routes['resources'] ?? [];
|
||||||
foreach ($resources as $resource => $config) {
|
foreach ($resources as $resource => $config) {
|
||||||
|
|
||||||
// the url parameter used as id to the resource
|
// the url parameter used as id to the resource
|
||||||
foreach($actions as $action) {
|
foreach($actions as $action) {
|
||||||
$url = $config['url'];
|
$url = $config['url'];
|
||||||
$method = $action['name'];
|
$method = $action['name'];
|
||||||
$verb = isset($action['verb']) ? strtoupper($action['verb']) : 'GET';
|
$verb = strtoupper($action['verb'] ?? 'GET');
|
||||||
$collectionAction = isset($action['on-collection']) ? $action['on-collection'] : false;
|
$collectionAction = $action['on-collection'] ?? false;
|
||||||
if (!$collectionAction) {
|
if (!$collectionAction) {
|
||||||
$url = $url . '/{id}';
|
$url .= '/{id}';
|
||||||
}
|
}
|
||||||
if (isset($action['url-postfix'])) {
|
if (isset($action['url-postfix'])) {
|
||||||
$url = $url . '/' . $action['url-postfix'];
|
$url .= '/' . $action['url-postfix'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$controller = $resource;
|
$controller = $resource;
|
||||||
|
@ -243,8 +284,7 @@ class RouteConfig {
|
||||||
* @param string $controller
|
* @param string $controller
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function buildControllerName($controller)
|
private function buildControllerName(string $controller): string {
|
||||||
{
|
|
||||||
if (!isset($this->controllerNameCache[$controller])) {
|
if (!isset($this->controllerNameCache[$controller])) {
|
||||||
$this->controllerNameCache[$controller] = $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller';
|
$this->controllerNameCache[$controller] = $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller';
|
||||||
}
|
}
|
||||||
|
@ -256,7 +296,7 @@ class RouteConfig {
|
||||||
* @param string $action
|
* @param string $action
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function buildActionName($action) {
|
private function buildActionName(string $action): string {
|
||||||
return $this->underScoreToCamelCase($action);
|
return $this->underScoreToCamelCase($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,12 +305,12 @@ class RouteConfig {
|
||||||
* @param string $str
|
* @param string $str
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function underScoreToCamelCase($str) {
|
private function underScoreToCamelCase(string $str): string {
|
||||||
$pattern = "/_[a-z]?/";
|
$pattern = '/_[a-z]?/';
|
||||||
return preg_replace_callback(
|
return preg_replace_callback(
|
||||||
$pattern,
|
$pattern,
|
||||||
function ($matches) {
|
function ($matches) {
|
||||||
return strtoupper(ltrim($matches[0], "_"));
|
return strtoupper(ltrim($matches[0], '_'));
|
||||||
},
|
},
|
||||||
$str);
|
$str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ use OC\AppFramework\DependencyInjection\DIContainer;
|
||||||
use OC\AppFramework\Routing\RouteActionHandler;
|
use OC\AppFramework\Routing\RouteActionHandler;
|
||||||
use OC\AppFramework\Routing\RouteConfig;
|
use OC\AppFramework\Routing\RouteConfig;
|
||||||
use OCP\ILogger;
|
use OCP\ILogger;
|
||||||
|
use OCP\Route\IRouter;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use OC\Route\Router;
|
||||||
|
|
||||||
class RoutingTest extends \Test\TestCase
|
class RoutingTest extends \Test\TestCase
|
||||||
{
|
{
|
||||||
|
@ -179,6 +182,27 @@ class RoutingTest extends \Test\TestCase
|
||||||
$this->assertSimpleOCSRoute($routes, 'admin_folders.open_current', 'DELETE', '/apps/app1/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent');
|
$this->assertSimpleOCSRoute($routes, 'admin_folders.open_current', 'DELETE', '/apps/app1/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testOCSResource()
|
||||||
|
{
|
||||||
|
$routes = ['ocs-resources' => ['account' => ['url' => '/accounts']]];
|
||||||
|
|
||||||
|
$this->assertOCSResource($routes, 'account', '/apps/app1/accounts', 'AccountController', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOCSResourceWithUnderScoreName()
|
||||||
|
{
|
||||||
|
$routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts']]];
|
||||||
|
|
||||||
|
$this->assertOCSResource($routes, 'admin_accounts', '/apps/app1/admin/accounts', 'AdminAccountsController', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOCSResourceWithRoot()
|
||||||
|
{
|
||||||
|
$routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts', 'root' => '/core/endpoint']]];
|
||||||
|
|
||||||
|
$this->assertOCSResource($routes, 'admin_accounts', '/core/endpoint/admin/accounts', 'AdminAccountsController', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
public function testResource()
|
public function testResource()
|
||||||
{
|
{
|
||||||
$routes = array('resources' => array('account' => array('url' => '/accounts')));
|
$routes = array('resources' => array('account' => array('url' => '/accounts')));
|
||||||
|
@ -277,6 +301,67 @@ class RoutingTest extends \Test\TestCase
|
||||||
$config->register();
|
$config->register();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $yaml
|
||||||
|
* @param string $resourceName
|
||||||
|
* @param string $url
|
||||||
|
* @param string $controllerName
|
||||||
|
* @param string $paramName
|
||||||
|
*/
|
||||||
|
private function assertOCSResource($yaml, $resourceName, $url, $controllerName, $paramName): void {
|
||||||
|
/** @var IRouter|MockObject $router */
|
||||||
|
$router = $this->getMockBuilder(Router::class)
|
||||||
|
->setMethods(['create'])
|
||||||
|
->setConstructorArgs([$this->getMockBuilder(ILogger::class)->getMock()])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
// route mocks
|
||||||
|
$container = new DIContainer('app1');
|
||||||
|
$indexRoute = $this->mockRoute($container, 'GET', $controllerName, 'index');
|
||||||
|
$showRoute = $this->mockRoute($container, 'GET', $controllerName, 'show');
|
||||||
|
$createRoute = $this->mockRoute($container, 'POST', $controllerName, 'create');
|
||||||
|
$updateRoute = $this->mockRoute($container, 'PUT', $controllerName, 'update');
|
||||||
|
$destroyRoute = $this->mockRoute($container, 'DELETE', $controllerName, 'destroy');
|
||||||
|
|
||||||
|
$urlWithParam = $url . '/{' . $paramName . '}';
|
||||||
|
|
||||||
|
// we expect create to be called once:
|
||||||
|
$router
|
||||||
|
->expects($this->at(0))
|
||||||
|
->method('create')
|
||||||
|
->with($this->equalTo('ocs.app1.' . $resourceName . '.index'), $this->equalTo($url))
|
||||||
|
->willReturn($indexRoute);
|
||||||
|
|
||||||
|
$router
|
||||||
|
->expects($this->at(1))
|
||||||
|
->method('create')
|
||||||
|
->with($this->equalTo('ocs.app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam))
|
||||||
|
->willReturn($showRoute);
|
||||||
|
|
||||||
|
$router
|
||||||
|
->expects($this->at(2))
|
||||||
|
->method('create')
|
||||||
|
->with($this->equalTo('ocs.app1.' . $resourceName . '.create'), $this->equalTo($url))
|
||||||
|
->willReturn($createRoute);
|
||||||
|
|
||||||
|
$router
|
||||||
|
->expects($this->at(3))
|
||||||
|
->method('create')
|
||||||
|
->with($this->equalTo('ocs.app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam))
|
||||||
|
->willReturn($updateRoute);
|
||||||
|
|
||||||
|
$router
|
||||||
|
->expects($this->at(4))
|
||||||
|
->method('create')
|
||||||
|
->with($this->equalTo('ocs.app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam))
|
||||||
|
->willReturn($destroyRoute);
|
||||||
|
|
||||||
|
// load route configuration
|
||||||
|
$config = new RouteConfig($container, $router, $yaml);
|
||||||
|
|
||||||
|
$config->register();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $resourceName
|
* @param string $resourceName
|
||||||
* @param string $url
|
* @param string $url
|
||||||
|
|
Loading…
Reference in New Issue