Skip to content

Releases: route-forge/php-common

v1.2.0

Choose a tag to compare

@xyj2156 xyj2156 released this 14 Sep 13:43
f3fa70d

未命名路由不再静默消失,严格模式一次报全「缺名字 / 缺层级」两类问题。

根因:RouteAnalyzerRouteRepository 都在 resolve() 之前把 name 为空的路由跳过,且告警条件只看原始显式 tier——于是「靠 config match 规则或 classifier 回调归入层级却没写名字」的路由既不进元信息、也不进 list 行、更不进 tier_counts,一条信号都不留;SPEC 承诺的 strict_mode 500(RF_BE_005)因此在生产里从不触发,是死代码。

修复

  • 未命名路由不再静默消失:现逐条探测层级归属并全量收集,被层级规则命中的未命名路由按层级分组进入 warnings(含 URI、HTTP 方法、中间件与命中来源,可直接 grep 定位)。
  • 历史文案兼容点:「显式 ->tier() 无名」的整句 Route (uri) has tier [x] but no route name assigned; … 原样保留(方法/中间件追加为句尾标签),适配包 Feature 测试与 CI 脚本的 substring / grep 断言不受影响。
  • RF_BE_005 不再是死代码:严格模式的「有层级归属却无路由名」由 StrictViolationScanner 在取数入口做全量预扫描接管(见下方「变更」)。

变更

破坏性提示:以下两项改变 strict_mode=true 项目的对外错误形态,适配包需按新文案同步 Feature 测试与 SPEC §3.2 / §6.1。

  • HTTP 端点strict_mode=true 时,任一读路径(层级端点 / 摘要 / 全量 / unassigned)取数前先全量扫描,发现「有层级归属却无路由名」或「命名路由未归级」即抛新错误码 RF_BE_009RouteStrictViolationException,HTTP 500),message 分组列出两类全量清单,violations() 另给结构化清单供页面高亮定位。取代原先「第一条 RF_BE_001 / RF_BE_005 就中断」的修一条刷一条模式;RF_BE_001 / RF_BE_005 两个异常类与错误码保留(TierResolver::resolve() 的单条语义不变)。层级名拼错、classifier 抛错等更精确的配置错误仍走各自错误码(RF_BE_002 / 004 / 006),只在聚合消息里作信息附录。
  • 命令行route:forge:list / typesstrict_mode=true 下不再因未归级路由直接以退出码 1 中断(命令本身在排查场景必须还能跑),改为经 analyze()['violations'] 全量输出「缺名字 / 缺层级 / 无法判定」三组,由命令层统一渲染成红色清单并决定退出码。宽松模式输出形态完全不变:表格、tier_counts--json 契约一字未动。
  • 未命名且不命中任何层级的路由不算违规:它压根不在 forge 管辖范围内(否则 vendor 与框架内部路由会把严格模式报错刷满)。

新增

  • Support\StrictViolationScanner:严格模式违规的唯一判定与措辞来源,scan() 返回 {missing_name, unassigned, unresolved}(按实例记忆,一次请求只扫一遍),count() 明确排除 unresolvedformat() 生成 HTTP 错误体与命令行红色清单共用的清单文本。
  • Exception\RouteStrictViolationExceptionRF_BE_009,500):fromViolations() 构造、violations() 输出结构化清单。
  • RouteAnalyzer::analyze() 输出新增 violations 键(仅严格模式非空);RouteRepositoryinfos() 入口挂预扫描。
  • Support\HttpMethods::withoutHead():HEAD 过滤的单点实现,RouteAnalyzer::withoutHead() 保留为委托入口,公开签名不变。
  • TierResolver::probe(RouteInfo):与 resolve() 共享同一套优先级求值(抽出 classifierTier() / matchedTier() 私有 helper 防口径漂移)的只读探测,返回 {level, source, requested, error}source ∈ explicit | classifier | match | none | explicit-unknown-level | classifier-unknown-tier | classifier-error。与 resolve() 的一致性由单测钉住。
  • TierResolver::configuredLevels() / isStrict():按配置顺序返回层级名、暴露严格模式开关,命令层与分析器不再各自读配置。
  • RouteAnalyzer::unnamedWarnings() / RouteAnalyzer::formatUnnamed():未命名路由的告警文本与 --unnamed 分组视图,文案在 common 单点生成,两个适配包不再各写一份。
  • RouteNameFilter 新增按 URI 前缀排除的第二维度(isUriExcluded() / 不可变 withUriPrefixes()):未命名路由没有名字可判,而 forge 自身的层级端点(如 _forge/routes/managemanage 中间件)会被 match 规则命中,不排除就是包把自己报成配置错误。URI 按段匹配,_forge/routes 不误伤 _forge/routeship

测试

  • 全量 109 tests / 291 assertions 通过(发布前 78 例 → 新增 31 例),CI 矩阵 PHP 8.2 / 8.3 双绿。
  • 新增 UnnamedRouteVisibilityTest(未命名路由归类、聚合文案、strict 不新增失败模式、计数口径、URI 排除、漂移守卫)与 StrictViolationScanTest(扫描器三分、RF_BE_009 聚合抛出、宽松静默、精确错误码不被冒名)。

版本

新增公开 API + 严格模式对外错误码变化(RF_BE_001/005RF_BE_009),宽松模式零变化,按 minor 发 1.2.0schemeVersion 保持 1。两个适配包(php-laravel / php-thinkphp)的 --unnamed 选项、红色 violations 渲染与 withUriPrefixes() 接线,以及 .docs/SPEC.md §3.1.4 / §3.2 / §6.1 的同步尚未跟进。

1.1.2...1.2.0 · 完整变更见 CHANGELOG.md

v1.1.2

Choose a tag to compare

@xyj2156 xyj2156 released this 11 Sep 16:13
b3e7000

修复

  • ConfigFileGenerator::formatMatchArrayformatLevelEntrymatch.prefix / match.middleware 及 level 级 endpoint_middleware 统一 (array) 归一:传单值字符串(如 'prefix' => 'admin')时,保存生成 config/forge.php 不再在 exportInlineArray(array) 的类型声明上抛 TypeError,落盘规范化为单元素数组字面量,语义与 TierResolver::matchConfig(1.1.1)对齐。此前手写配置的字符串写法能被读取、却无法经管理器保存回写,属两侧不对称。

测试

  • 新增 ConfigFileGeneratorTest:单值 string 与数组写法逐条生成等价(prefix / middleware / level endpoint_middleware)+ 空值边界回归;全量 78 tests / 201 assertions 通过。

版本

纯缺陷修复,无 API / 载荷形状变化,schemeVersion 保持 1。

1.1.1...1.1.2

v1.1.1

Choose a tag to compare

@xyj2156 xyj2156 released this 10 Sep 11:57
60bb26d

修复

  • TierResolver::matchConfig 对 match 规则统一类型归一化:match.prefix / match.middleware 传单值字符串(如 'prefix' => 'admin')不再抛 count(): Argument #1 ($value) must be of type Countable|array, string given,行为与单元素数组完全等价(按段匹配、空字符串不命中等语义不变)。
  • middleware_match 增加类型守卫:传入非 string/array 类型时回落 'any' 并记录 warning(此前直接 TypeError 崩溃)。

测试

  • 新增 5 个单测:string / 数组两种写法逐条等价(prefix、middleware、两者同时)+ 空值边界回归 + 非法 middleware_match 类型回落;全量 72 tests / 189 assertions 通过。

版本

纯缺陷修复,无 API / 载荷形状变化,schemeVersion 保持 1。

1.1.0...1.1.1

v1.1.0

Choose a tag to compare

@xyj2156 xyj2156 released this 09 Sep 15:26
f875f8e

修复

  • JsSafeEncoder 补齐 JSON_UNESCAPED_UNICODE:与 Illuminate\Support\Js::from 逐位对齐。@forgeSummary 内嵌载荷中的中文(如 levels.*.description)不再被转成 \uXXXX,避免首屏 <head> 载荷体积按字符数成倍膨胀;JS 解析结果本就等价。
  • 别名跟随 target 解析到的每一个层级:同一目标路由名以不同层级重复注册时,别名此前只随末次层级,导致 route:forge:list --level=<另一层级>typesd.ts 缺该条目。现在端点 / list / types / 管理器四处一律跟随目标解析到的每个层级;route_counttier_counts 口径不变(一别名只计一次)。

提示

  • 路由名跨层级重复注册时,RouteAnalyzer 输出 warning 点名歧义,而非静默择一。

完整变更

1.0.0…1.1.0

v1.0.0

Choose a tag to compare

@xyj2156 xyj2156 released this 08 Sep 16:13
232635a

route-forge/common 首个正式版本 —— 从 route-forge-laravel 拆分出的框架无关核心,供各框架适配器(Laravel / ThinkPHP / Symfony)复用。

核心能力

  • Tier 分级解析:5 优先级解析链(显式声明 > 分类器 > 配置匹配 > 未分配兜底),支持 middleware_match any / all / DNF
  • 别名系统:宏声明 + 配置双来源合并,冲突丢弃并告警,悬空目标快速失败(RF_BE_008)
  • 统一路由仓库:按层级的元信息 / 摘要 / 未分配 / 全量索引,全部走缓存
  • TS 类型生成:d.ts / JSON 双输出,collectTargets() 支持各框架 types 命令复用(空层级保留、HEAD 过滤、body 方法识别)
  • 摘要内嵌__ROUTE_FORGE__ 一次性嵌入,JsSafeEncoder 语义与安全 JSON.parse 等价
  • 配置文件生成:PHP 源码级生成,动态值全量转义
  • 缓存层SUMMARY_LEVEL + forgetLevel() 保证层级失效必同步失效摘要

分析管道(供框架命令复用)

  • RouteAnalyzer::analyzeRoutes():raw 路由集合 + normalizer 直入分析管道
  • filterRows() / withoutHead() / listPayload():SPEC §3.2 list --json 契约组装下沉
  • RouteRepository::normalizeEndpointPrefix():端点前缀规范化公共工具

工程保障

  • 仅依赖 psr/log,零框架引用(红线见 AGENTS.md)
  • 60 个框架无关单元测试,131 断言
  • 独立 CI:PHP 8.2 – 8.5 全矩阵

完整变更

提交历史