Command-line interface, console commands, argument parsing, and interactive prompts. The CLI system provides a powerful foundation for building command-line tools, background tasks, and interactive console applications.
Main console application class that manages commands, handles input/output, and provides a fluent interface for building CLI applications. The Console class serves as the entry point for all command-line operations.
Create and configure a console application.
use Forge\Console\Console;
use Forge\Console\Input\Input;
use Forge\Console\Output\Output;
// Create console application
$console = new Console('Forge Engine CLI', '1.0.0');
// Set application description
$console->setDescription('Command-line interface for Forge Engine applications');
// Configure global options
$console->setGlobalOptions([
    ['help', 'h', InputOption::VALUE_NONE, 'Display help for the given command'],
    ['quiet', 'q', InputOption::VALUE_NONE, 'Do not output any message'],
    ['verbose', 'v', InputOption::VALUE_NONE, 'Increase the verbosity of messages'],
    ['version', 'V', InputOption::VALUE_NONE, 'Display this application version'],
    ['ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'],
    ['no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'],
    ['no-interaction', 'n', InputOption::VALUE_NONE, 'Do not ask any interactive question']
]);
// Set default command
$console->setDefaultCommand('list');
// Run the application
$console->run();Register commands with the console application.
// Add a single command
$console->add(new GreetCommand());
// Add multiple commands
$console->addCommands([
    new GreetCommand(),
    new DatabaseMigrateCommand(),
    new CacheClearCommand(),
    new ServeCommand()
]);
// Add command using class name
$console->addCommand('app:serve', ServeCommand::class);
// Add command with configuration
$console->addCommand('cache:clear', [
    'class' => CacheClearCommand::class,
    'description' => 'Clear the application cache',
    'help' => 'This command clears all cached data from the application'
]);
// Add anonymous command
$console->addCommand('test:connection', function(Input $input, Output $output) {
    $output->writeln('Testing database connection... ');
    
    try {
        $db = Container::getInstance()->make('db');
        $db->ping();
        $output->writeln('Database connection successful! ');
        return 0;
    } catch (\Exception $e) {
        $output->writeln('Database connection failed: ' . $e->getMessage() . ' ');
        return 1;
    }
});Set whether to automatically exit after running a command.
// Don't auto-exit (useful for testing)
$console->setAutoExit(false);
// Run command and capture output
$exitCode = $console->run($input, $output);
// Process results
if ($exitCode === 0) {
    echo "Command executed successfully\n";
} else {
    echo "Command failed with exit code: {$exitCode}\n";
}
// Auto-exit (default behavior)
$console->setAutoExit(true);
$console->run(); // Will exit after completionSet whether to catch exceptions during command execution.
// Catch and display exceptions nicely
$console->setCatchExceptions(true);
// Don't catch exceptions (for debugging)
$console->setCatchExceptions(false);
// Custom exception handling
$console->setExceptionHandler(function(\Exception $e, Output $output) {
    $output->writeln('An error occurred: ');
    $output->writeln('' . $e->getMessage() . ' ');
    $output->writeln('');
    $output->writeln('Stack trace: ');
    $output->writeln($e->getTraceAsString());
    
    return 1;
});Base class for all console commands providing argument parsing, input validation, and execution logic. Commands are the building blocks of CLI applications, each handling a specific task or operation.
Create a custom command by extending the base Command class.
namespace App\Console\Commands;
use Forge\Console\Command;
use Forge\Console\Input\InputArgument;
use Forge\Console\Input\InputOption;
use Forge\Console\Input\InputInterface;
use Forge\Console\Output\OutputInterface;
class GreetCommand extends Command
{
    protected static $defaultName = 'app:greet';
    protected static $defaultDescription = 'Greet a user';
    
    protected function configure(): void
    {
        $this
            ->setName('app:greet')
            ->setDescription('Greet a user')
            ->setHelp('This command greets a user with a customizable message')
            ->addArgument(
                'name',
                InputArgument::REQUIRED,
                'The name of the user to greet'
            )
            ->addOption(
                'greeting',
                'g',
                InputOption::VALUE_OPTIONAL,
                'Custom greeting message',
                'Hello'
            )
            ->addOption(
                'uppercase',
                'u',
                InputOption::VALUE_NONE,
                'Convert greeting to uppercase'
            );
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $name = $input->getArgument('name');
        $greeting = $input->getOption('greeting');
        $uppercase = $input->getOption('uppercase');
        
        $message = "{$greeting}, {$name}!";
        
        if ($uppercase) {
            $message = strtoupper($message);
        }
        
        $output->writeln('' . $message . ' ');
        
        return Command::SUCCESS;
    }
}Define and use command arguments.
class DatabaseBackupCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('db:backup')
            ->setDescription('Backup the database')
            ->addArgument(
                'database',
                InputArgument::OPTIONAL,
                'Database name to backup',
                'default'
            )
            ->addArgument(
                'filename',
                InputArgument::OPTIONAL,
                'Backup filename',
                null
            )
            ->addArgument(
                'tables',
                InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
                'Specific tables to backup'
            );
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $database = $input->getArgument('database');
        $filename = $input->getArgument('filename');
        $tables = $input->getArgument('tables');
        
        // Generate filename if not provided
        if (!$filename) {
            $filename = sprintf(
                '%s_%s.sql',
                $database,
                date('Y-m-d_H-i-s')
            );
        }
        
        $output->writeln("Backing up database: {$database} ");
        
        if (!empty($tables)) {
            $output->writeln("Tables: " . implode(', ', $tables) . " ");
        }
        
        $output->writeln("Backup file: {$filename} ");
        
        // Perform backup logic here
        
        return Command::SUCCESS;
    }
}Define and use command options.
class UserCreateCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('user:create')
            ->setDescription('Create a new user')
            ->addArgument('email', InputArgument::REQUIRED, 'User email address')
            ->addArgument('password', InputArgument::OPTIONAL, 'User password')
            ->addOption('name', null, InputOption::VALUE_REQUIRED, 'User full name')
            ->addOption('role', null, InputOption::VALUE_REQUIRED, 'User role', 'user')
            ->addOption('verified', null, InputOption::VALUE_NONE, 'Mark email as verified')
            ->addOption('send-email', null, InputOption::VALUE_NONE, 'Send welcome email')
            ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force creation if user exists');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $email = $input->getArgument('email');
        $password = $input->getArgument('password');
        
        // Generate password if not provided
        if (!$password) {
            $password = $this->generatePassword();
            $output->writeln("Generated password: {$password} ");
        }
        
        $name = $input->getOption('name');
        $role = $input->getOption('role');
        $verified = $input->getOption('verified');
        $sendEmail = $input->getOption('send-email');
        $force = $input->getOption('force');
        
        // Check if user exists
        if ($this->userExists($email) && !$force) {
            $output->writeln("User with email {$email} already exists! ");
            $output->writeln("Use --force to override ");
            return Command::FAILURE;
        }
        
        // Create user
        $user = $this->createUser([
            'email' => $email,
            'password' => $password,
            'name' => $name,
            'role' => $role,
            'verified' => $verified
        ]);
        
        $output->writeln("User created successfully! ");
        $output->writeln("Email: {$user->email}");
        $output->writeln("Role: {$user->role}");
        
        if ($sendEmail) {
            $this->sendWelcomeEmail($user);
            $output->writeln("Welcome email sent! ");
        }
        
        return Command::SUCCESS;
    }
    
    private function generatePassword(): string
    {
        return bin2hex(random_bytes(8));
    }
}Create interactive commands with user prompts.
use Forge\Console\Style\SymfonyStyle;
use Forge\Console\Question\ConfirmationQuestion;
use Forge\Console\Question\Question;
use Forge\Console\Question\ChoiceQuestion;
class SetupCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('app:setup')
            ->setDescription('Interactive application setup');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        $io->title('Application Setup');
        $io->text('This wizard will help you configure your application.');
        $io->newLine();
        
        // Ask for application name
        $appName = $io->ask('Application name', 'My Application');
        
        // Ask for environment
        $environment = $io->choice(
            'Select environment',
            ['development', 'staging', 'production'],
            'development'
        );
        
        // Ask for database configuration
        $io->section('Database Configuration');
        
        $dbHost = $io->ask('Database host', 'localhost');
        $dbPort = $io->ask('Database port', '3306');
        $dbName = $io->ask('Database name', 'forge_app');
        $dbUser = $io->ask('Database username', 'root');
        $dbPass = $io->askHidden('Database password');
        
        // Confirm configuration
        $io->section('Configuration Summary');
        $io->table(
            ['Setting', 'Value'],
            [
                ['Application Name', $appName],
                ['Environment', $environment],
                ['Database Host', $dbHost],
                ['Database Port', $dbPort],
                ['Database Name', $dbName],
                ['Database User', $dbUser],
                ['Database Password', str_repeat('*', strlen($dbPass))]
            ]
        );
        
        if (!$io->confirm('Do you want to proceed with this configuration?', true)) {
            $io->warning('Setup cancelled.');
            return Command::FAILURE;
        }
        
        // Perform setup
        $io->section('Setting up application...');
        
        $progressBar = $io->createProgressBar(100);
        $progressBar->start();
        
        // Step 1: Create configuration files
        $this->createConfigFiles([
            'app_name' => $appName,
            'environment' => $environment,
            'database' => [
                'host' => $dbHost,
                'port' => $dbPort,
                'name' => $dbName,
                'user' => $dbUser,
                'password' => $dbPass
            ]
        ]);
        
        $progressBar->advance(25);
        
        // Step 2: Run migrations
        $this->runMigrations();
        $progressBar->advance(25);
        
        // Step 3: Seed database
        $this->seedDatabase();
        $progressBar->advance(25);
        
        // Step 4: Clear caches
        $this->clearCaches();
        $progressBar->advance(25);
        
        $progressBar->finish();
        $io->newLine(2);
        
        $io->success('Application setup completed successfully!');
        
        return Command::SUCCESS;
    }
}Handle user input and console output with formatting, colors, and interactive elements. The Input and Output classes provide a rich interface for reading user input and displaying formatted output.
Access command arguments and options.
class TestCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('test:input')
            ->setDescription('Test input handling')
            ->addArgument('name', InputArgument::REQUIRED, 'Your name')
            ->addArgument('emails', InputArgument::IS_ARRAY, 'Email addresses')
            ->addOption('verbose', 'v', InputOption::VALUE_NONE, 'Verbose output')
            ->addOption('format', 'f', InputOption::VALUE_REQUIRED, 'Output format', 'text')
            ->addOption('count', 'c', InputOption::VALUE_OPTIONAL, 'Number of iterations', 1);
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Get arguments
        $name = $input->getArgument('name');
        $emails = $input->getArgument('emails');
        
        // Get options
        $verbose = $input->getOption('verbose');
        $format = $input->getOption('format');
        $count = $input->getOption('count');
        
        // Check if option is set
        if ($input->hasOption('verbose')) {
            $output->writeln("Verbose mode enabled");
        }
        
        // Get all arguments
        $arguments = $input->getArguments();
        foreach ($arguments as $name => $value) {
            if (is_array($value)) {
                $output->writeln("{$name}: " . implode(', ', $value));
            } else {
                $output->writeln("{$name}: {$value}");
            }
        }
        
        // Get all options
        $options = $input->getOptions();
        foreach ($options as $name => $value) {
            if ($value !== false && $value !== null) {
                $output->writeln("Option {$name}: {$value}");
            }
        }
        
        // Interactive input
        if ($input->isInteractive()) {
            $helper = $this->getHelper('question');
            
            $question = new Question('Please enter your age: ');
            $age = $helper->ask($input, $output, $question);
            
            $output->writeln("Your age is: {$age}");
        }
        
        return Command::SUCCESS;
    }
}Format console output with colors and styles.
class StyledOutputCommand extends Command
{
    protected function configure(): void
    {
        $this->setName('demo:styles')->setDescription('Demonstrate output styles');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Basic styles
        $output->writeln('This is info text (green) ');
        $output->writeln('This is comment text (yellow) ');
        $output->writeln('This is question text (cyan) ');
        $output->writeln('This is error text (red) ');
        
        // Custom colors
        $output->writeln('This is red text>');
        $output->writeln('This is green text>');
        $output->writeln('This is blue text>');
        $output->writeln('This is magenta text>');
        
        // Background colors
        $output->writeln('White text on red background>');
        $output->writeln('Black text on green background>');
        $output->writeln('White text on blue background>');
        
        // Text formatting
        $output->writeln('Bold text ');
        $output->writeln('Underlined text ');
        $output->writeln('Blinking text ');
        $output->writeln('Reversed text ');
        
        // Combined styles
        $output->writeln('Bold red text>');
        $output->writeln('Underlined white on blue>');
        
        // Multiple lines
        $output->writeln([
            'Line 1 ',
            'Line 2 ',
            'Line 3 '
        ]);
        
        // Without newlines
        $output->write('Processing... ');
        sleep(1);
        $output->writeln('Done! ');
        
        // Verbose output
        if ($output->isVerbose()) {
            $output->writeln('Verbose information ');
        }
        
        if ($output->isVeryVerbose()) {
            $output->writeln('Very verbose information ');
        }
        
        if ($output->isDebug()) {
            $output->writeln('Debug information ');
        }
        
        return Command::SUCCESS;
    }
}         Display progress bars for long-running operations.
class ProgressCommand extends Command
{
    protected function configure(): void
    {
        $this->setName('demo:progress')->setDescription('Demonstrate progress bars');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Create progress bar
        $progressBar = new ProgressBar($output, 100);
        
        // Customize progress bar
        $progressBar->setFormat('debug');
        $progressBar->setBarCharacter('█ ');
        $progressBar->setEmptyBarCharacter('░');
        $progressBar->setProgressCharacter('➤');
        $progressBar->setBarWidth(50);
        
        // Start progress bar
        $progressBar->start();
        
        // Simulate work
        for ($i = 0; $i < 100; $i++) {
            usleep(20000); // 20ms
            $progressBar->advance();
        }
        
        // Finish progress bar
        $progressBar->finish();
        $output->writeln('');
        
        // Custom progress bar format
        $progressBar = new ProgressBar($output, 50);
        $progressBar->setFormat('Processing: %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');
        
        $progressBar->start();
        for ($i = 0; $i < 50; $i++) {
            usleep(40000);
            $progressBar->advance();
        }
        $progressBar->finish();
        $output->writeln('');
        
        // Progress bar with messages
        $progressBar = new ProgressBar($output, 10);
        $progressBar->setFormat("%message%\n%current%/%max% [%bar%] %percent:3s%%");
        
        $progressBar->start();
        for ($i = 0; $i < 10; $i++) {
            $progressBar->setMessage("Processing item {$i}");
            $progressBar->advance();
            usleep(100000);
        }
        $progressBar->finish();
        
        return Command::SUCCESS;
    }
}Display data in formatted tables and lists. The Console component provides helpers for creating nicely formatted tables and lists from your data.
Display data in formatted tables.
use Forge\Console\Helper\Table;
class TableCommand extends Command
{
    protected function configure(): void
    {
        $this->setName('demo:table')->setDescription('Demonstrate table display');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Simple table
        $table = new Table($output);
        $table->setHeaders(['ID', 'Name', 'Email', 'Status']);
        $table->setRows([
            [1, 'John Doe', 'john@example.com', 'Active '],
            [2, 'Jane Smith', 'jane@example.com', 'Active '],
            [3, 'Bob Johnson', 'bob@example.com', 'Pending '],
            [4, 'Alice Brown', 'alice@example.com', 'Inactive ']
        ]);
        $table->render();
        
        // Table with style
        $table = new Table($output);
        $table->setStyle('borderless');
        $table->setHeaders(['Feature', 'Status', 'Description']);
        $table->setRows([
            ['Database', '✓ ', 'MySQL 8.0 configured'],
            ['Cache', '✓ ', 'Redis cache enabled'],
            ['Queue', '⚠', 'Queue not configured'],
            ['Mail', '✗ ', 'Mail driver not set']
        ]);
        $table->render();
        
        // Complex table with alignment
        $table = new Table($output);
        $table->setHeaders(['Module', 'Version', 'Status', 'Dependencies']);
        $table->setRows([
            ['Auth', '1.2.0', 'Enabled ', 'Database, Cache'],
            ['Blog', '2.1.0', 'Enabled ', 'Auth, Media'],
            ['Media', '1.0.0', 'Disabled ', 'Storage'],
            ['Analytics', '1.5.0', 'Enabled ', 'Database']
        ]);
        
        // Set column styles
        $table->setColumnStyle(0, ['align' => 'left']);
        $table->setColumnStyle(1, ['align' => 'center']);
        $table->setColumnStyle(2, ['align' => 'center']);
        $table->setColumnStyle(3, ['align' => 'left']);
        
        $table->render();
        
        // Table from data source
        $users = $this->getUsers(); // Assume this returns user data
        
        $table = new Table($output);
        $table->setHeaders(['ID', 'Name', 'Email', 'Created', 'Last Login']);
        
        foreach ($users as $user) {
            $table->addRow([
                $user->id,
                $user->name,
                $user->email,
                $user->created_at->format('Y-m-d'),
                $user->last_login ? $user->last_login->diffForHumans() : 'Never'
            ]);
        }
        
        $table->render();
        
        return Command::SUCCESS;
    }
} Display data in formatted lists.
use Forge\Console\Helper\DescriptorHelper;
class ListCommand extends Command
{
    protected function configure(): void
    {
        $this->setName('demo:list')->setDescription('Demonstrate list display');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        // Simple list
        $io->listing([
            'Install dependencies',
            'Configure environment',
            'Run migrations',
            'Seed database',
            'Start application'
        ]);
        
        // Definition list
        $io->definitionList(
            ['Application' => 'Forge Engine'],
            ['Version' => '1.0.0'],
            ['Environment' => 'production'],
            ['Debug Mode' => 'disabled'],
            ['Cache Driver' => 'redis'],
            ['Database' => 'MySQL 8.0']
        );
        
        // Section with items
        $io->section('Available Commands');
        $io->listing([
            'cache:clear - Clear application cache',
            'db:migrate - Run database migrations',
            'user:create - Create a new user',
            'serve - Start development server'
        ]);
        
        // Nested sections
        $io->section('System Status');
        $io->text('Checking system requirements...');
        
        $io->section('PHP Extensions');
        $io->listing([
            '✓  PDO',
            '✓  Mbstring',
            '✓  OpenSSL',
            '⚠  Redis (optional)'
        ]);
        
        $io->section('Directory Permissions');
        $io->listing([
            '✓  storage/ - Writable',
            '✓  bootstrap/cache/ - Writable',
            '✓  public/uploads/ - Writable'
        ]);
        
        // Custom list with icons
        $io->section('Module Status');
        $modules = [
            'Auth' => '✓ Enabled ',
            'Blog' => '✓ Enabled ',
            'Media' => '⚠ Disabled ',
            'Analytics' => '✓ Enabled '
        ];
        
        foreach ($modules as $name => $status) {
            $io->writeln("  {$name}: {$status}");
        }
        
        return Command::SUCCESS;
    }
}Common patterns and examples for working with the CLI & Console system.
// Database migration command
class MigrateCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('db:migrate')
            ->setDescription('Run database migrations')
            ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force migration in production')
            ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Path to migration files')
            ->addOption('seed', null, InputOption::VALUE_NONE, 'Seed database after migration')
            ->addOption('fresh', null, InputOption::VALUE_NONE, 'Drop all tables and re-migrate');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        $force = $input->getOption('force');
        $path = $input->getOption('path') ?? 'database/migrations';
        $seed = $input->getOption('seed');
        $fresh = $input->getOption('fresh');
        
        // Check environment
        if (Container::getInstance()->make('app')->environment('production') && !$force) {
            $io->error('Migration in production requires --force option');
            return Command::FAILURE;
        }
        
        $io->title('Database Migration');
        
        if ($fresh) {
            $io->warning('This will drop all tables and re-create them');
            if (!$io->confirm('Are you sure you want to continue?', false)) {
                return Command::FAILURE;
            }
            
            $io->text('Dropping all tables...');
            $this->dropAllTables();
        }
        
        // Get migration files
        $migrations = $this->getMigrationFiles($path);
        
        if (empty($migrations)) {
            $io->info('No migrations found');
            return Command::SUCCESS;
        }
        
        $io->text(sprintf('Found %d migration(s)', count($migrations)));
        
        $progressBar = $io->createProgressBar(count($migrations));
        $progressBar->start();
        
        $executed = 0;
        foreach ($migrations as $migration) {
            try {
                $this->runMigration($migration);
                $executed++;
                $progressBar->advance();
            } catch (\Exception $e) {
                $progressBar->clear();
                $io->error("Migration failed: " . $e->getMessage());
                return Command::FAILURE;
            }
        }
        
        $progressBar->finish();
        $io->newLine();
        
        $io->success(sprintf('Executed %d migration(s)', $executed));
        
        if ($seed) {
            $io->section('Seeding Database');
            $this->seedDatabase();
            $io->success('Database seeded successfully');
        }
        
        return Command::SUCCESS;
    }
}
// Database backup command
class BackupCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('db:backup')
            ->setDescription('Backup the database')
            ->addArgument('filename', InputArgument::OPTIONAL, 'Backup filename')
            ->addOption('compress', 'c', InputOption::VALUE_NONE, 'Compress backup file')
            ->addOption('tables', 't', InputOption::VALUE_REQUIRED, 'Specific tables to backup')
            ->addOption('exclude', 'e', InputOption::VALUE_REQUIRED, 'Tables to exclude from backup');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        $filename = $input->getArgument('filename');
        $compress = $input->getOption('compress');
        $tables = $input->getOption('tables');
        $exclude = $input->getOption('exclude');
        
        // Generate filename if not provided
        if (!$filename) {
            $filename = sprintf('backup_%s.sql', date('Y-m-d_H-i-s'));
        }
        
        $io->title('Database Backup');
        
        // Parse table lists
        $includeTables = $tables ? explode(',', $tables) : [];
        $excludeTables = $exclude ? explode(',', $exclude) : [];
        
        // Get database configuration
        $config = config('database');
        $io->text(sprintf('Backing up database: %s', $config['database']));
        
        if (!empty($includeTables)) {
            $io->text(sprintf('Including tables: %s', implode(', ', $includeTables)));
        }
        
        if (!empty($excludeTables)) {
            $io->text(sprintf('Excluding tables: %s', implode(', ', $excludeTables)));
        }
        
        // Perform backup
        try {
            $backupPath = $this->performBackup($filename, $includeTables, $excludeTables);
            
            if ($compress) {
                $io->text('Compressing backup...');
                $backupPath = $this->compressFile($backupPath);
            }
            
            $fileSize = $this->formatBytes(filesize($backupPath));
            $io->success(sprintf('Backup completed: %s (%s)', basename($backupPath), $fileSize));
            
        } catch (\Exception $e) {
            $io->error('Backup failed: ' . $e->getMessage());
            return Command::FAILURE;
        }
        
        return Command::SUCCESS;
    }
    
    private function formatBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $i = 0;
        
        while ($bytes >= 1024 && $i < count($units) - 1) {
            $bytes /= 1024;
            $i++;
        }
        
        return round($bytes, 2) . ' ' . $units[$i];
    }
}// Maintenance mode command
class MaintenanceCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('down')
            ->setDescription('Put the application into maintenance mode')
            ->addOption('message', 'm', InputOption::VALUE_REQUIRED, 'Maintenance message')
            ->addOption('retry', 'r', InputOption::VALUE_REQUIRED, 'Retry after seconds', 60)
            ->addOption('allow', null, InputOption::VALUE_REQUIRED, 'Allowed IP addresses');
        
        $this->addSubcommand('up', new UpCommand());
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        $message = $input->getOption('message') ?? 'Application is under maintenance';
        $retry = $input->getOption('retry');
        $allow = $input->getOption('allow');
        
        $io->title('Maintenance Mode');
        
        // Create maintenance file
        $maintenanceData = [
            'time' => time(),
            'message' => $message,
            'retry' => $retry,
            'allowed' => $allow ? explode(',', $allow) : []
        ];
        
        file_put_contents(
            storage_path('framework/maintenance.php'),
            'warning('Application is now in maintenance mode');
        $io->text("Message: {$message}");
        $io->text("Retry after: {$retry} seconds");
        
        if ($allow) {
            $io->text("Allowed IPs: {$allow}");
        }
        
        return Command::SUCCESS;
    }
}
class UpCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('up')
            ->setDescription('Bring the application out of maintenance mode');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        $maintenanceFile = storage_path('framework/maintenance.php');
        
        if (!file_exists($maintenanceFile)) {
            $io->info('Application is not in maintenance mode');
            return Command::SUCCESS;
        }
        
        unlink($maintenanceFile);
        
        $io->success('Application is now live!');
        
        return Command::SUCCESS;
    }
}
// Cache management command
class CacheCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->setName('cache:clear')
            ->setDescription('Clear application cache')
            ->addOption('tags', 't', InputOption::VALUE_REQUIRED, 'Specific cache tags to clear')
            ->addOption('stores', 's', InputOption::VALUE_REQUIRED, 'Specific cache stores to clear');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        
        $tags = $input->getOption('tags');
        $stores = $input->getOption('stores');
        
        $io->title('Clearing Application Cache');
        
        $storesToClear = $stores ? explode(',', $stores) : ['default'];
        $tagsToClear = $tags ? explode(',', $tags) : [];
        
        $progressBar = $io->createProgressBar(count($storesToClear));
        $progressBar->start();
        
        foreach ($storesToClear as $store) {
            try {
                if (!empty($tagsToClear)) {
                    // Clear specific tags
                    foreach ($tagsToClear as $tag) {
                        cache()->store($store)->tags([$tag])->flush();
                    }
                } else {
                    // Clear entire store
                    cache()->store($store)->flush();
                }
                
                $progressBar->advance();
            } catch (\Exception $e) {
                $progressBar->clear();
                $io->error("Failed to clear cache store {$store}: " . $e->getMessage());
                return Command::FAILURE;
            }
        }
        
        $progressBar->finish();
        $io->newLine();
        
        $io->success('Cache cleared successfully!');
        
        return Command::SUCCESS;
    }
}Recommended patterns and guidelines for working with the CLI & Console system.