Kipchak 是做什么的?
Kipchak 是一个面向 PHP 8.4 及更高版本的 API 开发工具包。它基于 Slim Framework 4,采用固定结构:启动序列、外部服务驱动、中间件,以及路由、控制器、数据传输对象(DTO)和 OpenAPI 的约定。它运行在 FrankenPHP 的 Worker 模式下。文档:https://kipchak.dev;语言模型索引:https://kipchak.dev/llms.txt。
Kipchak 不是 Laravel 也不是 Symfony。 它没有门面(facades)、全局辅助函数、服务提供者、Eloquent、Blade、自动注入的控制器或隐藏的约定。每个端点所做的所有操作都在项目自身的代码中可见。请勿编写 request()、response()->json()、config('...')、app()、Route::get()、DB::、Cache:: 或任何其他框架辅助函数:这些在此处均不存在。
识别 Kipchak 项目
composer.json 要求安装 kipchak/core,并且项目包含以下文件夹。如果项目包含 AGENTS.md,请先阅读它:它描述了该项目的详细信息。
| 路径 | 包含内容 |
|---|---|
routes/ | 路由文件。其中任意深度的每个 .php 文件都会在启动时加载。版本化路由应放在 routes/v1/ 中。 |
api/Controllers/ | 控制器,命名空间 Api\Controllers;版本化控制器放在 v1/ 中 (Api\Controllers\v1)。 |
api/DataTransferObjects/ | DTO,版本化方式与控制器相同。它们是 API 契约。 |
api/Models/ | 业务逻辑。 |
api/Entities/Doctrine/<Connection>/ | Doctrine 实体,当使用 Doctrine 驱动时。 |
api/Middlewares/ | 项目自身的 PSR-15 中间件。 |
api/OpenApi/Definition.php | OpenAPI 标题、版本、服务器和共享响应。 |
api/Utils/ | 在 API 中共享的代码。 |
config/ | 每个驱动或中间件对应一个 PHP 文件,返回一个数组,命名为 kipchak.<name>.php。 |
drivers/drivers.php | 按顺序初始化驱动。 |
middlewares/middlewares.php | 初始化应用于每个请求的中间件:Error::initialise($app) 作为第一个和最后一个,其余中间件放在之间。 |
migrations/database/ | 用于 Doctrine 驱动的纯 SQL 迁移。 |
html/index.php | FrankenPHP Worker 入口点。很少编辑。 |
tests/ | PHPUnit 测试,启动 API 并发送请求。 |
Kipchak\Core\Api::boot() 构建 Slim 应用程序,然后加载 drivers/drivers.php,接着加载 middlewares/middlewares.php,最后加载每个路由文件,并返回该应用程序。
从脚手架创建的项目中的命令(composer create-project kipchak/starter my-api):
composer test:运行测试。每次更改后都应运行。composer openapi:将 OpenAPI 文档写入openapi.yaml;如果文档存在问题则失败。docker compose up --watch:在 http://localhost:8080 上运行 API,当文件更改时重启 Worker。
规则
- 每个位于
api/和tests/中的 PHP 文件都以declare(strict_types=1);开头。除非类需要被继承,否则将其声明为final。为每个属性、参数和返回值指定类型。 - 控制器应保持轻量。 读取请求,调用模型,返回响应。逻辑应放在
api/Models/中。 - DTO 是契约。 每个请求和响应结构都是一个带有
#[OA\Schema]的final readonlyDTO,并且每个属性都包含#[OA\Property](包含描述和示例)。控制器通过ref: '#/components/schemas/Name'引用 DTO 模式,永远不要内联定义 DTO 的字段。同一个 DTO 既描述请求体也描述响应。 - 响应通过
Kipchak\Core\Components\Http\Response::json($response, $data, $status)返回,该方法将$data包装在信封{"code": 200, "status": "OK", "data": ...}中。 - 错误使用 Slim 的 HTTP 异常:
HttpNotFoundException、HttpBadRequestException、HttpUnauthorizedException、HttpForbiddenException、HttpMethodNotAllowedException。Error 中间件(kipchak/middleware-error)将它们转换为相同的信封格式,例如{"code": 404, "status": "RESOURCE_NOT_FOUND", "data": "No order has the ID 9."}。任何其他异常都会变成 500 错误,客户端看不到其消息。 - Worker 模式。 API 只启动一次,然后从内存中服务多个请求。切勿将请求数据保存在静态属性、全局变量或单例中。静态内容只能缓存对每个请求都相同的内容。
- 优先使用 Kipchak 驱动来访问服务(如果存在),而不是直接使用客户端库(参见 references/packages.md)。关系数据库使用 Doctrine 驱动。
- 配置位于
config/和环境变量中。使用Kipchak\Driver\Config\Config::get('kipchak.api')读取配置文件,该方法返回一个数组。在配置文件中使用Kipchak\Core\env('NAME', 'default')读取环境变量。切勿在控制器或模型中调用getenv()。 - 日志记录在控制器中使用
$this->logger(Monolog,PSR-3);在其他地方使用Kipchak\Driver\Logger\Logger::get()。 - API 变更即契约变更。 同时更新 DTO 和控制器属性,然后更新测试,并检查 OpenAPI 文档仍然能生成且没有警告。
添加一个端点
请遵循以下五个步骤。每个步骤的完整代码在 references/endpoints.md 中;在编写端点之前请先阅读该文件。
- DTO 位于
api/DataTransferObjects/v1/中。 - 模型 位于
api/Models/中:包含逻辑,返回 DTO。使用 Valinor 将数组映射到 DTO:(new MapperBuilder())->mapper()->map(Order::class, Source::array($row))。 - 控制器方法 位于
api/Controllers/v1/中,方法所在的类继承自Kipchak\Core\Components\Controllers\Base,方法签名为(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface,并带有#[OA\Get]、#[OA\Post](等)属性:包含路径、operationId、摘要、标签、参数、请求体和响应。 - 路由 位于
routes/v1/<resource>.php中,放置在/v1组内:$group->get('/orders/{id:[0-9]+}', [Controllers\v1\Orders::class, 'get']); - 测试 位于
tests/中,测试类继承自项目的ApiTestCase,覆盖成功和错误响应。如果项目的 OpenAPI 测试列出了预期的路径,则需要添加新路径。
参考文档
阅读与任务匹配的参考文件:
- references/endpoints.md:完整的资源示例(DTO、模型、控制器、路由、测试),包括请求体与验证、查询参数、路径参数。
- references/drivers.md:使用驱动、配置、Doctrine,以及编写新驱动。
- references/middleware.md:全局、组和路由中间件,它们的顺序,以及编写新中间件。
- references/worker-mode.md:在长生命周期 Worker 中的安全操作、请求体、连接以及响应后的工作。
- references/packages.md:每个 Kipchak 驱动和中间件,包括免费版和企业版。