collectRoutes. * * @package Friendica\App */ class Router { const POST = 'POST'; const GET = 'GET'; const ALLOWED_METHODS = [ self::POST, self::GET, ]; /** @var RouteCollector */ protected $routeCollector; /** * @var string The HTTP method */ private $httpMethod; /** * @param array $server The $_SERVER variable * @param RouteCollector|null $routeCollector Optional the loaded Route collector */ public function __construct(array $server, RouteCollector $routeCollector = null) { $httpMethod = $server['REQUEST_METHOD'] ?? self::GET; $this->httpMethod = in_array($httpMethod, self::ALLOWED_METHODS) ? $httpMethod : self::GET; $this->routeCollector = isset($routeCollector) ? $routeCollector : new RouteCollector(new Std(), new GroupCountBased()); } /** * @param array $routes The routes to add to the Router * * @return self The router instance with the loaded routes * * @throws InternalServerErrorException In case of invalid configs */ public function addRoutes(array $routes) { $routeCollector = (isset($this->routeCollector) ? $this->routeCollector : new RouteCollector(new Std(), new GroupCountBased())); foreach ($routes as $route => $config) { if ($this->isGroup($config)) { $this->addGroup($route, $config, $routeCollector); } elseif ($this->isRoute($config)) { $routeCollector->addRoute($config[1], $route, $config[0]); } else { throw new InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'"); } } $this->routeCollector = $routeCollector; return $this; } /** * Adds a group of routes to a given group * * @param string $groupRoute The route of the group * @param array $routes The routes of the group * @param RouteCollector $routeCollector The route collector to add this group */ private function addGroup(string $groupRoute, array $routes, RouteCollector $routeCollector) { $routeCollector->addGroup($groupRoute, function (RouteCollector $routeCollector) use ($routes) { foreach ($routes as $route => $config) { if ($this->isGroup($config)) { $this->addGroup($route, $config, $routeCollector); } elseif ($this->isRoute($config)) { $routeCollector->addRoute($config[1], $route, $config[0]); }else { throw new InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'"); } } }); } /** * Returns true in case the config is a group config * * @param array $config * * @return bool */ private function isGroup(array $config) { return is_array($config) && is_string(array_keys($config)[0]) && // This entry should NOT be a BaseModule (substr(array_keys($config)[0], 0, strlen('Friendica\Module')) !== 'Friendica\Module') && // The second argument is an array (another routes) is_array(array_values($config)[0]); } /** * Returns true in case the config is a route config * * @param array $config * * @return bool */ private function isRoute(array $config) { return // The config array should at least have one entry !empty($config[0]) && // This entry should be a BaseModule (substr($config[0], 0, strlen('Friendica\Module')) === 'Friendica\Module') && // Either there is no other argument (empty($config[1]) || // Or the second argument is an array (HTTP-Methods) is_array($config[1])); } /** * The current route collector * * @return RouteCollector|null */ public function getRouteCollector() { return $this->routeCollector; } /** * Returns the relevant module class name for the given page URI or NULL if no route rule matched. * * @param string $cmd The path component of the request URL without the query string * * @return string|null A Friendica\BaseModule-extending class name if a route rule matched */ public function getModuleClass($cmd) { // Add routes from addons Hook::callAll('route_collection', $this->routeCollector); $cmd = '/' . ltrim($cmd, '/'); $dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->routeCollector->getData()); $moduleClass = null; $routeInfo = $dispatcher->dispatch($this->httpMethod, $cmd); if ($routeInfo[0] === Dispatcher::FOUND) { $moduleClass = $routeInfo[1]; } return $moduleClass; } }