nih/legacy-gateway
Composer 安装命令:
composer require nih/legacy-gateway
包简介
Route-level legacy fallback for route-by-route migration in PSR-15 applications built on nih/http-kernel.
关键字:
README 文档
README
Route-level legacy facade for PSR-15 applications built on top of nih/http-kernel.
What It Is
nih/legacy-gateway lets a PSR-15 application act as a facade over an existing legacy application.
Migrating a legacy system that already works in production is almost always painful:
- the old code must keep serving real traffic
- the new code must go live incrementally
- old and new behavior must coexist for a while
- a big-bang rewrite is usually too risky
That is why route-by-route migration exists as a practical strategy.
Instead of replacing the whole legacy application at once, you move one route, one endpoint group, or one use case at a time into the new PSR-15 application. The rest of the traffic continues to be handled by legacy code until you are ready to migrate it too.
This gives teams a controlled migration boundary:
- new routes can be implemented in modern middleware and handlers
- existing legacy pages can continue to work unchanged
- the application can stay online while the boundary moves gradually toward the new codebase
The router defines the boundary between modern and legacy code:
- if a request matches a modern route, it stays in the PSR-15 pipeline
- if no route matches, control falls through to a legacy entrypoint
In other words, the PSR-15 application becomes a route-level facade in front of legacy behavior. Every newly migrated route is claimed by the modern router, and everything else still falls through to the legacy entrypoint.
This makes gradual migration possible without introducing a separate reverse proxy, splitting the application into two public entrypoints, or forcing a rewrite-first migration plan.
How Request Routing Works
The package keeps the integration surface intentionally small:
LegacyGatewayBootstrapinsertsLegacyGatewayMiddlewareimmediately afterRouteMatchMiddlewareLegacyGatewayMiddlewaredecides whether the request stays in the PSR-15 application or falls through to legacy code
The key bootstrap line is:
$app->pipeline->append(LegacyGatewayMiddleware::class, after: RouteMatchMiddleware::class);
This is the whole routing boundary in one place:
RouteMatchMiddlewareruns first and decides whether the current request matches a modern routeLegacyGatewayMiddlewareruns immediately after that decision- if a route was matched, the request stays in the modern PSR-15 pipeline
- if no route was matched, the request can fall through to legacy
Without this exact placement, the package would not be route-driven. It would either run too early, before routing knows anything, or too late, after the request had already moved deeper into the modern dispatch flow.
Request flow:
- The request enters the
nih/http-kernelapplication. - Routing runs and produces a
RouteMatchResult. - If the route was matched, the request continues through the normal PSR-15 pipeline.
- If routing returns
RouteMatcher::NOT_FOUND, the middleware hands off to the legacy entrypoint. - The handoff is wrapped in
DeferredCallableResponse, so the kernel can restore runtime state before executing legacy code.
In practice, this means the PSR-15 app can behave like a route-level proxy or facade over legacy behavior while keeping routing as the decision point.
When To Use It
Typical use cases:
- migrate a legacy system route by route
- move new endpoints such as
/api/*,/health, or/admin/*into PSR-15 code first - keep a single application entrypoint while modern and legacy code coexist
Example migration shape:
/api/users,/health, and/admin/loginare matched by the modern router and handled by PSR-15 middleware and handlers/catalog,/checkout, and all unmatched URLs fall through tolegacy/index.php
Quick Start
Applications opt in explicitly by adding LegacyGatewayBootstrap to the bootstrap list and overriding the demo entrypoint binding in an app-specific bootstrap.
Recommended bootstrap order:
return [ NIH\HttpKernel\Bootstrap\Psr17Bootstrap::class, NIH\HttpKernel\Bootstrap\ErrorHandlingBootstrap::class, NIH\HttpKernel\Bootstrap\RoutingBootstrap::class, NIH\LegacyGateway\LegacyGatewayBootstrap::class, App\Bootstrap\AppBootstrap::class, ];
Why this order matters:
RouteMatchMiddlewaremust run beforeLegacyGatewayMiddleware- the legacy gateway must see the routing result before route dispatch
- the app-specific bootstrap should override the demo fallback configured by
LegacyGatewayBootstrap
In other words, LegacyGatewayBootstrap does not just "register one more middleware". It places the legacy gateway exactly at the point where the application already knows whether the request belongs to the new router or should fall through to the old system.
LegacyGatewayBootstrap ships with a demonstration fallback only:
$app->services->auto(LegacyGatewayMiddleware::class) ->argument('entrypoint', static function (): void { echo 'Legacy Fallback'; });
Real applications are expected to replace that with their own legacy entrypoint.
Configure the Legacy Entrypoint
File-based handoff
<?php declare(strict_types=1); namespace App\Bootstrap; use NIH\HttpKernel\Bootstrap\BootstrapInterface; use NIH\HttpKernel\HttpApplication; use NIH\LegacyGateway\LegacyGatewayMiddleware; final class AppBootstrap implements BootstrapInterface { public static function boot(HttpApplication $app): void { $app->services->auto(LegacyGatewayMiddleware::class) ->argument('entrypoint', dirname(__DIR__) . '/legacy/index.php'); } }
Closure-based handoff
$app->services->auto(LegacyGatewayMiddleware::class) ->argument('entrypoint', static function (): void { require __DIR__ . '/../legacy/index.php'; });
Use a closure when the handoff needs extra bootstrapping logic. Use a file path when a direct require is enough.
Runtime Contract
LegacyGatewayMiddleware:
- requires an
entrypointargument of typestring|Closure - throws for an empty string
- requires a
RouteMatchResultrequest attribute - only attempts handoff when routing produced
RouteMatcher::NOT_FOUND - falls through to the next handler when a string
entrypointis not a readable file - calls
PipelineControl::bypassOuter()when available - returns
DeferredCallableResponse - does not emit output directly
Out Of Scope
This package stays at the routing boundary. It is not responsible for:
- output-buffer cleanup
- HTTP state restoration
- error rendering
- fatal handling
Those runtime concerns belong to nih/http-kernel, not to this package.
nih/legacy-gateway 适用场景与选型建议
nih/legacy-gateway 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 11 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「routing」 「legacy」 「psr-15」 「legacy migration」 「route-by-route migration」 「incremental migration」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 nih/legacy-gateway 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 nih/legacy-gateway 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 nih/legacy-gateway 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Write down your routing mapping at one place
Ipgeobase PHP API
Yii2 Extension for sending push notification with both Firebase Cloud Messaging (FCM) HTTP Server Protocols (APIs).
Flight routing is a simple, fast PHP router that is easy to get integrated with other routers.
Client Legacy lib for Rest PKI
Client for Google Directions API to add interpolated points to a route consisting of given coordinates.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 39
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-11