_endpoints; } /** * Find an endpoint which matches this request and `execute()` it. * * @param string $route Route to find endpoint for. * @param string $method HTTP method to find endpoint for. * @param Nameless2API $api Instance of api instance to provide the endpoint. */ public function handle(string $route, string $method, Nameless2API $api): void { $available_methods = []; $matched_endpoint = null; foreach ($this->getAll() as $endpoint) { if (($vars = $this->matchRoute($endpoint, $route)) !== false) { // Save that we actually found an endpoint $matched_endpoint = $endpoint; // Save the methods that are available for this endpoint $available_methods[] = $endpoint->getMethod(); if ($endpoint->getMethod() === $method) { if (!$endpoint->isAuthorised($api)) { $api->throwError( $endpoint->getAuthType() === EndpointBase::AUTH_TYPE_API_KEY ? Nameless2API::ERROR_INVALID_API_KEY : Nameless2API::ERROR_NOT_AUTHORIZED, null, Response::HTTP_UNAUTHORIZED ); } if (!method_exists($endpoint, 'execute')) { throw new InvalidArgumentException("Endpoint class must contain an 'execute()' method."); } $reflection = new ReflectionMethod($endpoint, 'execute'); if ($reflection->getNumberOfParameters() !== (count($endpoint->customParams()) + count($vars) + 1)) { throw new InvalidArgumentException("Endpoint's 'execute()' method must take " . (count($endpoint->customParams()) + count($vars) + 1) . ' arguments. Endpoint: ' . $endpoint->getRoute()); } $endpoint->execute( $api, ...array_merge($endpoint->customParams(), array_map(function ($type, $value) use ($api) { return $this::transform($api, $type, $value); }, array_keys($vars), $vars)) ); return; } } } if ($matched_endpoint !== null) { $api->throwError(Nameless2API::ERROR_INVALID_API_METHOD, "The $route endpoint only accepts " . implode(', ', $available_methods) . ", $method was used.", Response::HTTP_METHOD_NOT_ALLOWED); } $api->throwError(Nameless2API::ERROR_INVALID_API_METHOD, 'If you are seeing this while in a browser, this means your API is functioning!', Response::HTTP_NOT_FOUND); } /** * Recursively scan, preload and register EndpointBase classes in a folder. * * @see EndpointBase * * @param string $path Path to scan from. */ public function loadEndpoints(string $path): void { $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)); foreach ($rii as $file) { if ($file->isDir()) { $this->loadEndpoints($file); return; } if ($file->getFilename() === '.DS_Store') { continue; } require_once($file->getPathName()); $endpoint_class_name = str_replace('.php', '', $file->getFilename()); /** @var EndpointBase $endpoint */ $endpoint = new $endpoint_class_name(); $key = $endpoint->getRoute() . '-' . $endpoint->getMethod(); if (!isset($this->_endpoints[$key])) { $this->_endpoints[$key] = $endpoint; } } } }