namespace wcf\action;
use CuyZ\Valinor\Mapper\MappingError;
+use FastRoute\ConfigureRoutes;
use FastRoute\Dispatcher\Result\MethodNotAllowed;
use FastRoute\Dispatcher\Result\NotMatched;
-use FastRoute\RouteCollector;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface;
use wcf\http\attribute\AllowHttpMethod;
+use wcf\system\cache\builder\ApiEndpointCacheBuilder;
use wcf\system\endpoint\event\ControllerCollecting;
use wcf\system\endpoint\IController;
use wcf\system\endpoint\RequestFailure;
use wcf\system\exception\UserInputException;
use wcf\system\request\RouteHandler;
-use function FastRoute\simpleDispatcher;
+use function FastRoute\cachedDispatcher;
/**
* Resolves and forwards API requests to the responsible controllers, exposing
return $this->toErrorResponse(RequestFailure::UnknownEndpoint, 'missing_endpoint');
}
- // TODO: This is currently very inefficient and should be cached in some
- // way, maybe even use a combined cache for both?
- $event = new ControllerCollecting();
- EventHandler::getInstance()->fire($event);
+ $dispatcher = cachedDispatcher(
+ static function (ConfigureRoutes $r) {
+ $event = new ControllerCollecting();
+ EventHandler::getInstance()->fire($event);
- $dispatcher = simpleDispatcher(
- static function (RouteCollector $r) use ($event) {
foreach ($event->getControllers() as $controller) {
$reflectionClass = new \ReflectionClass($controller);
$attribute = current($reflectionClass->getAttributes(RequestType::class, \ReflectionAttribute::IS_INSTANCEOF));
}
},
[
- // TODO: debug only
- 'cacheDisabled' => true,
+ 'cacheKey' => self::class,
+ 'cacheDriver' => ApiEndpointCacheBuilder::getInstance(),
]
);
--- /dev/null
+<?php
+
+namespace wcf\system\cache\builder;
+
+use FastRoute\Cache;
+
+/**
+ * Caches the list of available API endpoints.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since 6.1
+ */
+final class ApiEndpointCacheBuilder extends AbstractCacheBuilder implements Cache
+{
+ private \Closure $loader;
+
+ #[\Override]
+ public function get(string $key, callable $loader): array
+ {
+ $this->loader = \Closure::fromCallable($loader);
+
+ return $this->getData(['key' => $key]);
+ }
+
+ #[\Override]
+ public function rebuild(array $parameters)
+ {
+ if (!isset($this->loader)) {
+ throw new \RuntimeException('You may not access the API endpoint cache builder directly.');
+ }
+
+ $callable = $this->loader;
+
+ return $callable();
+ }
+}