aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCôme Chilliet <come.chilliet@nextcloud.com>2025-05-13 16:37:52 +0200
committerCôme Chilliet <come.chilliet@nextcloud.com>2025-06-05 17:58:53 +0200
commit01575b7d95cc2400962b5a8eaeeba954749d869b (patch)
treee7f1f7041f5e944bff4b1e002fff32b015d581f6
parentee3abdd81bc75aa6b373dcc6eec0bdd6aeda0c5a (diff)
downloadnextcloud-server-01575b7d95cc2400962b5a8eaeeba954749d869b.tar.gz
nextcloud-server-01575b7d95cc2400962b5a8eaeeba954749d869b.zip
feat(router): Use Symfony CompiledUrlMatcherDumper to cache routes
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
-rw-r--r--lib/private/Route/CachingRouter.php84
1 files changed, 37 insertions, 47 deletions
diff --git a/lib/private/Route/CachingRouter.php b/lib/private/Route/CachingRouter.php
index 9ceb08b61e2..3f60503e283 100644
--- a/lib/private/Route/CachingRouter.php
+++ b/lib/private/Route/CachingRouter.php
@@ -15,6 +15,9 @@ use OCP\IConfig;
use OCP\IRequest;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Matcher\CompiledUrlMatcher;
+use Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper;
use Symfony\Component\Routing\RouteCollection;
class CachingRouter extends Router {
@@ -57,60 +60,47 @@ class CachingRouter extends Router {
}
private function serializeRouteCollection(RouteCollection $collection): array {
- return array_map(
- fn (Route $route) => [$route->getPath(), $route->getDefaults(), $route->getRequirements(), $route->getOptions(), $route->getHost(), $route->getSchemes(), $route->getMethods(), $route->getCondition()],
- $collection->all(),
- );
- }
-
- private function unserializeRouteCollection(array $data): RouteCollection {
- $collection = new RouteCollection();
- foreach ($data as $name => $details) {
- $route = new Route(...$details);
- $collection->add($name, $route);
- }
- return $collection;
+ $dumper = new CompiledUrlMatcherDumper($collection);
+ return $dumper->getCompiledRoutes();
}
/**
- * Loads the routes
+ * Find the route matching $url
*
- * @param null|string $app
+ * @param string $url The url to find
+ * @throws \Exception
+ * @return array
*/
- public function loadRoutes($app = null): void {
- $this->eventLogger->start('cacheroute:load:' . $app, 'Loading Routes (using cache) for ' . $app);
- if (is_string($app)) {
- $app = $this->appManager->cleanAppId($app);
- }
-
- $requestedApp = $app;
- if ($this->loaded) {
- $this->eventLogger->end('cacheroute:load:' . $app);
- return;
+ public function findMatchingRoute(string $url): array {
+ $this->eventLogger->start('cacheroute:match');
+ $cachedRoutes = $this->cache->get('root:');
+ if (!$cachedRoutes) {
+ parent::loadRoutes();
+ $cachedRoutes = $this->serializeRouteCollection($this->root);
+ $this->cache->set('root:', $cachedRoutes, 3600);
}
- if (is_null($app)) {
- $cachedRoutes = $this->cache->get('root:');
- if ($cachedRoutes) {
- $this->root = $this->unserializeRouteCollection($cachedRoutes);
- $this->loaded = true;
- $this->eventLogger->end('cacheroute:load:' . $app);
- return;
- }
- } else {
- if (isset($this->loadedApps[$app])) {
- $this->eventLogger->end('cacheroute:load:' . $app);
- return;
- }
- $cachedRoutes = $this->cache->get('root:' . $requestedApp);
- if ($cachedRoutes) {
- $this->root = $this->unserializeRouteCollection($cachedRoutes);
- $this->loadedApps[$app] = true;
- $this->eventLogger->end('cacheroute:load:' . $app);
- return;
+ $matcher = new CompiledUrlMatcher($cachedRoutes, $this->context);
+ $this->eventLogger->start('cacheroute:url:match');
+ try {
+ $parameters = $matcher->match($url);
+ } catch (ResourceNotFoundException $e) {
+ if (!str_ends_with($url, '/')) {
+ // We allow links to apps/files? for backwards compatibility reasons
+ // However, since Symfony does not allow empty route names, the route
+ // we need to match is '/', so we need to append the '/' here.
+ try {
+ $parameters = $matcher->match($url . '/');
+ } catch (ResourceNotFoundException $newException) {
+ // If we still didn't match a route, we throw the original exception
+ throw $e;
+ }
+ } else {
+ throw $e;
}
}
- parent::loadRoutes($app);
- $this->cache->set('root:' . $requestedApp, $this->serializeRouteCollection($this->root), 3600);
- $this->eventLogger->end('cacheroute:load:' . $app);
+ $this->eventLogger->end('cacheroute:url:match');
+
+ $this->eventLogger->end('cacheroute:match');
+ return $parameters;
}
}