'api', 'GET test/(.*)' => 'apiWithText', ]; } /** * method for api * @return JsonResponse */ public function api(): JsonResponse { return new JsonResponse(200,['test'=>'OK']); } /** * method for api * @param string $text * @return JsonResponse */ public function apiWithText(string $text): JsonResponse { return new JsonResponse(200,['text'=>$text]); } /** * Triggered after Pico has loaded all available plugins * * This event is triggered nevertheless the plugin is enabled or not. * It is NOT guaranteed that plugin dependencies are fulfilled! * * * @param object[] $plugins loaded plugin instances */ public function onPluginsLoaded(array $plugins) { $this->routesOnPageRendered = []; foreach($plugins as $plugin){ if (method_exists($plugin,'registerOnPageRenderedApiRoutes')){ $routes = $plugin->registerOnPageRenderedApiRoutes(); if (is_array($routes)){ foreach($routes as $route => $methodName){ if (is_string($methodName) && method_exists($plugin,$methodName)){ $this->routesOnPageRendered[$route] = [$plugin,$methodName]; } } } } } } /** * If the call is a save query, save the edited regions and output the JSON response. * * Triggered after Pico has rendered the page * * @param string &$output contents which will be sent to the user * @return void */ public function onPageRendered(&$output) { if (isset($_GET['api'])){ $route = $this->getPico()->getUrlParameter( 'api', FILTER_UNSAFE_RAW, [ 'default' => '' ], [ FILTER_FLAG_STRIP_LOW, FILTER_FLAG_STRIP_HIGH ] ); $route = trim($route); if (empty($route)){ $output = (new JsonResponse(404,['code'=>404,'reason'=>'Empty api route']))->send(); } elseif (!preg_match('/^[A-Za-z0-9_\-.\/]+$/',$route)) { $output = (new JsonResponse(404,['code'=>404,'reason'=>"Route '$route' use forbidden characters !"]))->send(); } else { ob_start(); $response = null; try { $data = $this->searchCorrespondingRoute($route); $response = call_user_func_array([$data['plugin'],$data['methodName']],$data['params']); if (!($response instanceof JsonResponse)){ $response = null; throw new Exception("Return of '{$data['methodName']}' should be instanceof of 'JsonResponse'"); } } catch (BadMethodException $th) { $code = 405; $content = ['reason'=>$th->getMessage()]; } catch (NotFoundRouteException $th) { $code = 404; $content = ['reason'=>"Route '$route' not found !"]; } catch (Throwable $th) { $code = 500; $content = ['reason'=>$th->__toString()]; } $rawOutput = ob_get_contents(); ob_end_clean(); if (empty($response)){ if (!empty($rawOutput)){ $content['rawOutput'] = $rawOutput; } $content = array_merge(['code'=>$code],$content); $response = (new JsonResponse($code,$content)); } elseif (!empty($rawOutput)) { $response->mergeInContent(compact(['rawOutput'])); } $output = $response->send(); } } } /** * search corresponding route * @param string $route * @return array ['plugin'=>$plugin,'methodName'=>string,'params'=>array] * @throws BadMethodException * @throws NotFoundRouteException */ protected function searchCorrespondingRoute(string $route): array { if (empty($_SERVER['REQUEST_METHOD'])){ throw new BadMethodException('Method not defined'); } $method = $_SERVER['REQUEST_METHOD']; if (!in_array($method,['GET','POST'],true)){ throw new BadMethodException('Not allowed method'); } $splittedRoute = explode('/',$route); $nb = count($splittedRoute); $badMethod = false; for ($i=0; $i < 2**$nb; $i++) { $params = []; $splittedRouteFiltered = []; foreach ($splittedRoute as $idx => $value) { $currentPower = $nb - $idx - 1 ; if ((2**$currentPower & $i) > 0){ $splittedRouteFiltered[] = '(.*)'; $params[] = $value; } else { $splittedRouteFiltered[] = $value; } } $searchingRoute = implode('/',$splittedRouteFiltered); $data = []; if (array_key_exists("$method $searchingRoute",$this->routesOnPageRendered)){ $data = $this->routesOnPageRendered["$method $searchingRoute"]; } elseif (array_key_exists("$searchingRoute",$this->routesOnPageRendered)){ $data = $this->routesOnPageRendered["$searchingRoute"]; } if (!empty($data)){ return [ 'plugin' => $data[0], 'methodName' => $data[1], 'params' => $params ]; } elseif (!$badMethod && array_key_exists((($method == 'GET') ? 'POST' : 'GET' )." $searchingRoute",$this->routesOnPageRendered)){ $badMethod = true; } } if ($badMethod){ throw new BadMethodException('Not allowed method'); } throw new NotFoundRouteException(''); } }