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 completion
Set 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.