milpa/runtime
Composer 安装命令:
composer require milpa/runtime
包简介
The bootable Milpa kernel: composes milpa/container, milpa/events, milpa/http and milpa/plugin into container -> dispatcher -> capability-check -> ordered plugin boot -> route registration, with zero Doctrine and zero legacy Web coupling. The active-plugins list is config/filesystem-driven, never a
README 文档
README
Milpa Runtime
The bootable Milpa kernel — composes
milpa/core,milpa/container,milpa/events,milpa/httpandmilpa/plugininto a running app with a config-driven plugin registry, capability checks before boot, and lifecycle events. Zero database, zero magic.
milpa/runtime is where the rest of the family stops being separate packages and becomes an
app. Kernel::boot() wires a DI container, an event dispatcher, a pre-boot capability check
over every configured plugin, an ordered boot loop that emits lifecycle events at each step,
and a route table assembled from whatever plugins contribute one. The active-plugins list is
whatever list<class-string> the caller passes in — a config array, a file required into
that array, or filesystem discovery the caller performs beforehand. No Doctrine, no legacy
Milpa\Web, no database-backed plugin registry — those, if you want them, live in your host
application or a plugin you add on top.
Install
composer require milpa/runtime
Quick example
A plugin declares itself with #[PluginMetadata] and, optionally, contributes routes by
implementing RouteProviderInterface:
use Milpa\Attributes\PluginMetadata; use Milpa\Http\HttpMethod; use Milpa\Http\Routing\HandlerReference; use Milpa\Http\Routing\Route; use Milpa\Http\Routing\RouteResult; use Milpa\Interfaces\Di\DIContainerInterface; use Milpa\Interfaces\Plugin\PluginInterface; use Milpa\Runtime\Http\RouteProviderInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; final class HelloController { public function handle(ServerRequestInterface $request): ResponseInterface { $name = $request->getAttribute(RouteResult::ATTRIBUTE)?->parameter('name', 'world') ?? 'world'; return new \Nyholm\Psr7\Response(200, ['Content-Type' => 'text/plain'], "hello, {$name}"); } } #[PluginMetadata(version: '1.0.0', author: 'Acme', site: 'https://example.test', name: 'HelloPlugin', type: 'Web')] final class HelloPlugin implements PluginInterface, RouteProviderInterface { public function __construct(private readonly DIContainerInterface $container) { } public function boot(): void { } public function install(): void { } public function uninstall(): void { } public function enable(): void { } public function disable(): void { } /** @return list<Route> */ public function routes(): array { return [ new Route( path: '/hello/{name}', methods: HttpMethod::GET, name: 'hello', handler: new HandlerReference(HelloController::class, 'handle'), ), ]; } }
Kernel::boot() builds the container, capability-checks and boots the configured plugins in
provides → requires order, and assembles the route table; RequestHandler matches a real
PSR-7 request against it and dispatches to the resolved controller:
use Milpa\Runtime\Http\RequestHandler; use Milpa\Runtime\Kernel; use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7\ServerRequest; $kernel = Kernel::boot(['plugins' => [HelloPlugin::class]]); $kernel->bootedPluginNames(); // -> ['HelloPlugin'] $handler = new RequestHandler($kernel, new Psr17Factory()); $response = $handler->handle(new ServerRequest('GET', '/hello/milpa')); $response->getStatusCode(); // -> 200 (string) $response->getBody(); // -> 'hello, milpa'
No plugin can leave the boot loop undetected: boot() throws PluginDependencyException
before any plugin boots if a configured plugin requires a capability nothing configured
provides, and every step along the way — capability.resolved, plugin.booting (vetoable
via an InterceptionSlot), plugin.booted, kernel.booted — fires on the wired event
dispatcher for observability or feature-flag plugins to hook into.
Composes the family
milpa/runtime doesn't reimplement anything the family already ships — it wires the pieces
together and adds the boot sequence on top:
| Package | Owns |
|---|---|
milpa/core |
Contracts (PluginInterface, PluginMetadata, events) and the pre-boot capability check (CapabilityGraphChecker). |
milpa/container |
The DI container every plugin and controller is resolved through. |
milpa/events |
The dispatcher every lifecycle event (plugin.booting/plugin.booted, capability.resolved, kernel.booted) fires on. |
milpa/http |
Routing contracts — Route, RouteResult, RouterInterface — the route table is built from. |
milpa/plugin |
ContractResolver, the provides → requires load-order algorithm the boot loop follows. |
milpa/runtime (this package) |
Kernel::boot() itself: the wiring, the pre-boot capability check call, the ordered boot loop with lifecycle events, and Router/RequestHandler — a minimal RouterInterface implementation and PSR-15 entry point over the assembled route table. |
Requirements
- PHP ≥ 8.3
milpa/core^0.5milpa/container^0.1milpa/events^0.2milpa/http^0.1milpa/plugin^0.1
Documentation
Full API reference: getmilpa.github.io/runtime — generated straight from the source DocBlocks and dressed with the Milpa design system.
Contributing
Contributions are welcome — see CONTRIBUTING.md. Please report security issues via SECURITY.md, and note that this project follows a Code of Conduct.
License
Apache-2.0 © TeamX Agency.
Milpa is designed, built, and maintained by TeamX Agency.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 2
- 推荐数: 0
其他信息
- 授权协议: Apache-2.0
- 更新时间: 2026-07-09