From 303eafa4d5815e882f22991403df76a021230e4d Mon Sep 17 00:00:00 2001 From: bim-g Date: Fri, 21 Jul 2023 22:53:59 +0200 Subject: [PATCH 1/3] [ENH] Add API route group support --- .gitignore | 1 + .idea/php.xml | 17 +++++++++++++++++ .idea/wepesi_router.iml | 4 +++- example/controller/UserController.php | 4 +++- example/index.php | 10 +++++++++- example/middleware/UserValidation.php | 4 ++++ src/Router.php | 12 +++++++++++- 7 files changed, 48 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 57872d0..539257e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /vendor/ +.idea/* diff --git a/.idea/php.xml b/.idea/php.xml index 3b1bcf5..f2e8894 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -1,9 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/wepesi_router.iml b/.idea/wepesi_router.iml index c956989..7f6d08f 100644 --- a/.idea/wepesi_router.iml +++ b/.idea/wepesi_router.iml @@ -1,7 +1,9 @@ - + + + diff --git a/example/controller/UserController.php b/example/controller/UserController.php index a55f3ea..06ce84d 100644 --- a/example/controller/UserController.php +++ b/example/controller/UserController.php @@ -1,5 +1,7 @@ get('/', [userController::class,'get_users']); $router->group([ 'pattern'=>'/group', - 'middleware' => [userValidation::class,'detail_user'] + 'middleware' => [userValidation::class,'validateUser'] ],function () use($router){ $router->get('/:id/detail', [userController::class, 'get_user_detail']) ->middleware([userController::class, 'userExist']); $router->get('/:id/delete', 'Wepesi\Controller\UserController#delete_user'); }); }); +/** + * API Group + */ +$router->api('/users',function() use ($router){ + $router->get('/',function(){ + echo 'this is users api route'; + }); +}); /** * set custom 404 output */ diff --git a/example/middleware/UserValidation.php b/example/middleware/UserValidation.php index 23ed456..996b1da 100644 --- a/example/middleware/UserValidation.php +++ b/example/middleware/UserValidation.php @@ -10,4 +10,8 @@ function detail_user($id){ exit; } } + + function validateUser(){ + // implement here your validation + } } \ No newline at end of file diff --git a/src/Router.php b/src/Router.php index a18dd45..7fad899 100644 --- a/src/Router.php +++ b/src/Router.php @@ -17,10 +17,11 @@ class Router private string $baseRoute; private $notFoundCallback; private array $baseMiddleware; - + private static string $API_BaseRoute; use ExecuteRouteTrait; function __construct() { + self::$API_BaseRoute = ''; $this->baseRoute = ''; $this->routes = []; $this->_nameRoute = []; @@ -106,6 +107,15 @@ public function group($base_route, callable $callable): void $this->baseRoute = $cur_base_route; } + public function api($base_route, callable $callable){ + $patern = '/api'; + if(is_array($base_route)){ + $base_route['pattern'] = $patern .'/'. trim($base_route['pattern'],'/'); + }else{ + $base_route = $patern .'/'. trim($base_route,'/'); + } + return $this->group($base_route, $callable); + } /** * @param $middleware * @return callable[] From f6676c2a5e3724f4d0715f1ce9bca8778cecb69e Mon Sep 17 00:00:00 2001 From: bim-g Date: Fri, 21 Jul 2023 22:57:34 +0200 Subject: [PATCH 2/3] [DOC] Add copyright --- example/index.php | 1 + example/middleware/UserValidation.php | 3 +++ index.php | 4 ++++ src/Route.php | 5 ++++- src/Router.php | 9 ++++++--- src/Traits/ExceptionTrait.php | 3 +++ src/Traits/ExecuteRouteTrait.php | 3 +++ 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/example/index.php b/example/index.php index 43260f6..4637711 100644 --- a/example/index.php +++ b/example/index.php @@ -1,4 +1,5 @@ group($base_route, $callable); } diff --git a/src/Traits/ExceptionTrait.php b/src/Traits/ExceptionTrait.php index c051058..3a4356c 100644 --- a/src/Traits/ExceptionTrait.php +++ b/src/Traits/ExceptionTrait.php @@ -1,4 +1,7 @@ Date: Sun, 6 Aug 2023 12:34:48 +0200 Subject: [PATCH 3/3] [DOC] update API routing and trigger 404 --- README.md | 78 +++++++++++++++++++-------- composer.lock | 69 ++++++++++++++++++++++++ example/index.php | 26 +++++---- example/middleware/UserValidation.php | 7 ++- 4 files changed, 145 insertions(+), 35 deletions(-) create mode 100644 composer.lock diff --git a/README.md b/README.md index 75a569b..0364405 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,13 @@ Built by _([Boss Ibrahim Mussa](https://www.github.com/bim-g))_ and [Contributo - [Static Route Patterns](#route-patterns) - Dynamic Route Patterns: [Dynamic PCRE-based Route Patterns](#dynamic-pcre-based-route-patterns) or [Dynamic Placeholder-based Route Patterns](#dynamic-placeholder-based-route-patterns) - [Optional Route Subpatterns](#optional-route-subpatterns) -- [Supports `X-HTTP-Method-Override` header](#overriding-the-request-method) - [Subrouting / Group Routing](#Subrouting-/-Groupe-Routing) - [Allowance of `Class@Method` calls](#classmethod-calls) - [Before Route Middlewares](#before-route-middlewares) - [Before Router Middlewares / Before App Middlewares](#before-router-middlewares) +- [API Groupe Routing](#api-groupe-routing) +- [Supports `X-HTTP-Method-Override` header](#overriding-the-request-method) +- [Custom 404](#custom-404) - [Works fine in subfolders](#subfolder-support) @@ -200,15 +202,7 @@ $router->group('/articles', function() use ($router) { }); ``` -### `Setnotfound` route -You can set your custom notfound output -```php -$router->set404('**',function(){ - header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); - print('Not Found : ' . http_response_code()); - exit; -}); -``` + ### `Class#Method` calls @@ -231,6 +225,7 @@ $router->get('/users/profile', \Wepesi\Controller\Users::profile()); ``` Note: In case you are using static method, dont pass as string or in array. + ### Before Route Middleware `wepesi/routing` supports __Before Route Middlewares__, which are executed before the route handling is processed. @@ -258,25 +253,57 @@ $router->get('/admin/:id', function($id) { print_r("Last middleware before Route function"); }); ``` -Groupe route middleware, you should set the `pattern` and the `middleware` in order to make it work. +### API Groupe Routing + +You can define your API route inside the api method, and will auto complet api route fro you. ```php -$router->group([ -'pattern'=>'/admin/:id', -'middleware'=> function($id){ - print_r("Groupe middleware"); -} -], function($id) { - echo "admin id is:".$id; -})->middleware(function($id){ - print_r("First middleware"); -})->middleware(function($id){ - print_r("Last middleware before Route function"); +$router->api('/v1',function() use($router){ + $router->group('/users',function() use($router){ + $router->get('/',[appController::class,'getUsers']); + }); }); +// output +// /api/v1/users ``` + ### Overriding the request method Use `X-HTTP-Method-Override` to override the HTTP Request Method. Only works when the original Request Method is `POST`. Allowed values for `X-HTTP-Method-Override` are `PUT`, `DELETE`, or `PATCH`. +### Custom 404 + +The default 404 handler sets a 404 status code and exits. You can override this default 404 handler by using `$router->set404(callable);` + +```php +$router->set404(function() { + header('HTTP/1.1 404 Not Found'); + // ... do something special here +}); +``` + +You can also define multiple custom routes e.x. you want to define an `/api` route, you can print a custom 404 page: + +```php +$router->set404('**)?', function() { + header('HTTP/1.1 404 Not Found'); + header('Content-Type: application/json'); + + $jsonArray = array(); + $jsonArray['status'] = "404"; + $jsonArray['status_text'] = "route not defined"; + + echo json_encode($jsonArray); +}); +``` + +Also supported are `Class@Method` callables: + +```php +$router->set404([appController::class,'notfound']); +``` +The 404 handler will be executed when no route pattern was matched to the current URL. + +💡 You can also manually trigger the 404 handler by calling `$router->trigger404()` ## Integration with other libraries @@ -309,6 +336,13 @@ $router->put('/movies/:username', function($username) { }); ``` +## Subfolder support +```php +$router->api('/v1',function() use($router){ + include __DIR__.'/router/users.php'; +}); +``` + ## License `wepesi/routing` is released under the Apache-2.0 license. See the enclosed `LICENSE` for details. diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..fd20e77 --- /dev/null +++ b/composer.lock @@ -0,0 +1,69 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "9bf28e1a3d8c2630b8d6c5f961923a9f", + "packages": [ + { + "name": "wepesi/optionsresolver", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/bim-g/OptionsResolver.git", + "reference": "3bce1f7f9b2bf9e08e7b4d6c73bc6247777430da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bim-g/OptionsResolver/zipball/3bce1f7f9b2bf9e08e7b4d6c73bc6247777430da", + "reference": "3bce1f7f9b2bf9e08e7b4d6c73bc6247777430da", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Wepesi\\Resolver\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "bim-g", + "email": "ibmussafb@gmail.com" + } + ], + "description": "The OptionsResolver component helps you configure objects with option arrays. It supports default values, option constraints and lazy options.", + "support": { + "docs": "https://github.com/bim-g/OptionsResolver", + "email": "ibmussfb@gmail.com", + "forum": "https://github.com/bim-g/OptionsResolver", + "issues": "https://github.com/bim-g/OptionsResolver/issues", + "source": "https://github.com/bim-g/OptionsResolver", + "wiki": "https://github.com/bim-g/OptionsResolver" + }, + "time": "2022-12-29T12:44:59+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "wepesi/optionsresolver": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4", + "ext-json": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.2.0" +} diff --git a/example/index.php b/example/index.php index 4637711..74c1e3f 100644 --- a/example/index.php +++ b/example/index.php @@ -11,26 +11,30 @@ $router->get('/home',function (){ echo 'Welcom Home'; }); + +$router->get('/users', [userController::class,'get_users']); /** * Group */ -$router->group('/users', function () use ($router) { - $router->get('/', [userController::class,'get_users']); - $router->group([ - 'pattern'=>'/group', - 'middleware' => [userValidation::class,'validateUser'] - ],function () use($router){ - $router->get('/:id/detail', [userController::class, 'get_user_detail']) - ->middleware([userController::class, 'userExist']); - $router->get('/:id/delete', 'Wepesi\Controller\UserController#delete_user'); - }); + +$router->group([ + 'pattern'=>'/users', + 'middleware' => [userValidation::class, 'validateId'] +],function () use($router){ + $router->get('/:id/detail', [userController::class, 'get_user_detail']) + ->middleware([userController::class, 'userExist']); + $router->get('/:id/delete', 'Wepesi\Controller\UserController#delete_user'); }); /** * API Group */ $router->api('/users',function() use ($router){ $router->get('/',function(){ - echo 'this is users api route'; + echo json_encode([ + 'status' => http_response_code(), + 'message' => 'Welcom to Users API' + ],true); + exit(); }); }); /** diff --git a/example/middleware/UserValidation.php b/example/middleware/UserValidation.php index 31d8899..5afc824 100644 --- a/example/middleware/UserValidation.php +++ b/example/middleware/UserValidation.php @@ -14,7 +14,10 @@ function detail_user($id){ } } - function validateUser(){ - // implement here your validation + function validateId($id){ + if (!filter_var($id, FILTER_VALIDATE_INT)) { + echo 'your id should be an integer'; + exit; + } } } \ No newline at end of file