decodelabs / commandment
Console command interface
Requires
- php: ^8.4
- decodelabs/archetype: ^0.3.9
- decodelabs/coercion: ^0.3.2
- decodelabs/exceptional: ^0.5.3
- decodelabs/glitch-support: ^0.5.1
- decodelabs/slingshot: ^0.2.0
Requires (Dev)
- decodelabs/phpstan-decodelabs: ^0.7.0
- decodelabs/terminus: ^0.12
Conflicts
- decodelabs/terminus: <0.12
This package is auto-updated.
Last update: 2025-05-20 13:21:05 UTC
README
Console command interface
Commandment provides a unified system for building and dispatching console actions, mirroring the dispatcher and middleware stack of Harvest.
Installation
Install via Composer:
composer require decodelabs/commandment
Usage
Build your Action to interact with the command line. The Request
object provides the raw console arguments and the means to parse them in a structured way.
Use Argument
attributes on your Action class to define the arguments you want to accept.
Constructor arguments are automatically injected into your Action class - import the Terminus Session
to write to the output stream to keep your Actions portable.
namespace MyThing\Action; use DecodeLabs\Commandment\Action; use DecodeLabs\Commandment\Argument; use DecodeLabs\Commandment\Request; use DecodeLabs\Terminus\Session; #[Argument\Value( name: 'input', description: 'Input value', required: true, default: 'default' )] #[Argument\Flag( name: 'verbose', shortcut: 'v', description: 'Enable verbose output' )] #[Argument\Option( name: 'potatoes', shortcut: 'p', description: 'How many potatoes?', default: 5 )] class MyAction implements Action { public function __construct( protected Session $io ) { } public function execute( Request $request ): bool { $this->io->writeLine('Hello world!'); $this->io->writeLine('Input: '. $request->parameters->tryString('input')); if($request->parameters->asBool('verbose')) { $this->io->writeLine('Verbose output enabled'); for($potato = 0; $potato < $request->parameters->asInt('potatoes'); $potato++) { $this->io->writeLine('Potato #'. ($potato + 1)); } } return true; } }
effigy my-action "this is my input" -v --potatoes=3
Dispatching
To run your Action, create a Dispatcher
and a Request
object, then call the dispatch()
method:
use DecodeLabs\Commandment\Dispatcher; $dispatcher = new Dispatcher(); $request = $dispatcher->newRequest( command: 'my-action', arguments: [ 'this is my input', '-v', '--potatoes=3' ], attributes: [ 'arbitrary' => 'data' ], server: [ 'override' => '$_SERVER' ] ); $dispatcher->dispatch($request);
If you want to provide extra objects for dependency injection, you can add them to the Slingshot
instance, either on the Dispatcher
or on the Request
object:
use DecodeLabs\Commandment\Dispatcher; use MyThing\PotatoPeeler; use MyThing\PotatoMasher; $dispatcher = new Dispatcher(); $dispatcher->slingshot->addType(new PotatoPeeler()); $request = $dispatcher->newRequest('my-action', ['input ...']); $request->slingshot->addType(new PotatoMasher()); $request->slingshot->addParameter([ 'arbitrary' => 'data' ]); $dispatcher->dispatch($request);
You can then reference these types in your Action constructor:
namespace MyThing\Action; use DecodeLabs\Commandment\Action; use DecodeLabs\Commandment\Request; use DecodeLabs\Terminus\Session; use MyThing\PotatoPeeler; use MyThing\PotatoMasher; class MyAction implements Action { public function __construct( protected Session $io, protected PotatoPeeler $peeler, protected PotatoMasher $masher, protected string $arbitrary ) { } public function execute( Request $request ): bool { // Do the thing return true; } }
Middleware
Commandment supports simple middleware which can be used to modify the request before the Action is executed.
It doesn't need to handle the $next
middleware like traditional middleware as the CLI context doesn't require traditional response handling. Instead, just return a modified Request
object.
use DecodeLabs\Commandment\Middleware; class MyMiddleware implements Middleware { public function handle( Request $request, ): Request { // Do something with the request $request = $request->rewrite( command: 'redirected-action', arguments: [ 'new-argument' ], ); return $request; } }
Add the middleware to the dispatcher before dispatching:
use DecodeLabs\Commandment\Dispatcher; use MyThing\Middleware\MyMiddleware; $dispatcher = new Dispatcher(); $dispatcher->addMiddleware(new MyMiddleware()); $request = $dispatcher->newRequest('my-action', ['input ...']); $dispatcher->dispatch($request);
Licensing
Commandment is licensed under the MIT License. See LICENSE for the full license text.