Title here
Summary here
| Kind | Hooks into Pionia boot? | Example |
|---|---|---|
| Plugin | No — plain PHP library | Validator, HTTP client, DTO mapper |
| Provider | Yes — middleware, auth, routes, commands | acme/pionia-billing |
Plugins are normal Composer packages. Require them and use them from services.
Providers extend Pionia\Base\Provider\Provider and register capabilities during application boot. See App providers.
composer.json in your package:
{
"name": "acme/phone-normalizer",
"require": { "php": ">=8.5" },
"autoload": { "psr-4": { "Acme\\Phone\\": "src/" } }
}src/Normalizer.php — no Pionia imports required:
namespace Acme\Phone;
final class Normalizer
{
public static function e164(string $raw): string
{
return preg_replace('/\D/', '', $raw) ?? '';
}
}Use from a service:
use Acme\Phone\Normalizer;
protected function registerAction(\Pionia\Collections\Arrayable $data): \Pionia\Http\Response\ApiResponse
{
$phone = Normalizer::e164((string) $data->get('phone'));
return response(0, 'OK', ['phone' => $phone]);
}Structure:
acme-pionia-billing/
composer.json
src/
BillingProvider.php
BillingSwitch.php
Middleware/BillingContextMiddleware.php
Commands/SyncInvoicesCommand.phpBillingProvider.php
namespace Acme\Billing;
use Pionia\Base\Provider\Provider;
use Pionia\Http\Routing\PioniaRouter;
use Pionia\Middlewares\MiddlewareChain;
class BillingProvider extends Provider
{
public function middlewares(MiddlewareChain $chain): MiddlewareChain
{
return $chain->add(Middleware\BillingContextMiddleware::class);
}
public function commands(): array
{
return ['billing:sync' => Commands\SyncInvoicesCommand::class];
}
public function routes(PioniaRouter $router): PioniaRouter
{
// Use a unique version slug — not "v2" unless you own that API surface
return $router->switch(BillingSwitch::class, 'billing');
}
}CLI command in the package — extend Pionia\Console\Command:
namespace Acme\Billing\Commands;
use Pionia\Console\Command;
class SyncInvoicesCommand extends Command
{
protected string $name = 'billing:sync';
protected string $description = 'Pull invoices from the billing API';
protected function handle(): int
{
$this->info('Syncing…');
return Command::SUCCESS;
}
}Input helpers live under Pionia\Console\Input\ (InputArgument, InputOption) — same concepts as other PHP CLIs, but native to Pionia.
After composer require acme/pionia-billing:
; environment/settings.ini
[app_providers]
billing=Acme\Billing\BillingProviderOr in bootstrap/application.php:
$app = AppRealm::create(__DIR__);
$app->web()->addAppProvider(\Acme\Billing\BillingProvider::class);
return $app;Clear cache when removing a provider:
php pionia cache:clearcomposer create-project pionia/pionia-app sandbox.composer.json:"repositories": [
{ "type": "path", "url": "../acme-pionia-billing", "options": { "symlink": true } }
],
"require": {
"acme/pionia-billing": "@dev"
}composer update acme/pionia-billing and register the provider./api/billing/ (or your chosen version) and php pionia billing:sync.Provider FQCN documented in READMEroutes()Application\ namespacesuggest, not require@moonlight-* tags on public actions if you ship HTTP API docs