mcustiel / power-route
Power Route 是一个可配置的 PHP 路由器
Requires
- php: >=5.6
- mcustiel/creature: ^2.0.0
- mcustiel/mockable-datetime: ^1.0.0
- zendframework/zend-diactoros: ^1.1.3 || ^2.0
Requires (Dev)
- phpunit/phpunit: ^4.8.9
This package is auto-updated.
Last update: 2023-07-05 16:20:53 UTC
README
PowerRoute! 是一个 PHP 路由系统,可以根据 HTTP 请求的多个组件执行不同的操作,并且完全兼容 PSR-7。
配置由三个主要组件组成,并定义了一个二叉树
- 输入源:输入源是从请求中获取要评估数据的组件。
- 匹配器:此组件接收输入源的价值并对其进行检查。
- 操作:基于匹配器执行检查的结果执行的组件。
在配置中,可以为匹配器返回 true 的情况和返回 true 的情况设置操作,从而构建一个二叉树。
可以通过添加输入源、匹配器和操作来扩展整个系统。此外,用于在配置中标识组件的名称可以任意分配。
组件被分组形成二叉树的节点,每个节点看起来如下
'expectationUrl' => [ 'condition' => [ 'one-of' => [ [ 'input-source' => ['url' => 'path'], 'matcher' => [ 'matches' => '/some/url/?' ], ], ], ], 'actions' => [ 'if-matches' => [ ['myCustomAction' => 'withSomeParameter'], ], 'else' => [ ['notFound' => null], ], ], ],
目录
安装
该项目已在 Packagist 上发布,因此您只需将其添加到 composer.json 中的依赖项即可。
"require": { // ... "mcustiel/power-route": "*" }
如何使用
配置
配置必须是一个 PHP 数组。它必须定义两个键
- root:图根节点的名称。
- nodes:所有节点的定义,这是一个键 => 值对的数组,其中键是节点的名称,值是其定义。
示例
始终重定向到 google.com 的配置
[ 'root' => 'default', 'nodes' => [ 'default' => [ 'condition' => [], 'actions' => [ 'if-matches' => [ [ 'redirect' => 'http://www.google.com' ] ] ] ] ] ]
您可以使用您喜欢的名称为输入源、匹配器和操作命名,然后使用此库提供的工厂将它们映射。
代码
在正确定义所有配置后,必须使用 Executor 类根据接收到的请求遍历图。要创建 Executor 类的实例,必须首先创建 Actions、输入源和匹配器的工厂。每个工厂构造函数都期望一个 Mcustiel\Creature\CreatorInterface 对象的数组,索引为 PowerRoute! 配置文件中使用的类标识符。请参阅以下示例
use Mcustiel\PowerRoute\PowerRoute; use Mcustiel\PowerRoute\Common\Factories\ActionFactory; use Mcustiel\PowerRoute\Common\Factories\InputSourceFactory; use Mcustiel\PowerRoute\Common\Factories\MatcherFactory; use Mcustiel\PowerRoute\Common\Factories\ActionFactory; Mcustiel\PowerRoute\Common\Conditions\ConditionsMatcherFactory; use Mcustiel\PowerRoute\Matchers\NotNull; use Mcustiel\PowerRoute\Matchers\Equals; use Mcustiel\PowerRoute\InputSources\QueryStringParam; use Mcustiel\PowerRoute\Actions\Redirect; use Mcustiel\Creature\SingletonLazyCreator; use Your\Namespace\MyMatcher; use Your\Namespace\MyInputSource; use Your\Namespace\MyAction; $matcherFactory = new MatcherFactory( [ 'notNull' => new SingletonLazyCreator(NotNull::class), 'equals' => new SingletonLazyCreator(Equals::class), 'someSpecialMatcher' => new SingletonLazyCreator(MyMatcher::class) ] ); $inputSourceFactory = new InputSourceFactory( [ 'get' => new SingletonLazyCreator(QueryStringParam::class), 'someSpecialInputSource' => new SingletonLazyCreator(MyInputSource::class) ] ); $actionFactory = new ActionFactory( [ 'redirect' => new SingletonLazyCreator(Redirect::class), 'someSpecialAction' => new SingletonLazyCreator(MyAction::class) ] ); $config = $yourConfigManager->getYourPowerRouteConfig(); $router = new PowerRoute( $config, $actionFactory, ConditionsMatcherFactory($inputSourceFactory, $matcherFactory) );
在您有了 executor 实例后,只需使用 PSR7 请求和响应调用 start 方法即可。
use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; use Zend\Diactoros\Response\SapiEmitter; $request = ServerRequestFactory::fromGlobals(); $response = $router->start($request, new Response()); (new SapiEmiter())->emit($response);
或者,为了提高性能,您可以使用 PHP-PM
namespace Your\Namespace; class MyApplication { private $router; public function __construct() { // Set up the application // ... $this->router = new PowerRoute( $config, $actionFactory, ConditionsMatcherFactory($inputSourceFactory, $matcherFactory) ); } public function __invoke($request, $response, $next = null) { return $this->router->start($request, $response); } }
并按照以下方式运行:
vendor/bin/ppm start --bridge=PHPPM\\Psr7\\Psr7Bridge --bootstrap=Your\\Namespace\\MyApplication
预定义组件
输入源
Cookie
允许匹配请求体。
Cookie
允许根据HTTP请求中的cookie执行操作。
参数
cookie的名称。
头部
允许根据HTTP请求中的头部执行操作。
参数
头部的名称。
方法
返回执行请求所使用的HTTP方法。它不接收任何参数。
查询字符串参数
允许根据请求的查询字符串中的参数执行操作。
参数
查询字符串参数的名称。
URL
允许根据URL或其部分执行操作。
参数
一个字符串,指定要评估的URL部分。以下是一些可能的值:
- full:评估整个URL。
- host:评估主机。
- scheme:评估方案。
- authority:评估授权部分。
- fragment:评估片段。
- path:评估路径。
- port:评估端口。
- query:评估查询。
- user-info:评估用户信息部分。
匹配器
不区分大小写的等于
用于在不考虑大小写的情况下比较两个字符串。
包含
此匹配器返回true,如果输入源中的值包含作为参数接收的值的子串。
等于
如果输入源中的值等于作为参数接收的另一个值,则返回true。
在数组中
如果输入源中的值在作为参数接收的值列表中,则返回true。
非空
如果输入源中的值不为空,则返回true。
非空
如果输入源中的值非空,则返回true。
正则表达式
如果输入源返回的值与作为参数接收的正则表达式匹配,则返回 true。
操作
转到
这是一个始终添加的默认操作,其标识符是字符串 'goto'。它允许跳转到另一个节点执行。它的参数是要执行的节点的名称。
显示文件
此操作显示一个文件。其路径必须作为参数定义。
未找到
此操作将响应的 http 状态码设置为 404。
重定向
此操作将 Location 头添加到响应中,并将 http 状态码设置为 302。其重定向目标必须作为参数定义。
保存 Cookie
此操作设置 cookie 的值。它接收一个对象作为参数,其中包含 cookie 所需的所有数据
- 名称
- 值
- 域名
- 路径
- 安全
服务器错误
将响应 statusCode 设置为 500。也可以将其他错误 statusCode 作为参数传递。如果提供的错误无效,则设置 500。
设置头
此操作设置头部的值。作为参数接收一个对象,具有以下键
- 名称
- 值
状态码
默认将响应 statusCode 设置为 200。也可以传递其他错误 statusCode 作为参数。如果提供无效的错误,则抛出异常。
扩展 PowerRoute!
创建自己的操作
要创建自己的操作并通过 PowerRoute! 使用,您必须创建一个实现 ActionInterface 的类。如果您想使您的操作具有支持占位符的能力,您必须使用 PlaceholderEvaluator trait。
- ActionInterface 定义了操作应该实现的方法。
- PlaceholderEvaluator 定义了 getValueOrPlaceholder 方法,这使您的操作能够在字符串中解析可能的占位符。
interface ActionInterface { public function execute(\Mcustiel\PowerRoute\Common\TransactionData $transactionData, $argument = null); }
TransactionData 是一个对象,作为参数传递给所有操作,用于在它们之间共享请求、响应和其他可能希望共享的数据。
在操作内部,您应从 TransactionData(请求或响应对象)检索您想要修改的对象。然后修改它,并在 TransactionData 中再次设置新对象。必须以这种方式执行,因为 PSR7 是不可变的。
您甚至可以在操作中初始化框架。
使用 PSR7 中间件
PowerRoute! 支持作为操作使用的 psr-7 中间件。您需要做的就是将配置中的操作名称映射到一个实现以下方法的类
function __invoke($request, $response, $next = null);
您还可以将操作名称映射到具有该签名的可调用对象。
PowerRoute! 将调用中间件,并将配置的参数作为 $next
参数传递。
示例
对于操作配置
[ 'myMiddleware' => new OtherMiddleware() ]
并且工厂设置
[ 'myMiddleware' => new LazyCreator(MyMiddlewareImplementation::class) ]
PowerRoute 将这样做
$implementation = new MyMiddleWareImplementation(); $implementation($request, $response, new OtherMiddleware());
动作示例
interface ActionInterface { /** * @param \Mcustiel\PowerRoute\Common\TransactionData $transactionData This object is modified inside the class. * @param mixed $argument This optional argument comes from the config of PowerRoute! */ public function execute(TransactionData $transactionData, $argument = null); }
class Redirect implements ActionInterface { use PlaceholderEvaluator; public function execute(TransactionData $transactionData, $argument = null) { return $transactionData->setResponse( $transactionData->getResponse() ->withHeader( 'Location', $this->getValueOrPlaceholder($argument, $transactionData) ) ->withStatus(302) ); } }
TransactionData类
此类作为参数传递给每个动作,并定义了两个方法来访问当前请求和相应的响应(分别对应getRequest和getResponse)。它还通过get($name)
和set($name, $value)
方法提供了保存和检索自定义变量的能力。
占位符
动作接收的参数可以包括一个占位符来访问TransactionData对象中的值。参数的格式如下
{{source.name}}
其中source指示从哪里获取值,name是与给定值关联的标识符。
可能的占位符来源
- var:允许您访问在TransactionData对象中保存的一些自定义值。
- uri:允许您访问用于请求的url中的数据。如果您不提供标识符,它将返回完整的url。如果不提供,它允许一系列标识符来检索请求的部分。
- full:也返回完整的url。
- host:返回url的主机部分。
- scheme:返回url的方案部分。
- authority:返回url的权限部分。
- fragment:返回url的片段部分。
- path:返回当前请求中使用的url的路径。
- port:返回url中请求的端口号。
- query:返回当前请求的查询字符串。
- user-info:返回在url中指定的用户信息。
- method:返回当前请求使用的方法。
- get:允许您访问查询字符串中的一个参数,必须指定为占位符的名称部分。
- header:允许您访问一个头,必须指定为占位符的名称部分。
- cookie:允许您访问一个cookie,必须指定为占位符的名称部分。
- post:允许您访问一个post变量,必须指定为占位符的名称部分。
- bodyParam:允许您访问从体中获取的变量,必须指定为占位符的名称部分。
** 注意:有关先前来源的更多信息,请参阅PSR7文档。
创建您自己的输入来源
输入来源是用于从请求中访问数据的组件,它使用匹配器来验证数据和请求。
它还应扩展AbstractArgumentAware以访问配置中的参数,并且必须实现InputSourceInterface。它必须返回值,以便PowerRoute!将其提供给匹配器。
interface InputSourceInterface { /** * @param \Psr\Http\Message\ServerRequestInterface $request * @param mixed $argument * * @return mixed */ public function getValue(ServerRequestInterface $request, $argument = null); }
输入来源示例
class Header implements InputSourceInterface { public function getValue(ServerRequestInterface $request, $argument = null) { $header = $request->getHeaderLine($argument); return $header ?: null; } }
创建您自己的匹配器
匹配器是负责对通过InputSource从请求中获得的价值执行检查的组件。要创建自己的匹配器,您必须创建一个类,该类应扩展AbstractArgumentAware以访问参数,并且必须实现MatcherInterface。
interface MatcherInterface { /** * @param mixed $value * @param mixed $argument * * @return boolean */ public function match($value, $argument = null); }
匹配器示例
class Equals implements MatcherInterface { public function match($value, $argument = null) { return $value == $argument; } }
示例
Phiremock使用PowerRoute,您可以在此处查看其配置文件:这里。