gac/routing

自定义路由库,特别适用于快速API开发

v3.1.7 2024-08-22 19:15 UTC

README

这个库允许您创建静态或动态路由。这个库受到了 PHP Slim 框架 的启发

PHP Tests License Total Downloads

通过 composer 安装

composer require gac/routing

手动安装

发布页面 下载最新版本。

别忘了将以下 include_once 语句添加到您的 php 文件中

include_once "./Exceptions/CallbackNotFound.php";
include_once "./Exceptions/RouteNotFoundException.php";
include_once "./Request.php";
include_once "./Routes.php";

安装后

为了正确使用这个库,您需要在项目的根目录下创建一个 .htaccess 文件。

.htaccess 文件的示例可能如下所示

RewriteEngine On

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.+)$ index.php [QSA,L]

注意

如果您将主文件重命名了,请将 .htaccess 文件中的 index.php 替换为您的主应用文件。

快速开始

示例代码,帮助您快速开始开发。

use Gac\Routing\Exceptions\CallbackNotFound;
use Gac\Routing\Exceptions\RouteNotFoundException;
use Gac\Routing\Request;
use Gac\Routing\Response;
use Gac\Routing\Routes;

include_once "vendor/autoload.php"; # IF YOU'RE USING composer

$routes = new Routes();
try {
    $routes->add('/', function (Request $request) {
        // Old way of doing it, still supported until v4
        $request
            ->status(200, "OK")
            ->send(["message" => "Welcome"]);

        // New way of doing it
        Response::
        withHeader("Content-Type", "application/json")::
        withStatus(200, 'OK')::
        withBody([ "message" => "Welcome" ])::
        send();
    });
    
    $routes->route('/', function (Request $request) {
        // Old way of doing it, still supported until v4
        $request
            ->status(200, "OK")
            ->send(["message" => "Welcome"]);

        // New way of doing it
        Response::
        withHeader("Content-Type", "application/json")::
        withStatus(200, 'OK')::
        withBody([ "message" => "Welcome" ])::
        send();
    }, [Routes::POST])->save();

    $routes->route();
} catch (RouteNotFoundException $ex) {
    // Old way of doing it, still supported until v4
    $routes->request->status(404, "Route not found")->send(["error" => ["message" => $ex->getMessage()]]);
    
    // New way of doing it
    Response::withStatus(404, 'Route not found')::send(["error" => [ "message" => $ex->getMessage() ]]);
} catch (CallbackNotFound $ex) {
    // Old way of doing it, still supported until v4
    $routes->request->status(404, "Callback not found")->send(["error" => ["message" => $ex->getMessage()]]);
    
    // New way of doing it
    Response::withStatus(404, 'Callback not found')::send(["error" => [ "message" => $ex->getMessage() ]]);
} catch (Exception $ex) {
    $code = $ex->getCode() ?? 500;
    
    // Old way of doing it, still supported until v4
    $routes->request->status($code)->send(["error" => ["message" => $ex->getMessage()]]);
    
    // New way of doing it
    Response::withStatus($code)::send(["error" => [ "message" => $ex->getMessage() ]]);
}

示例

动态路由示例

$routes->add('/test/{int:userID}-{username}/{float:amount}/{bool:valid}', function (
    Request $request,
    int $userID,
    string $username,
    float $amount,
    bool $valid
) {
    echo 'Dynamic route content here';
});

链式路由

在使用链式方法时,最后一个方法可以使用 ->save()->add() 来表示链的结束

注意

  • ->save(true|false) 方法仍然可以链式使用
    • false(默认值是 true)传递给 ->save() 方法将保留该链中所有前面的前缀和中间件
  • ->add() 不能 链式使用,应该是链的最后一个调用
$routes
    ->prefix('/user') // all the routes added will have the /user prefix
    ->middleware([ 'verify_token' ]) // all the routes added will have the verify_token middleware applied
    ->route('/', [ HomeController::class, 'getUsers' ], Routes::GET)
    ->route('/', [ HomeController::class, 'addUser' ], Routes::POST)
    ->route('/', [ HomeController::class, 'updateUser' ], Routes::PATCH)
    ->route('/', [ HomeController::class, 'replaceUser' ], Routes::PUT)
    ->add('/test', [ HomeController::class, 'deleteUser' ], Routes::DELETE);

链式路由,以 save 结束

$routes
    ->prefix("/test")
    ->middleware(['decode_token'])
    ->route("/t0", function(Request $request){})
    ->get("/t1", function (){})
    ->post("/t2", function (){})
    ->put("/t3", function (){})
    ->patch("/t4", function (){})
    ->delete("/t5", function (){})
    ->save();

链式路由,在一个调用中包含多个链

$routes
    ->prefix("/test")
    ->middleware([ 'decode_token' ])
    ->get("/t1", function () { }) // route would be: /test/t1
    ->get("/t2", function () { }) // route would be: /test/t2
    ->get("/t3", function () { }) // route would be: /test/t3
    ->save(false) // by passing the false argument here, we keep all the previous shared data from the chain (previous prefix(es) and middlewares)
    ->prefix("/test2")
    ->middleware([ "verify_token" ])
    ->get("/t4", function () { }) // route would be: /test/test2/t4
    ->get("/t5", function () { }) // route would be: /test/test2/t5
    ->get("/t6", function () { }) // route would be: /test/test2/t6
    ->save() // by not passing the false argument here, we are removing all shared data from the previous chains (previous prefix(es) and middlewares)
    ->prefix("/test3")
    ->middleware([ "verify_token" ])
    ->get("/t7", function () { }) // route would be: /test3/t7
    ->get("/t8", function () { }) // route would be: /test3/t8
    ->get("/t9", function () { }) // route would be: /test3/t9
    ->add(); //using save or add at the end makes the chaining stop and allows for other independent routes to be added

传递参数到中间件方法

当与中间件一起工作时,如果需要,您也可以传递它们参数

use Gac\Routing\Response;

$routes
    ->middleware([
        'test_middleware',
        'has_roles' => 'admin,user',
        [ Middleware::class, 'test_method' ],
        [ Middleware::class, 'has_role', 'Admin', 'Moderator', [ 'User', 'Bot' ] ],
    ])
    ->add('/test', function (Request $request) {
        // Old way of doing it, still supported until v4
        $request->send([ 'msg' => 'testing' ]);
        
        //New way of doing it
        Response::send([ "msg" => "testing" ]);
    });

只要指定了正确的类型,每个中间件函数也可以在任何位置接受类型为 Gac\Routing\Request 的参数。

可选参数

$routes->add(
    '/demo/{id?}',
    function($id = 'defaultValue'){
    	echo "ID: . $id";
    },
    Routes::GET
);

当使用 /demo 调用此端点时,它将输出 ID: defaultValue,而使用 /demo/123 时将输出 ID: 123

在路由类上使用依赖注入

当使用类来处理您的路由回调,并且这些类有一些需要通过构造函数注入的依赖时,您可以指定要注入的参数数组,或者让库尝试自动注入类。

$routes->add(
    '/demo',
    [ 
        HomeController::class, 
        'dependency_injection_test', 
        [ new InjectedClass() ] 
    ],
    Routes::GET
);

您还可以使用命名参数或混合使用它们

$routes->add(
    '/demo',
    [ 
        HomeController::class, 
        'dependency_injection_test', 
        [ "injected_var" => new InjectedClass(), new Middleware ] 
    ],
    Routes::GET
);

让库自动注入类到构造函数中

$routes->add(
    '/demo',
    [ InjectController::class ],
    Routes::GET
);

注意

如果没有提供任何类,库将始终尝试自动注入类(将跳过默认值为 null 的类),如果您使用类作为回调。

对于单方法类,请使用 __invoke

$routes->add(
    '/invoke',
    [ HomeController::class ],
    Routes::GET
);

您还可以使用 __invoke 进行依赖注入

$routes->add(
    '/invoke',
    [ 
        HomeController::class, 
        [ new InjectedClass() ] 
    ],
    Routes::GET
);

更多示例请查看 sample 文件夹 中的 index.php 文件

文档

源代码文档可以在 PHP Routing 文档 页面找到

特性

  • 静态路由
  • 动态路由
  • 动态路由与可选参数
  • 中间件
    • 向中间件传递参数
  • 路由前缀
  • 方法链式调用
  • 类上的依赖注入
    • 手动注入
    • 自动注入