codezone / router
一个基于FastRoute的路由器,用于Roots-based WordPress插件和主题,或任何使用Illuminate/Container的插件或主题。
Requires
- php: >=7.4.0
- ext-json: *
- illuminate/container: ^v8.0.0
- illuminate/http: ^v8.0.0
- illuminate/support: ^v8.0.0
- nikic/fast-route: ^1.3.0
Requires (Dev)
- mreduar/laravel-phpcs: ^1.8
- phpunit/phpunit: ^9
- squizlabs/php_codesniffer: ^3.8
README
此包包含一个简单的路由系统实现,适用于Roots-based WordPress插件或站点,或任何利用容器的WordPress项目。
该路由器使用FastRoute分发库,并与Laravel框架中的Illuminate\Container\Container类集成,以管理依赖关系。
链接
- Sage:现代WordPress启动主题,具有开发工作流程。
- FastRoute:一个快速且高度灵活的PHP请求路由器,支持反向路由。
- Illuminate Container:Illuminate Container包用于管理类依赖关系和执行依赖注入,是Laravel框架的一部分。
使用方法
在PHP文件顶部导入Router类
use CodeZone\Router;
注册路由器
您首先必须将路由器注册到容器中。这可以在服务提供程序或插件的主文件中完成。
$router = Router::register($configArray);
在这个例子中,$configArray是一个必须包含一个'container'键的数组,其值为Illuminate\Container\Container实例。
$configArray = [ 'container' => $containerInstance // Illuminate\Container\Container ];
定义路由
一旦注册了路由器,您可以通过回调函数定义路由。
$dispatcher = $router->routes(function (Routes $r) { $r->get('/my-route', [Plugin\Controllers\MyController::class, 'index']); //or $r->get('/my-route', 'Plugin\Controllers\MyController@index'); //or $r->get('/my-route', function () { return "<h1>Hello World!</h1>"; }); });
路由参数
路由参数在路由路径中提供动态段,并允许路径包含可变部分。此包使用FastRoute语法定义路由参数。
以下是一个包含参数的路由示例
$r->get('/user/{id}', 'Plugin\Controllers\UserController@show');
在这种情况下,{id}是一个路由参数。在匹配路由时,FastRoute使用这些参数来捕获路径的部分,这允许灵活的路由策略。
您可以在FastRoute文档中了解更多关于路由参数的信息。
条件
在此路由系统中,您可以使用$r->condition(conditionClass, callback)定义条件路由。必须实现返回布尔值的test()方法的conditionClass类。只有当test()方法返回true时,才会执行回调。
以下是一个示例,其中IsFrontendPath是一个定义检查当前请求是否未指向管理页面的条件的类
namespace CodeZone\Router\Conditions; class IsFrontendPath implements Condition { public function test(): bool { return ! is_admin(); } }
您可以在路由定义中使用它,如下所示,以排除这些路由在管理页面上的注册
$r->condition(IsFrontendPath::class, function($r){ $r->get('/my-route', 'MyController'); });
您还可以使用codezone/router/conditions操作添加命名条件
add_action( Router::class . '\\' . 'conditions', function($conditions) { $conditions['isFrontend'] = IsFrontendPath::class; });
这使得路由条件定义更易于阅读
$r->condition('isFrontend', function($r){ $r->get('/my-route', 'MyController'); });
在这种情况下,只有当满足IsFrontendPath条件时,即请求不是管理请求时,才会由'MyController'处理器处理对'/my-route'的GET请求。
中间件
在此路由系统中,中间件提供了一组“层”,请求必须通过这些层才能到达您的应用程序处理器,并且在返回响应时也必须通过这些层。
中间件可以用于修改HTTP请求或响应,例如,或在请求处理前后运行代码。
中间件使用示例是一个LoggedIn类,它检查用户是否已登录
namespace CodeZone\Router\Middleware; use CodeZone\Router\Illuminate\Http\Request; use WP_HTTP_Response; class LoggedIn implements Middleware { public function handle( Request $request, WP_HTTP_Response $response, $next ) { if ( ! is_user_logged_in() ) { $response->set_status( 302 ); $response->set_data( wp_login_url( $request->getUri() ) ); } return $next( $request, $response ); } }
在这个例子中,如果用户未登录,中间件会将响应状态设置为302,并将用户重定向到登录页面。否则,它将继续中间件堆栈到下一个中间件。
全局中间件
全局中间件应用于所有路由,通过将中间件添加到扩展Laravel集合的Stack中来进行注册。
通过将中间件类名数组传递给Stack构造函数来创建一个新的堆栈。以下堆栈将处理您主题或插件的整个请求/响应生命周期。
use CodeZone\Router\Middleware\DispatchController; use CodeZone\Router\Middleware\HandleErrors; use CodeZone\Router\Middleware\HandleRedirects; use CodeZone\Router\Middleware\Render; use CodeZone\Router\Middleware\Route; use CodeZone\Router\Middleware\SetHeaders; use CodeZone\Router\Middleware\Stack; $middleware = [ Route::class, DispatchController::class, SetHeaders::class, HandleRedirects::class, HandleErrors::class, Render::class, ]; $stack = container()->makeWith(Stack::class, $middleware); $stack->run();
一旦有了堆栈实例,您可以将中间件类推送到它上面,以创建一个堆栈(或管道)的中间件,应用程序将运行通过。请求将按添加中间件的顺序通过堆栈移动。添加的中间件围绕应用程序处理,允许它们在应用程序之前和之后与请求进行交互。
路由中间件
除了为每个路由运行的全局中间件外,您还可以定义仅对特定路由运行的中间件。
您可以通过在定义路由后链式调用->middleware()方法来应用路由中间件
$r->get('/my-route', 'MyController')->middleware(Middleware::class);
在这个例子中,Middleware::class将只应用于'/my-route'路由。
注意,像条件一样,您可以将回调传递给middleware()方法
$r->get('/my-route', 'MyController')->middleware(Middleware::class, function () { //... });
将中间件应用于路由的第二种方法是将其包含在处理数组的三值中
$r->get('/my-route', ['MyController', 'myMethod', ['middleware' => Middleware::class]]); //or $r->get('/my-route', 'MyController')->middleware([MiddlewareOne::class, MiddlewareTwo::class]);
在这个例子中,Middleware::class只应用于/my-route路由。
这些方法允许您指定仅对某些路由执行的中间件。这为您在插件中何时使用不同中间件提供了更精细的控制。
命名中间件
您还可以使用codezone/router/middleware操作来添加命名中间件
add_action( Router::class . '\\' . 'middleware', function($middleware) { $middleware['auth'] = AuthMiddleware::class; });
这允许更易读的路由中间件定义
$r->get('/my-route', 'MyController', ['middleware' => 'auth']);
或
$r->middleware('auth', function($r){ $r->get('/my-route', 'MyController'); });
HasCap 中间件
此包包括一个UserHasCap中间件类,用于检查当前用户是否具有特定能力。您可以使用此中间件来限制对某些路由的访问。
假设您将命名中间件注册为['can' => UserHasCap::class],则可以这样使用它
$r->get('/my-route', 'MyController', ['middleware' => 'hasCap:manage_options,edit_posts']);
WordPress 钩子
此包使用apply_filters函数来控制某些功能。以下是您可以使用及其描述的钩子。
'codezone/router/response' 过滤器
此过滤器修改来自路由的HTTP响应
add_filter( Router::class . '\\' . 'response', function($response) { return $response; });
'codezone/router/error-codes' 过滤器
此过滤器用于修改错误代码。
add_filter( Router::class . '\\' . 'error_codes', function($error_codes) { unset($error_codes[404]); return $error_codes });
'codezone/router/routable_params' 过滤器
此过滤器允许您修改路由器中的可路由参数。这些参数被视为路由路径的一部分,而不仅仅是传递给Request对象。
add_filter(Router::class . '\\' . 'routable_params', function($params) { $params['action', 'page', 'tab']; }); // Would match $r->get('/contact?action=submit', 'Plugin\Controllers\ContactController@submit');
'codezone/router/routes' 过滤器
此过滤器允许您修改路由器中的路由
add_filter(Router::class . '\\' . 'routes', function($routes) { $routes->get('/my-route', 'MyController'); return $routes; });
'codezone/router/matched_routes' 过滤器
此过滤器允许您修改路由器中的匹配路由
add_filter(Router::class . '\\' . 'matched_routes', function($matchedRoutes) { $matchedRoutes[0] = true; $matchedRoutes[1] = [ 'handler' => [ 'Plugin\Controllers\MyController' 'myMethod' ], 'params' => [ 'id' => '3', ] ] return $matchedRoute; });
'codezone/router/render' 动作
渲染响应的操作。此操作在路由器匹配路由后和响应发送到浏览器之前调用。
add_action( Router::class . '\\' . 'render' ), function($response) { echo $response->getContent(); });
'codezone/router/render/json' 动作
将响应作为JSON渲染的操作。此操作在路由器匹配路由后和响应发送到浏览器之前调用。
add_action(Router::class . '\\' . 'render_json', function($response) { echo json_encode($response->getContent()); });
'codezone/router/middleware' 动作
添加命名中间件的操作。允许更易读的路由中间件定义。
add_action(Router::class . '\\' . 'middleware', function($middleware) { $middleware['auth'] = AuthMiddleware::class; });
'codezone/router/conditions' 动作
添加命名条件的操作。允许更易读的路由条件定义。
add_action(Router::class . '\\' . 'conditions', function($conditions) { $conditions['isFrontend'] = IsFrontendPath::class; });
'codezone/router/conditions/factory' 过滤器
手动处理命名条件实例化的过滤器。如果需要将额外参数传递给解析条件签名和传递给条件构造函数,请使用此过滤器。
add_filter(Router::class . '\\' . 'conditions_factory', function(Condition|null $instanceOrNull, array $attributes = []) { //Check if this is our named condition if ($name !== 'can') { return $instanceOrNull; } $className = $attributes['className'] ?? null; $name = $attributes['name'] ?? null; $signature = $attributes['signature'] ?? null; //The signature is the part of the route name after the ":". We need to break it into an array. $params = explode(',', $signature); return container->makeWith(HasCap::class, ['params' => $params]); });
'codezone/router/conditions/factories' 过滤器
作为使用上述过滤器的一种替代方案,您还可以实现Factory接口来注册一个条件工厂。
add_filter(Router::class . '\\' . 'conditions_factory', function(Condition|null $instanceOrNull, array $attributes = []) { //Check if this is our named condition if ($name !== 'can') { return $instanceOrNull; } $className = $attributes['className'] ?? null; $name = $attributes['name'] ?? null; $signature = $attributes['signature'] ?? null; //The signature is the part of the route name after the ":". We need to break it into an array. $params = explode(',', $signature); return container->makeWith(HasCap::class, ['params' => $params]); });
'codezone/router/middleware/factory' 过滤器
一个用于手动处理命名中间件实例化的过滤器。如果您需要传递额外的参数来解析中间件签名并将额外参数传递给中间件构造函数,请使用此过滤器。
add_filter(Router::class . '\\' . 'middleware_factory', function(Middleware|null $instanceOrNull, array $attributes = []) { //Check if this is our named middleware if ($name !== 'can') { return $instanceOrNull; } $className = $attributes['className'] ?? null; $name = $attributes['name'] ?? null; $signature = $attributes['signature'] ?? null; //The signature is the part of the route name after the ":". We need to break it into an array. $params = explode(',', $signature); return container->makeWith(UserHasCap::class, ['params' => $params]); });
'codezone/router/middleware/factories' 过滤器
作为使用上述过滤器的一种替代方案,您还可以实现Factory接口来注册一个中间件工厂。
add_filter(Router::class . '\\' . 'conditions_factories', function($factories) { $factories[UserHasCap::class] = UserHasCapFactory::class; return $factories; });