Skip to content

Commit abc0a2e

Browse files
committed
feat(router): Add fallback for legacy action and file routes
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
1 parent db3c1af commit abc0a2e

2 files changed

Lines changed: 81 additions & 15 deletions

File tree

lib/private/Route/CachingRouter.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
class CachingRouter extends Router {
2424
protected ICache $cache;
2525

26+
protected array $legacyCreatedRoutes = [];
27+
2628
public function __construct(
2729
ICacheFactory $cacheFactory,
2830
LoggerInterface $logger,
@@ -104,4 +106,52 @@ public function findMatchingRoute(string $url): array {
104106
$this->eventLogger->end('cacheroute:match');
105107
return $parameters;
106108
}
109+
110+
/**
111+
* @param array{action:mixed, ...} $parameters
112+
*/
113+
protected function callLegacyActionRoute(array $parameters): void {
114+
/*
115+
* Closures cannot be serialized to cache, so for legacy routes calling an action we have to include the routes.php file again
116+
*/
117+
$app = $parameters['app'];
118+
$this->useCollection($app);
119+
parent::requireRouteFile($parameters['route-file'], $app);
120+
$collection = $this->getCollection($app);
121+
$parameters['action'] = $collection->get($parameters['_route'])?->getDefault('action');
122+
parent::callLegacyActionRoute($parameters);
123+
}
124+
125+
/**
126+
* Create a \OC\Route\Route.
127+
* Deprecated
128+
*
129+
* @param string $name Name of the route to create.
130+
* @param string $pattern The pattern to match
131+
* @param array $defaults An array of default parameter values
132+
* @param array $requirements An array of requirements for parameters (regexes)
133+
*/
134+
public function create($name, $pattern, array $defaults = [], array $requirements = []): Route {
135+
$this->legacyCreatedRoutes[] = $name;
136+
return parent::create($name, $pattern, $defaults, $requirements);
137+
}
138+
139+
/**
140+
* Require a routes.php file
141+
*/
142+
protected function requireRouteFile(string $file, string $appName): void {
143+
$this->legacyCreatedRoutes = [];
144+
parent::requireRouteFile($file, $appName);
145+
foreach ($this->legacyCreatedRoutes as $routeName) {
146+
$route = $this->collection?->get($routeName);
147+
if ($route === null) {
148+
/* Should never happen */
149+
throw new \Exception("Could not find route $routeName");
150+
}
151+
if ($route->hasDefault('action')) {
152+
$route->setDefault('route-file', $file);
153+
$route->setDefault('app', $appName);
154+
}
155+
}
156+
}
107157
}

lib/private/Route/Router.php

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -312,27 +312,43 @@ public function match($url) {
312312
$application = $this->getApplicationClass($caller[0]);
313313
\OC\AppFramework\App::main($caller[1], $caller[2], $application->getContainer(), $parameters);
314314
} elseif (isset($parameters['action'])) {
315-
$action = $parameters['action'];
316-
if (!is_callable($action)) {
317-
throw new \Exception('not a callable action');
318-
}
319-
unset($parameters['action']);
320-
unset($parameters['caller']);
321-
$this->eventLogger->start('route:run:call', 'Run callable route');
322-
call_user_func($action, $parameters);
323-
$this->eventLogger->end('route:run:call');
315+
$this->logger->warning('Deprecated action route used', ['parameters' => $parameters]);
316+
$this->callLegacyActionRoute($parameters);
324317
} elseif (isset($parameters['file'])) {
325-
$param = $parameters;
326-
unset($param['_route']);
327-
$_GET = array_merge($_GET, $param);
328-
unset($param);
329-
include $parameters['file'];
318+
$this->logger->debug('Deprecated file route used', ['parameters' => $parameters]);
319+
$this->includeLegacyFileRoute($parameters);
330320
} else {
331321
throw new \Exception('no action available');
332322
}
333323
$this->eventLogger->end('route:run');
334324
}
335325

326+
/**
327+
* @param array{file:mixed, ...} $parameters
328+
*/
329+
protected function includeLegacyFileRoute(array $parameters): void {
330+
$param = $parameters;
331+
unset($param['_route']);
332+
$_GET = array_merge($_GET, $param);
333+
unset($param);
334+
require_once $parameters['file'];
335+
}
336+
337+
/**
338+
* @param array{action:mixed, ...} $parameters
339+
*/
340+
protected function callLegacyActionRoute(array $parameters): void {
341+
$action = $parameters['action'];
342+
if (!is_callable($action)) {
343+
throw new \Exception('not a callable action');
344+
}
345+
unset($parameters['action']);
346+
unset($parameters['caller']);
347+
$this->eventLogger->start('route:run:call', 'Run callable route');
348+
call_user_func($action, $parameters);
349+
$this->eventLogger->end('route:run:call');
350+
}
351+
336352
/**
337353
* Get the url generator
338354
*
@@ -496,7 +512,7 @@ private function getAttributeRoutes(string $app): array {
496512
* @param string $file the route file location to include
497513
* @param string $appName
498514
*/
499-
private function requireRouteFile($file, $appName) {
515+
protected function requireRouteFile(string $file, string $appName): void {
500516
$this->setupRoutes(include $file, $appName);
501517
}
502518

0 commit comments

Comments
 (0)