jetfirephp / routing
JetFire - 路由
Requires
- php: >=5.4.0
Requires (Dev)
- phpunit/phpunit: 4.8.*
- symfony/yaml: v2.8.2
Suggests
- jetfire/autoload: For loading your class
This package is not auto-updated.
Last update: 2024-09-14 18:36:48 UTC
README
A simple & powerful router for PHP 5.4+
特性
V1.3
V1.2
V1.1
V1.0
- 支持静态和动态路由模式
- 支持REST路由
- 支持使用命名路由进行反向路由
- Uri匹配器
- 数组匹配器
- Closure解析器
- 模板解析器
- 控制器解析器
- 路由中间件
- 与其他库集成
入门
- 需要PHP 5.4+
- 使用Composer安装
JetFire\Routing
- 设置URL重写,以便所有请求都由index.php处理
安装
通过composer
$ composer require jetfirephp/routing
.htaccess
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.[a-zA-Z0-9\-\_\/]*)$ index.php?url=$1 [QSA,L]
用法
创建JetFire\Routing\RouteCollection
实例并定义您的路由。然后创建JetFire\Routing\Router
实例并运行您的路由。
// Require composer autoloader require __DIR__ . '/vendor/autoload.php'; // Create RouteCollection instance $collection = new \JetFire\Routing\RouteCollection(); // Define your routes // ... // Create an instance of Router $router = new \JetFire\Routing\Router($collection) // select your matcher $matcher1 = new \JetFire\Routing\Matcher\ArrayMatcher($router); $matcher2 = new \JetFire\Routing\Matcher\UriMatcher($router); // set your matcher to the router $router->setMatcher([$matcher1,$matcher2]) // Run it! $router->run();
匹配器
JetFire\Routing
为您的路由提供两种类型的匹配器:JetFire\Routing\Matcher\ArrayMatcher
和JetFire\Routing\Matcher\UriMatcher
Uri匹配器
使用Uri匹配器,您不需要定义路由。根据uri,它可以检查当前url是否存在目标。但您必须将视图目录路径和控制器命名空间定义为集合
$options = [ 'view_dir' => '_VIEW_DIR_PATH_', 'ctrl_namespace' => '_CONTROLLERS_NAMESPACE_' ]; $collection = new \JetFire\Routing\RouteCollection(null,$options); // or $collection = new \JetFire\Routing\RouteCollection(); $collection->setOption($options); // or $collection = new \JetFire\Routing\RouteCollection(); $collection->addRoutes(null,$options)
例如,如果uri是:/home/index
解析器
以下是Uri匹配器解析器的列表
$resolver = [ 'isControllerAndTemplate', 'isController', 'isTemplate' ];
模板解析器
Uri匹配器检查/_VIEW_DIR_PATH_/Home
目录中是否存在index.php
文件。
如果您想检查其他扩展(html、json等),可以像这样配置路由
$router->setConfig([ // Define your template extension like this 'templateExtension' => ['.php','.html','.twig','.json','.xml'], ]);
控制器解析器
使用控制器解析器,Uri匹配器检查命名空间_CONTROLLERS_NAMESPACE_
中的控制器HomeController
是否有index
方法。您必须在匹配之前要求控制器,或者可以使用自定义自动加载器来加载控制器。Uri匹配器还支持动态路由。例如,如果uri是:/home/user/peter/parker
,则必须有一个方法user
,它有两个参数如下所示
class HomeController { public function user($firstName,$lastName){ // $firstName = peter // $lastName = parker } }
数组匹配器
使用数组匹配器,您必须像这样添加路由
$options = [ 'view_dir' => '_VIEW_DIR_PATH_', 'ctrl_namespace' => '_CONTROLLERS_NAMESPACE_' ]; // addRoutes expect an array argument $collection->addRoutes([ '/home/index' => '_TARGET_' ],$options); // or a file containing an array $collection->addRoutes('path_to_array_file',$options);
我们建议您在单独的文件中定义路由,并将路径传递给addRoutes()
方法。
// routes.php file return [ '/home/index' => '_TARGET_' ];
解析器
以下是Uri匹配器解析器的列表
$resolver = [ 'isControllerAndTemplate', 'isClosureAndTemplate', 'isClosure', 'isController', 'isTemplate' ];
您有5种可能的数组路由操作。我们假设您正在使用单独的路由文件。
模板解析器
return [ // static route '/home/index' => 'Home/index.php', // dynamic route with arguments '/home/user-:id-:slug' => [ 'use' => 'Home/page.html', 'arguments' => ['id' => '[0-9]+','slug' => '[a-z-]*'], ], ];
控制器解析器
return [ // static route '/home/index' => 'HomeController@index', // dynamic route with arguments '/home/user-:id-:slug' => [ 'use' => 'HomeController@page', 'arguments' => ['id' => '[0-9]+','slug' => '[a-z-]*'], ], ];
控制器和模板解析器
return [ // controller and template resolver // call first the controller and render then the template // if the template is not found, the controller is returned '/home/log' => [ 'use' => 'HomeController@log', 'template' => 'Home/log.php', //in your controller you can return an array of data that you can access in your template ], // dynamic route with arguments '/home/user-:id-:slug' => [ 'use' => 'HomeController@page', 'template' => 'Home/log.php', 'arguments' => ['id' => '[0-9]+','slug' => '[a-z-]*'], ], ];
控制器分组解析器
return [ // suppose we have the following methods in the AccountController : // public function create(); // public function read($id); // public function update($id); // public function destroy($id); // if the uri is /account/create the router will call the associated method in the controller '/account/*' => [ 'use' => 'AccountController@{method}', ], ];
Closure解析器
return [ // static route '/home/index' => function(){ return 'Hello world !'; }, // dynamic route with arguments '/home/user-:id-:slug' => [ 'use' => function($id,$slug){ return 'Hello User '.$id.'-'.$slug; }, 'arguments' => ['id' => '[0-9]+','slug' => '[a-z-]*'], ], ];
Closure和模板解析器
return [ // closure and template matching // call first the closure and render then the template '/home/log' => [ 'use' => function(){ return ['name' => 'Peter']; } 'template' => 'Home/log.php', // in log.php you can access the return data like this : $name ='Peter' ], '/home/user-:id-:slug' => [ 'use' => function($id,$slug){ return ['id' => $id,'slug' => $slug]; }, 'template' => 'Home/log.php', 'arguments' => ['id' => '[0-9]+','slug' => '[a-z-]*'], ], ];
块路由
使用JetFire\Routing
,您有创建块路由以更好地组织代码的能力。例如,如果您有一个网站的行政部分,您可以为此部分创建一个块,并为公共部分创建另一个块,如下所示
// Create RouteCollection instance $collection = new \JetFire\Routing\RouteCollection(); // Block routes $collection->addRoutes('admin_routes_path',['view_dir' => 'admin_view_path' , 'ctrl_namespace' => 'admin_controllers_namespace','prefix' => 'admin']); $collection->addRoutes('public_routes_path',['view_dir' => 'public_view_path' , 'ctrl_namespace' => 'public_controllers_namespace']); // Create an instance of Router $router = new \JetFire\Routing\Router($collection) // Select your matcher $router->addRouter(new \JetFire\Routing\Matcher\ArrayMatcher($router)); // Run it! $router->run();
路由配置
以下是您可以编辑的路由配置列表
$router->setConfig([ // You can add/remove extension for views // default extension for views 'templateExtension' => ['.html', '.php', '.json', '.xml'], // If you use template engine library, you can use this to render the view // See the 'Integration with other libraries' section for more details 'templateCallback' => [], // If you want to add a dependency injection container for your controllers constructor or method // for example if your controller 'HomeController' method 'log' method require a class like this : public function log(Request $request) // by default : 'di' => function($class){ return new $class; }, // See the Named Routes section for more details 'generateRoutesPath' => false, ]);
集合选项
以下是您可以编辑的每个集合路由的选项列表
$options = [ // your view directory 'view_dir' => 'view_directory', // your controllers namespace 'ctrl_namespace' => 'controllers_namespace', // your routes prefix 'prefix' => 'your_prefix' ];
命名路由
您可以为每个路由指定一个名称,如下所示
return [ '/home/index' => [ 'use' => 'Home/index.html', 'name' => 'home.index' ], '/home/user-:id-:slug' => [ 'use' => 'HomeController@user', 'name' => 'home.user', 'arguments' => ['id' => '[0-9]+','slug' => '[a-z-]*'], ], ];
然后要获取此路由的URL,您可以这样做
// You have to enable generateRoutesPath to get routes url $router->setConfig([ 'generateRoutesPath' => true, // Other configuration // ... ]); // Reverse routing $collection->getRoutePath('home.index'); // return http://your_domain/home/index $collection->getRoutePath('home.user',[ 'id' => 1, 'slug' => 'toto']); // return http://your_domain/home/user-1-toto
仅支持在 JetFire\Routing\Matcher\ArrayMatcher
中。
REST 路由
您可以通过这种方式为每个路由指定请求方法
return [ '/api/users' => [ 'use' => [ 'GET' => function($response){ $response->setHeaders(['Content-Type' => 'application/json']); return ['name' => 'Peter']; }, 'POST' => function($response){ $response->setHeaders(['Content-Type' => 'application/json']); $response->setStatusCode(201); return []; }, ], 'name' => 'api.users', 'method' => ['GET', 'POST'] ], '/api/users/:id' => [ 'use' => [ 'GET' => function($response){ $response->setHeaders(['Content-Type' => 'application/json']); return ['name' => 'Peter']; }, 'PUT' => function($response){ $response->setHeaders(['Content-Type' => 'application/json']); return []; }, ], 'name' => 'api.user', 'arguments' => ['id' => '[0-9]+'], 'method' => ['GET','PUT'] ], ];
前缀
您可以为每个路由集合设置前缀,如下所示
$collection->addRoutes('routes_file_1',['prefix' => 'prefix_1']); // all routes in routes_file_1 begin with prefix_1/ $collection->addRoutes('routes_file_2',['prefix' => 'prefix_2']); // all routes in routes_file_2 begin with prefix_2/
或者
$collection->addRoutes('routes_file_1'); $collection->addRoutes('routes_file_2'); $collection->setPrefix(['prefix_1','prefix_2']);
中间件
中间件在路由匹配当前 URI 前后调用。您必须创建一个中间件配置文件,如下所示
// Your middleware file return [ // global middleware are called every time 'global_middleware' => [ // Here you define your middleware class to be called 'app\Middleware\Global', ], // block middleware are called when the current route block match one of the following block 'block_middleware' => [ // You define here for each block the middleware class to be called '/app/Blocks/PublicBlock/' => 'app\Middleware\Public', '/app/Blocks/AdminBlock/' => 'app\Middleware\Admin', '/app/Blocks/UserBlock/' => 'app\Middleware\User', ], // class middleware are called when the controller router match one of the following controller 'class_middleware' => [ // You define here for each controller the middleware class to be called '/app/Blocks/PublicBlock/Controllers/HomeController' => 'app\Middleware\Home', ], // route middleware are called when the current route match one of the following middleware name 'route_middleware' => [ // You define here a name to the middleware and assign the class to be called // You have to specify this name to the route like this : `'middleware' => 'home'` 'home' => 'app\Middleware\App' ], ];
然后您必须以这种方式实例化中间件类 Middleware
$middleware = new Middleware($router); $middleware->setCallbackAction('before', 'your_before_middleware_file'); $middleware->setCallbackAction('between', 'your_between_middleware_file'); $middleware->setCallbackAction('after', 'your_after_middleware_file'); $router->addMiddleware($middleware);
让我们看看如何创建您的中间件类。例如,我们以全局中间件为例
namespace app\Middleware; class Global{ // Middleware class must implements handle method // object passed in argument will be inject automatically public function handle(){ // here you put your code // ... } }
查看 API 部分,了解如何在中间件类中处理您的 $route。
自定义匹配器和调度器
如果默认的匹配器和调度器不符合您的预期,您可以像这样编写自己的匹配器和调度器
class MyCustomMatcher implements MatcherInterface{ public function __construct(Router $router); // in this method you can check if the current uri match your expectation // return true or false // if it match you have to set your route target with an array of params and the dispatcher class name to be called // $this->setTarget(['dispatcher' => '\My\Custom\Dispatcher\Class\Name', 'other_params' => 'values']); public function match(); // set your route target $this->router->route->setTarget($target); public function setTarget($target = []); // set your resolver public function setResolver($resolver = []); // you can add multiple resolver method in the same matcher public function addResolver($resolver); // to retrieve your resolver public function getResolver(); // dispatcher yo be called public function setDispatcher($dispatcher = []); public function addDispatcher($dispatcher); } class MyCustomDispatcher implements DispatcherInterface{ public function __construct(Router $router); // your target to call // you can get your route target information with $this->route->getTarget() public function call(); } $router->addMatcher('MyCustomMatcher');
您也可以像这样覆盖默认的匹配器
class MyCustomMatcher extends ArrayMatcher implements MatcherInterface{ public function __construct(Router $router){ parent::__construct($router); // your custom match method $this->addResolver('customResolver'); } public function customResolver(){ // your code here // ... // then you set the route target with the dispatcher } } class MyCustomDispatcher implements DispatcherInterface{ public function __construct(Router $router); // your target to call // you can get your route target information with $this->route->getTarget() public function call(); }
与其他库集成
如果您想集成其他模板引擎库(如 twig、smarty 等),您必须在路由中设置 'templateCallback'。
// Twig template engine require_once '/path/to/lib/Twig/Autoloader.php'; Twig_Autoloader::register(); // Other template engine $tpl = new \Acme\Template\Template(); $router->setConfig([ 'templateCallback' => [ // if the router find a template with twig enxtension then it will call the twig template engine 'twig' => function($route){ $loader = new Twig_Loader_Filesystem($route->getTarget('block')); $twig = new Twig_Environment($loader, []); $template = $twig->loadTemplate($route->getTarget('template')); echo $template->render($route->getData()); }, // for other template engine 'tpl' => function($route) use ($tpl){ $tpl->load($route->getTarget('template')); $tpl->setData($route->getData()); $tpl->display(); } ], // Other configuration // ... ]);
子域名
return [ '{subdomain}.{host}/home' => [ 'use' => 'AdminController@index', 'name' => 'admin.home.index', 'subdomain' => 'admin' // could be a regex for multiple subdomain ] ];
或者,如果您想为某个块添加子域名,您必须将此行添加到您的路由集合选项中
$options = [ // ... 'subdomain' => 'your_subdomain' ];
API
以下是您最可能使用的公共类中的公共方法和变量的列表。
// JetFire\Routing\RouteCollection $collection-> routesByName // routes url by their name countRoutes // count routes block addRoutes($collection,$options = []) // set your routes getRoutes($key = null) // return all routes getRoutePath($name,$params = []) // return the url of route setPrefix($prefix) // $prefix can be a string (applied for every collection) // or an array (for each collection you can specify a prefix) setOption($options = []) // set your routes option generateRoutesPath() // generate routes url by their name // JetFire\Routing\Router $router-> response // JetFire\Routing\ResponseInterface instance route // JetFire\Routing\Route instance collection // JetFire\Routing\RouteCollection instance middlewareCollection // middleware collection matcher // list of matcher dispatcher // the dispatcher instance setConfig($config) // router configuration getConfig() // get router configuration run() // run the router with the request url // JetFire\Routing\Route $route-> set($args = []) // set your route array parameters getUrl() // return the route url setUrl($url) // set the route url getName() // return the route name setName($name) // set the route name getCallback() // return the route callback (template,controller or anonymous function) setCallback($callback) // set the route callback getMethod() // return the route method (GET,POST,PUT,DELETE) getDetail() // return the route detail setDetail($detail) // set the route detail addDetail($key,$value) // add a detail for the route getTarget($key = null) // return the route target (dispatcher,template or controller|action or function) setTarget($target = []) // set the route target hasTarget($key = null) // check if the route has the following target getData() // return data for the route __call($name,$arguments) // magic call to get or set route detail
许可证
JetFire 路由是在 MIT 公共许可证下发布的:https://open-source.org.cn/licenses/MIT。