diff --git a/RestApi.module b/RestApi.module index e3496d3..ad8b8ac 100644 --- a/RestApi.module +++ b/RestApi.module @@ -20,12 +20,9 @@ require_once __DIR__ . "/Router.php"; // }); class RestApi extends WireData implements Module { - - // public function __construct() { - // echo "construct"; - // set_error_handler(array($this, 'handleErrorCallback')); - // set_exception_handler(array($this, 'handleErrorCallback')); - // } + + private $apiTemplates = ['api-endpoint-route', 'api-endpoint-method']; + private $apiFields = ['api_fastrouteoption', 'api_class', 'api_class_method', 'api_auth']; public function init() { $this->addHookBefore('ProcessPageView::execute', $this, 'checkIfApiRequest'); @@ -50,13 +47,20 @@ class RestApi extends WireData implements Module { public function ___install() { $apiPath = "{$this->config->paths->site}api"; + $apiClassesPath = "{$this->config->paths->site}api/classes"; $routesPath = "{$this->config->paths->site}api/Routes.php"; - $examplesPath = "{$this->config->paths->site}api/Example.php"; + $examplesPath = "{$apiClassesPath}/Example.php"; + $examplesContent = "{$apiClassesPath}/Blog.php"; if (!file_exists($apiPath)) { $this->files->mkdir("{$this->config->paths->site}api"); $this->message("$this->className: Created api directory: $apiPath"); - } + } + + if (!file_exists($apiClassesPath)) { + $this->files->mkdir("{$this->config->paths->site}api/classes"); + $this->message("$this->className: Created classes directory: $apiPath"); + } if (!file_exists($routesPath)) { $this->files->copy(__DIR__ . "/apiTemplate/Routes.php", $routesPath); @@ -64,13 +68,132 @@ class RestApi extends WireData implements Module { } if (!file_exists($examplesPath)) { - $this->files->copy(__DIR__ . "/apiTemplate/Example.php", $examplesPath); - $this->message("$this->className: Created Example.php in: $examplesPath"); + $this->files->copy(__DIR__ . "/apiTemplate/Example.php", $apiClassesPath); + $this->message("$this->className: Created Example class in: $apiClassesPath"); + } + + if (!file_exists($examplesContent)) { + $this->files->copy(__DIR__ . "/apiTemplate/Blog.php", $apiClassesPath); + $this->message("$this->className: Created Example Content class in: $apiClassesPath"); + } + + $this->createTemplates(); + $this->createEndpoints(); + } + + private function createTemplates() { + + foreach($this->apiTemplates as $template){ + // new fieldgroup for template + $fg = new Fieldgroup(); + $fg->name = $template; + $fg->add($this->fields->get('title')); + $fg->save(); + // new template for routes and methods + $tRoute = new Template(); + $tRoute->name = $template; + $tRoute->fieldgroup = $fg; + $tRoute->save(); + $this->message("$this->className: Created API Templates"); + } + // add api-endpoint-method fields to api-endpoint-method template + foreach($this->apiFields as $methodField){ + $f = new Field(); // create new field object + if($methodField == 'api_auth'){ + $f->type = $this->modules->get("FieldtypeCheckbox"); + } else { + $f->type = $this->modules->get("FieldtypeText"); + } + $f->name = $methodField; + $f->save(); + $fg = wire('fieldgroups')->get('api-endpoint-method'); + $fg->add($f); + $fg->save(); + $this->message("$this->className: Created API Fields"); } } + + private function createEndpoints() { + //add a container page for our routes + // needed for pw driven routes + $endpoints = new Page(); + $endpoints->template = 'api-endpoint-route'; + $endpoints->parent = wire('pages')->get(1); + $endpoints->name = 'api-endpoints'; + $endpoints->title = 'API ENDPOINTS'; + $endpoints->save(); + $endpoints->addStatus(Page::statusHidden); + $endpoints->save(); + + //add some example routes to provide a endpoint to get all content + $exRoute = new Page(); + $exRoute->template = 'api-endpoint-route'; + $exRoute->parent = $endpoints; + $exRoute->name = 'contents'; + $exRoute->title = 'contents'; + $exRoute->save(); + + $exMethodPosts = new Page(); + $exMethodPosts->template = 'api-endpoint-method'; + $exMethodPosts->parent = $exRoute; + $exMethodPosts->name = 'get'; + $exMethodPosts->title = 'GET'; + $exMethodPosts->save(); + $exMethodPosts->api_class = 'Blog'; + $exMethodPosts->api_class_method = 'getPosts'; + $exMethodPosts->api_auth = false; + $exMethodPosts->save(); + + $exRoutePost = new Page(); + $exRoutePost->template = 'api-endpoint-route'; + $exRoutePost->parent = $endpoints; + $exRoutePost->name = 'content'; + $exRoutePost->title = 'content'; + $exRoutePost->save(); + + $exMethod = new Page(); + $exMethod->template = 'api-endpoint-method'; + $exMethod->parent = $exRoutePost; + $exMethod->name = 'get'; + $exMethod->title = 'GET'; + $exMethod->save(); + $exMethod->api_fastrouteoption = '{id:\d+}'; + $exMethod->api_class = 'Blog'; + $exMethod->api_class_method = 'getPost'; + $exMethod->api_auth = true; + $exMethod->save(); + + $this->message("$this->className: Created API Example Endpoints"); + } public function ___uninstall() { + $this->message("$this->className: You need to remove the site/api folder yourself if you're not planning on using it anymore"); + $apiTemplates = ['api-endpoint-route','api-endpoint-method']; + $endpoints = wire('pages')->get('name=api-endpoints'); + + if($endpoints->id){ + wire('pages')->delete($endpoints, true); + } + + foreach($this->apiTemplates as $template) { + $t = wire('templates')->get($template); + if($t->id){ + wire('templates')->delete($t); + } + $fieldgroups = wire('fieldgroups'); + $fg = $fieldgroups->get($template); + if($fg){ + $fieldgroups->delete($fg); + } + } + + foreach($this->apiFields as $field) { + $f = wire('fields')->get($field); + if($f->id){ + wire('fields')->delete($f); + } + } } public function ___upgrade($fromVersion, $toVersion) { diff --git a/RestApiHelper.php b/RestApiHelper.php index 1083c31..62b45ad 100644 --- a/RestApiHelper.php +++ b/RestApiHelper.php @@ -25,7 +25,7 @@ public static function checkAndSanitizeRequiredParameters($data, $params) { if (!isset($sanitizer[1])) $sanitizer = 'text'; else $sanitizer = $sanitizer[1]; - if(!method_exists(wire('sanitizer'), $sanitizer)) throw new \Exception("Sanitizer: '$sanitizer' ist no valid sanitizer", 400); + if(!method_exists(wire('sanitizer'), $sanitizer)) throw new \Exception("Sanitizer: '$sanitizer' is no valid sanitizer", 400); $data->$name = wire('sanitizer')->$sanitizer($data->$name); } diff --git a/apiTemplate/Blog.php b/apiTemplate/Blog.php new file mode 100644 index 0000000..7fc5f70 --- /dev/null +++ b/apiTemplate/Blog.php @@ -0,0 +1,41 @@ +get(1)->children; + + $response = new \StdClass(); + $response->posts = []; + + foreach($posts as $post) { + array_push($response->posts, [ + "id" => $post->id, + "title" => $post->title + ]); + } + + return $response; + } + + public static function getPost($data) { + $data = RestApiHelper::checkAndSanitizeRequiredParameters($data, ['id|int']); + + $response = new \StdClass(); + + $post = wire('pages')->get($data->id); + + if(!$post->id) throw new \Exception('Post not found'); + + $response->id = $post->id; + foreach($post->template->fields as $field) { + $response->{$field->name} = $post->{$field->name}; + } + + return $response; + + } + +} \ No newline at end of file diff --git a/apiTemplate/Routes.php b/apiTemplate/Routes.php index 52d9a57..c60a138 100644 --- a/apiTemplate/Routes.php +++ b/apiTemplate/Routes.php @@ -1,9 +1,15 @@ get('/api-endpoints/')->children; + require_once wire('config')->paths->RestApi . "vendor/autoload.php"; require_once wire('config')->paths->RestApi . "RestApiHelper.php"; -require_once __DIR__ . "/Example.php"; +foreach($apiClasses as $apiClass){ + require_once $classPath . $apiClass; +} $routes = [ ['OPTIONS', 'test', RestApiHelper::class, 'preflight', ['auth' => false]], // this is needed for CORS Requests @@ -14,4 +20,23 @@ ['GET', '', Example::class, 'getAllUsers', ["auth" => false]], ['GET', '{id:\d+}', Example::class, 'getUser', ["auth" => false]], // check: https://github.com/nikic/FastRoute ], -]; \ No newline at end of file +]; + +foreach($endpoints as $endpoint){ + $endpointOptions = false; + $endpointOptions[] = ['OPTIONS', '', RestApiHelper::class, 'preflight', ['auth' => false]]; + foreach($endpoint->children as $method){ + $auth = false; + if($method->api_auth){ + $auth = true; + } + $endpointOptions[] = [ + $method->title, + $method->api_fastrouteoption, + __NAMESPACE__ . '\\' . $method->api_class, + $method->api_class_method, + ['auth' => $auth], + ]; + $routes[$endpoint->title] = $endpointOptions; + } +} \ No newline at end of file