承接 milpa/skeleton 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

milpa/skeleton

Composer 安装命令:

composer create-project milpa/skeleton

包简介

The composer create-project starting point for a Milpa app: boots milpa/runtime's Kernel, serves a real HTTP response with zero database, and ships a minimal coa CLI (doctor/validate/make) wired to milpa/devtools.

README 文档

README

Milpa

Milpa Skeleton

composer create-project milpa/skeleton myapp → an app that runs — booted, serving /, answering coa — with zero database. This is your starting point, not a demo.

CI Packagist PHP License

milpa/skeleton is the smallest real host of milpa/runtime: a Kernel::boot() call, one plugin, one route, one CLI. No Doctrine, no legacy Milpa\Web, nothing to configure before you see it work.

Quickstart

composer create-project milpa/skeleton myapp
cd myapp
php -S localhost:8000 -t public

Open http://localhost:8000 — you'll see "Milpa is running", served by App\Plugins\HelloPlugin\Controllers\HomeController through Milpa\Runtime\Http\RequestHandler.

Then check the CLI:

php bin/coa doctor
milpa · coa doctor
root: /path/to/myapp
✔ 1 plugin(s) configured, 1 booted: HelloPlugin
✔ container: Milpa\Container\DIContainer
✔ dispatcher: Milpa\Eventing\EventDispatcher
✔ 1 route(s) declared (RouteProviderInterface plugins)
✔ config: app.greeting = 'Milpa is running.'
✔ kernel booted — zero database queries.

What's in here

Path What it is
public/index.php The HTTP entry point: builds a PSR-7 request from globals, boots the kernel, dispatches through Milpa\Runtime\Http\RequestHandler, emits the response.
bin/coa The CLI entry point — doctor, validate, make:controller. See src/Console/Application.php.
config/plugins.php The active-plugins list — a plain list<class-string>. This is the only source of truth for what boots; no database, no filesystem discovery.
config/app.php The app-config bag. Registered by Kernel::boot() as Milpa\Runtime\Config; plugins read it in boot(). See The Config idiom.
src/Plugins/HelloPlugin/ The example plugin: #[PluginMetadata], no provides/requires, one GET / route, and the Config read that drives the homepage greeting. Copy its shape for your own plugins.
tests/Boot/KernelBootTest.php The boot smoke test: the kernel boots from config/plugins.php and GET / returns 200.

Add a plugin

  1. Create src/Plugins/YourPlugin/YourPlugin.php implementing Milpa\Interfaces\Plugin\PluginInterface with a #[Milpa\Attributes\PluginMetadata(...)] attribute (copy HelloPlugin's shape).
  2. To contribute routes, also implement Milpa\Runtime\Http\RouteProviderInterface::routes() — return a list<Milpa\Http\Routing\Route>, each bound to a Milpa\Http\Routing\HandlerReference(ControllerClass::class, 'method').
  3. Write a controller whose method takes a Psr\Http\Message\ServerRequestInterface and returns a Psr\Http\Message\ResponseInterface (see HomeController — this skeleton ships nyholm/psr7 as its PSR-7 implementation, since milpa/http deliberately ships contracts only, no concrete request/response classes).
  4. Add the class to config/plugins.php.
  5. php bin/coa doctor to confirm it booted and its routes were counted; php bin/coa validate for a static pre-boot capability check without running boot().

Milpa\Runtime\Kernel::boot() capability-checks every configured plugin's #[PluginMetadata] before anything boots — a requires with no matching provides fails loudly, pre-boot, with a typed PluginDependencyException, not a runtime surprise three requests later.

The Config idiom

A plugin's constructor is fixed by Milpa\Interfaces\Plugin\PluginInterface to a single argument — (DIContainerInterface $container). It never receives config values directly. So how does a plugin get a storage path, an API base URL, or a greeting string? It reads them in boot() from the app-config bag:

  1. Put configuration in config/app.php, which returns a nested array. Dot-notation indexes it, so ['app' => ['greeting' => 'Hi']] is read back as app.greeting.

  2. public/index.php (and bin/coa) pass it into the kernel:

    $kernel = Kernel::boot([
        'plugins' => require $root . '/config/plugins.php',
        'config'  => require $root . '/config/app.php',
    ]);
  3. Kernel::boot() registers it in the container as Milpa\Runtime\Config. A plugin reads what it needs in boot() — this is exactly what HelloPlugin does:

    public function boot(): void
    {
        $greeting = $this->container->get(Config::class)->get('app.greeting', 'Milpa is running.');
        $this->container->registerService(HomeController::class, new HomeController($greeting));
    }

Edit app.greeting in config/app.php, reload http://localhost:8000, and the heading changes — no env vars, no constructor plumbing. That is the whole idiom: config lives in a file, plugins read it in boot(), coa doctor echoes back the value it resolved.

Scaffolding with coa

bin/coa wires milpa/devtools' generate/inspect layer straight into this project — including for an agent driving the CLI, not just a human:

php bin/coa doctor                                        # boot the kernel, report what came up
php bin/coa validate                                      # static capability check, no boot()
php bin/coa make:controller HelloPlugin GreetingController --methods=index

make:controller is real milpa/devtools machinery (Milpa\DevTools\Make\Generators\ControllerGenerator

  • WriteGuard) — but its output targets the legacy Milpa host convention devtools was built for (Milpa\Plugins\*\Controllers, extends Milpa\app\Providers\BaseController), not this skeleton's App\Plugins\* + RouteProviderInterface pattern. The command prints that mismatch after writing the file; treat the generated code as a reference and adapt the namespace, base class, and route wiring by hand. See this front's SDD report for the full context — closing that gap with a runtime-native generator is a natural next step for milpa/devtools.

What this is NOT

  • Not a finished app. One plugin, one route, one page. Everything past that is yours to add.
  • Not wired to a database. milpa/runtime's plugin registry is config-driven, never a Doctrine entity — persistence is something a plugin opts into, never something the kernel requires. Add doctrine/orm and a storage plugin when (if) you need one.
  • Not the only PSR-7 choice. nyholm/psr7 is declared here as a real dependency because milpa/http ships routing contracts only, no concrete request/response implementation. Swap it for another PSR-7/PSR-17 implementation if you prefer — public/index.php and RequestHandler only depend on the PSR interfaces.

The family

This skeleton composes six published Milpa packages, unmodified:

Contributing

Contributions are welcome. Please report security issues responsibly, and note that this project follows a standard code of conduct.

License

Apache-2.0 © TeamX Agency.

Milpa is designed, built, and maintained by TeamX Agency.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: Apache-2.0
  • 更新时间: 2026-07-09

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固