zenstruck/console-extra
Modular helpers to reduce boilerplate in Symfony console commands. Build invokable commands with auto-injected IO, arguments/options via attributes, and handy traits to run other commands or processes. Designed to mix and match features or power a shared base command.
symfony/console) ensures seamless adoption.InvokableServiceCommand, RunsCommands, and RunsProcesses are decoupled, allowing selective adoption (e.g., use IO without RunsProcesses).configure() methods with PHP 8.0+ attributes, reducing boilerplate and improving readability.controller.service_arguments, the package’s InvokableServiceCommand can be adapted via Laravel’s service container (e.g., binding commands as services with bind()).Command base class. For native Laravel Artisan commands, a wrapper trait/class can bridge the gap.symfony/process only needed for RunsProcesses). No Laravel-specific conflicts.InvokableServiceCommand’s DI. Mitigation: Use Laravel’s bind() or a custom command resolver.CommandSummarySubscriber requires Symfony’s EventDispatcher. Mitigation: Implement a Laravel event listener or use Laravel’s terminating hook.define() for configuration, not attributes. Mitigation: Hybrid approach (attributes + configure() fallback).RunsProcesses relies on symfony/process. Mitigation: Laravel’s Process facade can replace it with minor adjustments.CommandSummarySubscriber be replicated with Laravel’s terminating middleware?InvokableServiceCommand add measurable overhead vs. native Artisan commands?configure())?symfony/console (already included in Laravel) to avoid reinventing the wheel.Zenstruck\Console\InvokableCommand for new commands.IO/RunsCommands features.InvokableServiceCommand instances as Laravel services using bind().$app->bind(CreateUserCommand::class, function ($app) {
return new CreateUserCommand($app->make(UserManager::class));
});
InvokableServiceCommand for new CLI features (e.g., php artisan user:create).#[Argument], #[Option]).LegacyCommandAdapter trait to retroactively add IO/RunsCommands to existing Artisan commands.class LegacyUserCommand extends Command {
use Zenstruck\Console\LegacyCommandAdapter; // Hypothetical wrapper
use RunsCommands;
protected function execute(InputInterface $input, OutputInterface $output): int {
$this->runCommand('new:user:create', [$input->getArgument('email')]);
return Command::SUCCESS;
}
}
execute() methods with __invoke().symfony/console integration.configure() calls.composer require zenstruck/console-extra
symfony/process is installed (for RunsProcesses).abstract class AppConsoleCommand extends InvokableServiceCommand {}
RunsCommands/RunsProcesses work in CI/CD pipelines.configure()/execute() code, lowering maintenance burden.IO injection, success/error handling).zenstruck/console-extra for Symfony version compatibility.symfony/console changes.configure() logic.try-catch blocks in adapters.__invoke() vs. execute()).InvokableCommand (similar to native Artisan).RunsCommands/RunsProcesses add minimal runtime cost (process spawning is the bottleneck).dispatchSync() or Process facade.CommandSummarySubscriber adds ~100ms overhead per command (memory/duration tracking). Disable in high-throughput environments.| Risk | Impact | Mitigation |
|---|---|---|
| Service Injection Failure | Command breaks if service not bound. | Use Laravel’s bind() with fallback. |
| Process Hangs | RunsProcesses blocks indefinitely. |
Set timeouts in Process objects. |
| Attribute Parsing Errors | Invalid attributes crash commands. | Validate with PHPStan or tests. |
| Event Dispatcher Mismatch | CommandSummarySubscriber fails. |
Implement Laravel event listener. |
| Backward Incompatibility | Symfony 7 drops support. | Pin version or upgrade Laravel. |
#[Argument] clarifies inputs).IO pattern.InvokableServiceCommand.IO usage, RunsCommands syntax).#[Option]).execute() while keeping others migrated.How can I help you explore Laravel packages today?