iassasin / easyroute
非常轻量级且简单的PHP路由器
Requires
- php: >=7.0
- psr/container: ^1.0
Requires (Dev)
- phpunit/phpunit: ^6
- satooshi/php-coveralls: ^2.0
README
简单的路由器不需要很多设置,只需几分钟即可安装并运行。
安装
要开始使用路由器,请完成以下4个简单步骤
- 通过composer安装
easyroute
composer require iassasin/easyroute
- 在项目根目录设置您的路由。例如,在文件
routes.php中
require_once 'vendor/autoload.php'; use Iassasin\Easyroute\Router; use Iassasin\Easyroute\Route; $router = new Router(); $router->setControllersPath($_SERVER['DOCUMENT_ROOT'].'/controllers/'); $router->addRoutes([ new Route('/(:controller:(/:action:(/:arg)?)?)?', ['controller' => 'home', 'action' => 'index', 'arg' => null]), ]); $router->processRoute();
- 通过
.htaccess让web服务器将所有请求(除静态assets/)重定向到路由器
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/assets/
RewriteRule ^(.*)$ routes.php [B,QSA,L]
- 在
controllers/home.php中创建第一个控制器
class ControllerHome { public function index($arg){ return '<html><body>Home page! '.($arg !== null ? 'Argument: '.$arg : 'Argument not set').'</body></html>'; // or use "return new Response('...')" which is more flexible } }
这就完了!
请注意,文件名必须与URL模板中的:controller名称匹配,控制器类名必须与带有前缀Controller的:controller名称匹配。在上面的例子中,路由 /home/index 与文件 controllers/home.php 匹配,并具有类 ControllerHome。
有用功能
带参数的路由
路由是一个正则字符串,具有用于命名路由参数的简单语法。例如
/:controller/:action/:arg(所有参数都是必需的)/(foo|bar)-:arg/gotcha(正则表达式和部分参数匹配。有效的有/foo-123/gotcha,/bar-qwerty/gotcha,但不包括/qwerty/gotcha)/:arg?(参数arg可选,但不能是/。有效的有/,/param,但不包括/sub/param)/(:controller:(/:action:(/:arg)?)?)?(所有参数都是可选的。有效的有/,/home,/home/index/val,但不包括/home/,/home/index/)
参数名称必须匹配正则表达式 [a-zA-Z_0-9]+。
默认情况下,:parameter 匹配正则表达式 [^\/]+,但您可以使用自己的过滤器
new Route('/:arg(\d+)?', // arg not required and can contains only numerics ['controller' => 'home', 'action' => 'index', 'arg' => null], // default values )
如果您需要使用 ( 来匹配分组,但不是过滤参数,请在参数名称中使用尾随的 ::/:controller:(postfix1|postfix2) 将匹配 /homepostfix1,其中 controller = 'home'。
内置简单的依赖注入容器
您可以使用内置的依赖注入容器将应用程序代码拆分为服务(这些服务将通过自动加载加载)并在控制器操作中简单使用它们
class ControllerHome { public function index($arg, Request $request, DatabaseService $db){ // ... } }
服务构造函数也可以使用依赖注入,并通过相同的语法要求其他服务。
类 SampleContainer 实现 Psr\Container\ContainerInterface。
use Iassasin\Easyroute\Router; $router = new Router(); /** @var SimpleContainer $container */ $container = $router->getContainer(); // get default container // Instantiate and add services by hand $container->setService(Database::class, new Database('login', 'password')); // Disable automatic instantiation for services $container->setAutowireEnabled(false);
您还可以使用另一个依赖注入容器
use Iassasin\Easyroute\Router; use Iassasin\Easyroute\Http\Request; $router = new Router(); $request = Request::createFromGlobals(); // some implementation of ContainerInterface $container = new MyContainer(); // Router don't know how to register Request class in your container implementation // You should to do it by self if you want to use Request class in controllers // See next section for details of Request class $container->register(Request::class, $request); $router->setContainer($container);
请求类
通过依赖注入容器,您有权访问提供对请求参数访问的 Request 服务。
Request 包含以下字段
query-$_GET数组request-$_POST数组attributes- 关联数组,包含任何数据,您可以在创建Request实例时设置cookies-$_COOKIE数组files-$_FILES数组server-$_SERVER数组
每个字段都是 Parameters 类的实例,并具有以下方法
get(string $name)- 通过其名称获取参数has(string $name)- 检查具有$name的参数是否存在all()- 获取所有参数的数组
Request 提供一些有用的方法
getContent()- 获取整个http post内容作为字符串getClientIP()- 返回$this->server->get('REMOTE_ADDR')getScriptName()- 返回$this->server->get('SCRIPT_NAME')getScheme()- 返回$this->server->get('REQUEST_SCHEME')getHost()- 返回$this->server->get('SERVER_NAME')getUri()- 返回$this->server->get('REQUEST_URI')getMethod()- 返回$this->server->get('REQUEST_METHOD')getProtocol()- 返回$this->server->get('SERVER_PROTOCOL')
响应类
Response 类用于向客户端返回数据。在控制器操作中返回 Response 实例,而不是使用 echo 等手动发送数据。
内置响应类
存在 3 个内置响应类
Response- 所有响应的基础类,具有以下方法__construct(string $content, int $statusCode = 200, array $headers = [])getStatusCode(),setStatusCode(int $code)- 获取/设置 HTTP 状态码getContent(),setContent(string $content)- 获取/设置 HTTP 响应内容getHeaders(),setHeaders(array $headers)- 获取/设置 HTTP 头部信息setHeader(string $name, string $value)- 设置单个头部send()- 向客户端发送响应,由处理程序调用
Response404- 扩展Request用于默认 HTTP 404 错误,具有以下属性__construct(string $url, array $headers = [])getUrl()- 获取导致 404 错误的 URL
Response500- 扩展Request用于默认 HTTP 500 错误。如果在路由处理期间抛出任何异常,则会生成。__construct(\Throwable $exception = null, array $headers = [])getException()- 获取在路由处理期间抛出的异常
ResponseJson- 扩展Request用于发送 JSON 响应,同时设置正确的 HTTPContent-Type头部。__construct(object|array $data, int $statusCode = 200, array $headers = [])getData(),setData(object|array $data)- 设置要发送到客户端的源数据- 注意:不能使用
setContent并抛出LogicException
响应类的自定义处理程序
为 Response 类设置自定义处理程序
use Iassasin\Easyroute\Http\Responses\Response404; $router->setResponseHandler(Response404::class, function(Response404 $resp){ $resp->setContent('<html><body><h1>Custom 404 Not Found</h1> The requested url "<i>'.htmlspecialchars($resp->getUrl()).'</i>" not found!'); $resp->send(); return true; // do not call other handlers });
并为任何 HTTP 状态码设置自定义处理程序
use Iassasin\Easyroute\Http\Response; $router->setStatusHandler(302, function(Response $resp){ $resp->setContent('You have redirected'); $resp->send(); return true; // do not call other handlers });
注意 1:您可以同时使用这两个处理程序,但响应处理程序将被首先调用(并且可以停止调用状态处理程序)。
注意 2:您可以为父响应类设置处理程序以匹配所有子类,子处理程序将始终首先被调用:从最子类到最父类。因此,您可以通过为
Response::class设置处理程序来匹配 所有 响应。
控制器子目录
使用子目录分隔区域
(new Route('/admin/:controller/:action?', ['action' => 'index'])) ->setControllersSubpath('zones/admin') // '/admin/home/index' will match 'controllers/zones/admin/home.php' // and class 'ControllerHome'
访问过滤
使用 RouteFilter 防止访问某些路由
use Iassasin\Easyroute\RouteFilter; class RouteFilterAdmin extends RouteFilter { public function preRoute($path, $controller, $action, $args){ if (!isCurrentUserAdmin()){ (new Response('Access denied!', 403))->send(); return Router::COMPLETED; // Do not call controller's action } return Router::CONTINUE; // Call controller's action } } //... (new Route('/admin/:controller/:action?', ['action' => 'index'])) ->setFilter(new RouteFilterAdmin())
自定义控制器类名前缀
设置自定义控制器类名前缀(默认为 Controller)
$router->setControllerClassPrefix('TheController');