neuron-php / cli
Unified command-line interface for the Neuron PHP framework
Requires
- php: ^8.4
- neuron-php/application: ^0.7
Requires (Dev)
- phpmd/phpmd: ^2.15
- phpunit/phpunit: ^9.0
This package is auto-updated.
Last update: 2025-08-14 15:13:52 UTC
README
A unified command-line interface for the Neuron PHP framework that provides a modern, extensible CLI tool for all Neuron components.
Features
- Unified CLI Interface - Single entry point for all component commands
- Automatic Command Discovery - Auto-detects commands from installed components
- Rich Terminal Output - Colored output, tables, and progress bars
- Zero Configuration - Works out of the box with any Neuron component
- Extensible Architecture - Easy to add custom commands
- ️ Built on Solid Foundation - Extends Neuron's CommandLineBase for consistency
Requirements
- PHP 8.4 or higher
- Composer
- Neuron Application component
Installation
Local Installation (Recommended)
composer require neuron-php/cli
After installation, the CLI will be available at:
./vendor/bin/neuron
Global Installation
composer global require neuron-php/cli
Make sure your global Composer bin directory is in your PATH, then:
neuron version
Basic Usage
List All Commands
neuron list
Get Help
# General help neuron --help # Help for specific command neuron help make:controller
Run Commands
# Run a command neuron make:controller UserController # With options neuron make:controller UserController --resource # With verbose output neuron make:controller UserController -v
For Component Developers
The CLI component provides two ways for your component to register commands:
Method 1: CLI Provider Class (Recommended)
This is the preferred method as it keeps all command registrations in one place.
- Update your component's
composer.json
:
{ "name": "neuron-php/your-component", "extra": { "neuron": { "cli-provider": "Neuron\\YourComponent\\Cli\\CommandProvider" } } }
- Create the provider class:
<?php namespace Neuron\YourComponent\Cli; class CommandProvider { public static function register($app): void { // Register your commands $app->register('component:command1', Command1::class); $app->register('component:command2', Command2::class); $app->register('component:command3', Command3::class); } }
Method 2: Direct Registration
For simpler cases, you can register commands directly in composer.json
:
{ "name": "neuron-php/your-component", "extra": { "neuron": { "commands": { "component:command": "Neuron\\YourComponent\\Commands\\YourCommand", "component:another": "Neuron\\YourComponent\\Commands\\AnotherCommand" } } } }
Creating Command Classes
All commands must extend the base Command
class:
<?php namespace Neuron\YourComponent\Commands; use Neuron\Cli\Commands\Command; class MakeControllerCommand extends Command { /** * Get the command name (how it's invoked) */ public function getName(): string { return 'make:controller'; } /** * Get the command description (shown in list) */ public function getDescription(): string { return 'Create a new controller class'; } /** * Configure arguments and options */ public function configure(): void { // Add required argument $this->addArgument('name', true, 'The controller name'); // Add optional argument with default $this->addArgument('namespace', false, 'Custom namespace', 'App\\Controllers'); // Add boolean option (flag) $this->addOption('resource', 'r', false, 'Create a resource controller'); // Add option that accepts a value $this->addOption('model', 'm', true, 'Model to bind to controller'); // Add option with default value $this->addOption('template', 't', true, 'Template to use', 'default'); } /** * Execute the command * * @return int Exit code (0 for success) */ public function execute(): int { // Get arguments $name = $this->input->getArgument('name'); $namespace = $this->input->getArgument('namespace'); // Get options $isResource = $this->input->getOption('resource'); $model = $this->input->getOption('model'); // Output messages $this->output->info("Creating controller: {$name}"); // Show progress for long operations $progress = $this->output->createProgressBar(100); $progress->start(); for ($i = 0; $i < 100; $i++) { // Do work... $progress->advance(); usleep(10000); } $progress->finish(); // Success message $this->output->success("Controller created successfully!"); return 0; // Success } }
Command Naming Conventions
- Use namespace format:
component:action
(e.g.,mvc:controller
,cms:init
) - Use kebab-case for multi-word actions:
make:controller
,cache:clear
- Group related commands under the same namespace
- Keep names short but descriptive
Built-in Commands
Core Commands
Command | Description | Usage |
---|---|---|
help |
Display help for a command | neuron help [command] |
list |
List all available commands | neuron list |
version |
Show version information | neuron version [--verbose] |
Output Helpers
The Output
class provides rich formatting options:
Basic Output
// Simple messages $this->output->write('Simple message'); $this->output->writeln('Message with newline', 'green'); // Styled messages $this->output->info('Information message'); // Cyan $this->output->success('Success message'); // Green with ✓ $this->output->warning('Warning message'); // Yellow with ⚠ $this->output->error('Error message'); // Red with ✗ $this->output->comment('Comment'); // Yellow // Sections and titles $this->output->title('Command Title'); $this->output->section('Section Header');
Tables
$this->output->table( ['Name', 'Version', 'Description'], [ ['cli', '1.0.0', 'CLI component'], ['mvc', '0.6.0', 'MVC framework'], ['cms', '0.5.0', 'Content management'], ] );
Progress Bars
$progress = $this->output->createProgressBar(100); $progress->start(); foreach ($items as $item) { // Process item... $progress->advance(); } $progress->finish();
Interactive Input
The CLI component provides full support for interactive user input in commands:
// Check if terminal is interactive if (!$this->input->isInteractive()) { $this->output->error('This command requires an interactive terminal'); return 1; } // Ask for text input with optional default $name = $this->input->ask('What is your name?', 'Anonymous'); // Ask without default (returns empty string if no input) $email = $this->input->ask('Enter your email'); // Ask yes/no questions if ($this->input->confirm('Do you want to continue?', true)) { // User confirmed (pressed y/yes/1/true or Enter with default true) } // Read raw input with custom prompt $line = $this->input->readLine('> ');
Interactive Input Methods
Method | Description | Example |
---|---|---|
isInteractive() |
Check if terminal supports interaction | if ($this->input->isInteractive()) |
ask($question, $default) |
Ask for text input | $name = $this->input->ask('Name?', 'John') |
confirm($question, $default) |
Ask yes/no question | if ($this->input->confirm('Continue?', true)) |
askSecret($question) |
Ask for hidden input (passwords) | $pass = $this->input->askSecret('Password') |
choice($question, $choices, $default, $multiple) |
Select from options | $opt = $this->input->choice('Pick:', ['A', 'B']) |
readLine($prompt) |
Read raw input line | $line = $this->input->readLine('> ') |
Example: Interactive Setup Command
class SetupCommand extends Command { public function execute(): int { if (!$this->input->isInteractive()) { $this->output->error('Setup requires interactive mode'); return 1; } // Gather information $project = $this->input->ask('Project name', 'my-app'); $author = $this->input->ask('Author name'); $email = $this->input->ask('Author email'); // Validate email while (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $this->output->error('Invalid email format'); $email = $this->input->ask('Author email'); } // Show summary $this->output->section('Configuration Summary'); $this->output->write("Project: {$project}"); $this->output->write("Author: {$author} <{$email}>"); // Confirm if (!$this->input->confirm('Create project with these settings?', true)) { $this->output->warning('Setup cancelled'); return 1; } // Proceed with setup... $this->output->success('Project created successfully!'); return 0; } }
Secret Input (Passwords)
The askSecret()
method hides user input, perfect for passwords and sensitive data:
// Ask for password (input will be hidden) $password = $this->input->askSecret('Enter password'); // Confirm password $confirm = $this->input->askSecret('Confirm password'); if ($password !== $confirm) { $this->output->error('Passwords do not match'); return 1; }
Choice Selection
The choice()
method presents options for selection:
// Simple choice from array $colors = ['Red', 'Green', 'Blue']; $color = $this->input->choice('Pick a color:', $colors, 'Blue'); // Associative array (key => display value) $environments = [ 'dev' => 'Development', 'staging' => 'Staging', 'prod' => 'Production' ]; $env = $this->input->choice('Select environment:', $environments, 'dev'); // Multiple selection $features = [ 'api' => 'REST API', 'auth' => 'Authentication', 'cache' => 'Caching' ]; $selected = $this->input->choice( 'Select features to enable:', $features, null, // No default true // Allow multiple ); // Returns array like: ['api', 'auth'] // Users can select by: // - Number: Type "1" for first option // - Key: Type "dev" for development // - Value: Type "Development" (case-insensitive) // - Multiple: "1,3" or "api,cache" (when multiple allowed)
How Command Discovery Works
- Installation Detection: When
neuron
is run, the ComponentLoader scans for installed packages - Package Filtering: Only
neuron-php/*
packages are considered - Configuration Check: Each package's
composer.json
is checked for CLI configuration - Provider Loading: If a CLI provider is found, its
register()
method is called - Direct Registration: Any directly listed commands are registered
- Project Commands: The root project's
composer.json
is also checked
This automatic discovery means:
- No manual registration needed
- Commands available immediately after component installation
- Clean separation between components
- No conflicts between component commands
Example Implementations
MVC Component Commands
class RoutesListCommand extends Command { public function getName(): string { return 'routes:list'; } public function getDescription(): string { return 'Display all registered routes'; } public function execute(): int { $routes = $this->getRoutes(); // Your logic here $this->output->table( ['Method', 'Path', 'Controller', 'Action'], $routes ); return 0; } }
CMS Component Commands
class InitCommand extends Command { public function getName(): string { return 'cms:init'; } public function getDescription(): string { return 'Initialize CMS structure'; } public function configure(): void { $this->addOption('theme', null, true, 'Initial theme', 'default'); $this->addOption('with-sample', null, false, 'Include sample content'); } public function execute(): int { $theme = $this->input->getOption('theme'); $this->output->title('CMS Initialization'); // Create directories $this->output->info('Creating directory structure...'); // ... implementation // Install theme $this->output->info("Installing theme: {$theme}"); // ... implementation if ($this->input->getOption('with-sample')) { $this->output->info('Adding sample content...'); // ... implementation } $this->output->success('CMS initialized successfully!'); return 0; } }
Error Handling
Commands should return appropriate exit codes:
0
- Success1
- General error2
- Misuse of command126
- Command cannot execute127
- Command not found
Example:
public function execute(): int { try { // Command logic... return 0; } catch (ValidationException $e) { $this->output->error('Validation failed: ' . $e->getMessage()); return 2; } catch (\Exception $e) { $this->output->error('An error occurred: ' . $e->getMessage()); return 1; } }
Testing Your Commands
use PHPUnit\Framework\TestCase; use Neuron\Cli\Console\Input; use Neuron\Cli\Console\Output; class MakeControllerCommandTest extends TestCase { public function testExecute(): void { $command = new MakeControllerCommand(); // Mock input $input = new Input(['UserController', '--resource']); $output = new Output(false); // No colors for testing $command->setInput($input); $command->setOutput($output); $command->configure(); $input->parse($command); $exitCode = $command->execute(); $this->assertEquals(0, $exitCode); } }
Contributing
When adding new features to the CLI component:
- Extend the
Command
base class for new commands - Add tests in the
tests/
directory - Update this README with new features
- Follow PSR-4 naming conventions
- Use the existing code style (tabs, spaces etc)
License
This component is part of the Neuron PHP Framework and is released under the MIT License.