klezbucket / cakephp-klez-api
CakePHP 的 KlezApi 插件
Requires
- php: >=7.0
- cakephp/cakephp: ^3.5
Requires (Dev)
- phpunit/phpunit: ^5.7.14|^6.0
This package is auto-updated.
Last update: 2024-09-13 13:30:49 UTC
README
欢迎使用 KlezPlugin 的家族。
我们的目标是自动化并简化任何项目的重复部分。扩展框架以提供钩子和设置来实现这一点。
变更日志 v0.5-beta
ImplementationNode 已在此处实现,实现了抽象管道。
变更日志 v0.4-beta
PreflightNode 已在此处实现,准备好服务 CORS 请求。
具体化抽象管道,提取出常见的管道部分。避免配置冗余。
变更日志 v0.3-beta
实现了多管道执行流程。在新的 API 中跨管道跳转。
实现了管道停止。通过新的 API 停止当前管道执行。
变更日志 v0.2-beta
实现了日志功能。
变更日志 v0.1-beta
这是第一次提交。
此包涵盖了项目可能需要的所有 Api 必需品。
格式化支持
- json
- xml
- yml
- php
安装
您可以使用 composer 将此插件安装到您的 CakePHP 应用程序中。
安装 composer 包的推荐方法是
composer require klezbucket/cakephp-klez-api
路由
您应该在所需的范围内挂钩插件的路由。例如
Router::scope('/', function (RouteBuilder $routes) {
$routes->scope('/api', [ 'plugin' => 'KlezApi' ], function (RouteBuilder $routes) {
$routes->loadPlugin('KlezApi');
});
});
之后,整个 API 都挂在这个路由上
$routes->connect('/:endpoint.:format', ['controller' => 'Webservice', 'action' => 'index' ]);
有效的路由示例:/api/test.json
API 的关键部分是 (端点,格式) 对。上面的例子表示 'test' 端点,以 'json' 数据。
引导
避免使用 config/bootstrap.php 加载插件。
相反,将以下代码放入您的 src/Application.php bootstrap() 方法中。
$this->addPlugin('KlezApi', [
'routes' => false,
'log' => [
'enabled' => true,
'maxlength' => 255
],
'config' => [
'endpoints' => 'endpoints'
]
]);
config.endpoints 条目表示位于 /config 文件夹中的 CakePHP 配置文件。log 条目表示日志配置。
日志配置
日志引擎需要 KlezCore 的日志适配器。日志的配置有以下选项
- enabled: boolean,用于启用日志适配器。默认为 false。
- maxlength: 整数,指定任何给定日志消息的最大长度。默认为 255。
- file: 字符串,表示日志的文件名。默认为 'klezapi'
- scopes: 数组,表示日志适配器的任何上下文。默认为 ['klezapi']
端点配置文件
与任何 CakePHP 配置文件一样,它应该返回一个关联数组。
此数组中的每个键应遵循以下约定:'KlezApi.endpoints.{endpoint}',其中 {endpoint} 表示由路由指定的端点名称。
有两种设置,'单个文件' 一种和 '冗余' 一种。
'单个文件' 示例:我们表示一个相对于 /config 文件夹的文件,插件将搜索该文件并从中加载配置。
此文件应遵循 '冗余' 语法。
"KlezApi.endpoints.test" => "endpoints/test",
'冗余' 示例,我们将一切放入同一个配置文件中。
"KlezApi.endpoints.test2" => [
"config" => [
"increment" => -3,
],
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\CounterNode",
1 => "KlezApi\\Controller\\Node\\CounterNode",
2 => "KlezApi\\Controller\\Node\\CounterNode",
3 => "KlezApi\\Controller\\Node\\CounterNode",
4 => "KlezApi\\Controller\\Node\\CounterNode",
5 => "KlezApi\\Controller\\Node\\FormatterNode",
],
],
关键组件是配置和管道数组。
'配置' 表示端点可能需要的所有硬编码设置,作为附加输入。
'管道' 表示插件应按顺序执行以处理和生成输出的 '节点' 集合。
'pipeline' 键对应于主要管道,表示端点执行流的入口点。然而,也可以跨管道跳转。
要指定另一个管道,只需给它一个不同的名称并将其节点集合放入同一个关联数组中,例如
"KlezApi.endpoints.test2" => [
"config" => [
"increment" => -3,
],
"pipeline" => [
0 => "YourApp\\Controller\\Node\\SomeJumpingNode",
1 => "KlezApi\\Controller\\Node\\FormatterNode",
],
'another_pipeline' => [
0 => "KlezApi\\Controller\\Node\\CounterNode",
1 => "KlezApi\\Controller\\Node\\CounterNode",
2 => "KlezApi\\Controller\\Node\\CounterNode",
3 => "KlezApi\\Controller\\Node\\CounterNode",
4 => "KlezApi\\Controller\\Node\\CounterNode",
]
],
在这个例子中,指定了 'another_pipeline'。
管道和节点
每个端点至少有一个节点集合,称为管道。每个节点应实现 'Node' 接口,以遵守其管道指定的执行流。
该管道在每一个节点之间提供了一个公共缓冲区,数据可以通过它进行存储和转换。
缓冲区API在节点接口内包含了read()、write()、overwrite()和delete()方法。
跨管道跳转
在上面的示例中,指定了另一个管道。
为了跳转到这个新管道,主管道上的节点必须调用jump()方法。此方法的参数必须是所需管道的名称。
$this->jump('another_pipeline');
如果管道未指定到端点的关联数组中,它将被解析为空管道而不是引发错误。
为了进一步解释,调用jump()的管道将被称为“调用管道”。
停止当前管道
如果出于某种原因不希望继续当前管道的执行,halt()方法将停止进一步的节点评估。
$this->halt();
注意,如果您在Node中调用halt()后立即调用jump(),则此跳转不会产生任何效果,因为当前管道正在停止。
停止当前管道会将执行流程回溯到调用管道(如果有的话)。
抽象管道
有时几个端点可能有共同的执行路径,复制粘贴节点应该可以工作,但并不那么优雅。
可以使用抽象管道来指定此类共同路径。此外,这些抽象管道不会暴露在API路由中,因此它们在具体化之前保持隐藏。
concretize()方法允许这样做。它需要一个参数,即抽象管道的名称。
$this->concretize('my_abstract_pipeline');
抽象管道的配置与常规管道完全相同,但它们通过端点的关联数组中的KlezApi.abstract.{$name}键进行指定。
"KlezApi.abstracts.triple_sum_by_eleven" => [
"config" => [
"increment" => 11,
],
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\CounterNode",
1 => "KlezApi\\Controller\\Node\\CounterNode",
2 => "KlezApi\\Controller\\Node\\CounterNode",
],
],
"KlezApi.endpoints.abstract" => [
"config" => [
'preflight' => [
'Access-Control-Allow-Origin' => 'klezkaffold3.klez'
],
'concretize' => 'triple_sum_by_eleven'
],
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\PreflightNode",
1 => "KlezApi\\Controller\\Node\\ConcretizeTestNode",
2 => "KlezApi\\Controller\\Node\\FormatterNode",
],
],
在上面的示例中,指定了一个名为'triple_sum_by_eleven'的抽象管道。还指定了抽象端点。请注意,端点管道中的'ConcretizeTestNode'调用concretize(),并在其配置中指定了'concretize'参数。因此,'triple_sum_by_eleven'抽象被具体化并跳转进去。
如果抽象中指定了多个替代管道,它们也会被具体化,但跳转是在主管道上执行的。
核心节点
我们将尝试提供一些基本的节点,这些节点可以解决任何web服务开发中的许多常见问题。
在提供的Node套件中,还有一些许多在web服务开发上下文中没有意义但在测试中非常有用的测试节点。
格式化节点
如上例中管道的最后一个元素所示,'FormatterNode'是一个核心节点。其主要功能是提供输出,格式化方式由其路由指定的'format'决定。
此节点将其当前缓冲区序列化为所需的格式,然后再发送输出。
跳转方法节点
'JumpMethodNote'跳转到当前请求的小写形式指定的http方法所表示的管道。
"KlezApi.endpoints.test" => [
"config" => [
],
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\RandomIncrementNode",
1 => "KlezApi\\Controller\\Node\\JumpMethodNode",
2 => "KlezApi\\Controller\\Node\\FormatterNode",
],
'get' => [
0 => "KlezApi\\Controller\\Node\\BufferCounterNode",
],
'post' => [
0 => "KlezApi\\Controller\\Node\\BufferCounterNode",
1 => "KlezApi\\Controller\\Node\\BufferCounterNode",
],
'put' => [
0 => "KlezApi\\Controller\\Node\\BufferCounterNode",
1 => "KlezApi\\Controller\\Node\\BufferCounterNode",
2 => "KlezApi\\Controller\\Node\\BufferCounterNode",
],
],
在这个例子中,所有的GET请求都将转换为'get'管道,每个在端点关联数组中指定的方法也是如此。如果没有指定方法,则将其解析为空管道,因此不会发生任何事情。
预检节点
当请求OPTIONS方法时,'PreflightNode'提供CORS头。如果检测到该方法,则提供配置的头,如果没有指定,则传递默认值。此节点在提供CORS头时会停止管道。
"KlezApi.endpoints.cors" => [
"config" => [
'headers => [
'Access-Control-Allow-Headers' => 'Accept,Authorization,Content-Type'
]
],
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\PreflightNode",
1 => "KlezApi\\Controller\\Node\\RandomIncrementNode"
2 => "KlezApi\\Controller\\Node\\JumpMethodNode",
3 => "KlezApi\\Controller\\Node\\FormatterNode",
],
'options' => [
0 => "KlezApi\\Controller\\Node\\BufferCounterNode",
],
'get' => [
0 => "KlezApi\\Controller\\Node\\BufferCounterNode",
1 => "KlezApi\\Controller\\Node\\BufferCounterNode",
],
],
在这个示例中,当请求 OPTIONS 方法时,'PreflightNode' 将服务配置的 'Access-Control-Allow-Headers',并附加默认缺少的头部 'Access-Control-Allow-Methods' 和 'Access-Control-Allow-Origin'。如果需要更多的头部,它们也可以追加到配置关联数组中。之后,管道将停止。因此,指定的 'options' 管道永远不会执行,因为执行流程不会达到 'JumpMethodNode'。
实现节点
'ImplementationNode' 实现了一个抽象管道,它从 config.implements 中读取所需的管道。
"KlezApi.abstracts.main" => [
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\PreflightNode",
1 => "KlezApi\\Controller\\Node\\ImplementationNode",
2 => "KlezApi\\Controller\\Node\\FormatterNode",
],
],
"KlezApi.abstracts.auth" => [
"pipeline" => [
0 => "App\\Controller\\Node\\CaptchaNode",
1 => "App\\Controller\\Node\\AuthNode",
],
],
"KlezApi.endpoints.auth" => [
"config" => [
'implements' => 'auth'
],
"pipeline" => [
0 => "App\\Controller\\Node\\MainNode", // MainNode runs $this->concretize('main');
],
],
在上面的示例中,'auth' 端点实现了抽象的 'main' 管道,它围绕在公共特征节点之间的另一个 ImplementationNode。这个 ImplementationNode 实现了 'auth' 抽象管道,它包含应用程序的授权逻辑。
这允许创建一个公共管道部分,'main' 抽象管道。然后指定与业务相关的逻辑,'auth' 抽象管道。
命令
生成裸端点
bin/cake KlezApi.generator newstuff
在端点配置文件中创建一个新的端点条目。
上面的示例将以下条目追加到配置数组中
"KlezApi.endpoints.newstuff" => [
"config" => [
],
"pipeline" => [
0 => "KlezApi\\Controller\\Node\\FormatterNode",
],
],
它检查端点是否已存在。在这种情况下,端点配置不会被替换,命令将失败。