Console Commands

Keywords: CLI Command Console Symfony Cache Package User DB Config Terminal

Übersicht

CLI-Command-System basierend auf Symfony Console für Cache, Package, User, DB und Config-Management.

Methoden

rex_console_command (Abstract Base)

Methode Parameter Rückgabe Beschreibung
setPackage($package) rex_package|null $this Setzt zugehöriges Package
getPackage() - rex_package|null Liefert Package (null bei Core-Commands)
getStyle($input, $output) InputInterface, OutputInterface SymfonyStyle Symfony IO-Helper
decodeMessage($message) string string HTML→CLI (strip_tags, htmlspecialchars_decode)
configure() - void Abstract: Command konfigurieren
execute($input, $output) InputInterface, OutputInterface int Abstract: Command ausführen (0=success)

Built-in Commands

Cache Commands

Command Beschreibung Beispiel
cache:clear Löscht REDAXO Core-Cache php bin/console cache:clear

Package Commands

Command Beschreibung Beispiel
package:install <id> Installiert Package php bin/console package:install yform
package:install <id> --re-install Reinstalliert Package php bin/console package:install yform -r
package:uninstall <id> Deinstalliert Package php bin/console package:uninstall debug
package:activate <id> Aktiviert Package php bin/console package:activate cronjob
package:deactivate <id> Deaktiviert Package php bin/console package:deactivate debug
package:delete <id> Löscht Package-Dateien php bin/console package:delete old_addon
package:list Listet alle Packages php bin/console package:list
package:run-update-script <id> Führt Update-Script aus php bin/console package:run-update-script yform

User Commands

Command Beschreibung Beispiel
user:create <login> [password] Erstellt neuen User php bin/console user:create admin
user:create --admin User mit Admin-Rechten php bin/console user:create admin secret --admin
user:create --name "Name" Mit Display-Name php bin/console user:create john pwd --name "John Doe"
user:create --password-change-required Passwort-Änderung erzwingen php bin/console user:create temp pwd --password-change-required
user:set-password <login> [password] Passwort ändern php bin/console user:set-password admin
user:list Listet alle User php bin/console user:list
user:delete <login> Löscht User php bin/console user:delete old_user

DB Commands

Command Beschreibung Beispiel
db:connection-options Zeigt DB-Connection-Params php bin/console db:connection-options
db:set-connection <id> Setzt aktive DB-Connection php bin/console db:set-connection 2
db:update Führt DB-Updates aus php bin/console db:update

Config Commands

Command Beschreibung Beispiel
config:get <namespace> <key> Liest Config-Wert php bin/console config:get yform settings
config:set <namespace> <key> <value> Setzt Config-Wert php bin/console config:set myAddon api_key xyz

System Commands

Command Beschreibung Beispiel
system:report System-Report ausgeben php bin/console system:report
assets:sync Assets synchronisieren php bin/console assets:sync

Praxisbeispiele

Cache löschen

# Core-Cache löschen
php bin/console cache:clear

# Output:
# [OK] Der Cache wurde erfolgreich gelöscht!

Package installieren

# Addon installieren
php bin/console package:install yform

# Mit Re-Install-Option (ohne Nachfrage)
php bin/console package:install yform --re-install
php bin/console package:install yform -r

# Plugin installieren
php bin/console package:install yform/manager

# Mehrere Packages nacheinander
php bin/console package:install phpmailer
php bin/console package:install yform
php bin/console package:install cronjob

Package-Lifecycle

# Installieren
php bin/console package:install debug

# Aktivieren (falls deaktiviert)
php bin/console package:activate debug

# Deaktivieren
php bin/console package:deactivate debug

# Update-Script ausführen
php bin/console package:run-update-script yform

# Deinstallieren
php bin/console package:uninstall debug

# Löschen (entfernt Dateien)
php bin/console package:delete debug

Package-Liste

# Alle Packages anzeigen
php bin/console package:list

# Output:
# +-----------+--------+-----------+
# | Package   | Status | Version   |
# +-----------+--------+-----------+
# | phpmailer | active | 3.3.0     |
# | yform     | active | 4.0.0     |
# | cronjob   | active | 2.3.0     |
# +-----------+--------+-----------+

User erstellen

# Interaktiv (fragt Passwort ab)
php bin/console user:create admin

# Mit Passwort als Parameter
php bin/console user:create admin mySecretPassword

# Admin-User
php bin/console user:create admin secret --admin

# Mit Name
php bin/console user:create john pwd --name "John Doe"

# Passwort-Änderung bei Login erzwingen
php bin/console user:create temp pwd --password-change-required

# Kombination
php bin/console user:create superadmin secret --admin --name "Super Admin"

User-Management

# Alle User auflisten
php bin/console user:list

# Passwort ändern (interaktiv)
php bin/console user:set-password admin

# Passwort ändern (mit Parameter)
php bin/console user:set-password admin newPassword

# User löschen
php bin/console user:delete old_user

DB-Commands

# DB-Connection-Optionen anzeigen
php bin/console db:connection-options

# Output:
# Host: localhost
# Database: redaxo5
# User: root
# ...

# DB-Connection wechseln
php bin/console db:set-connection 2

# DB-Updates ausführen (nach REDAXO-Update)
php bin/console db:update

Config-Werte

# Config-Wert lesen
php bin/console config:get yform settings

# Config-Wert setzen
php bin/console config:set myAddon api_key xyz123

# Mehrere Werte setzen
php bin/console config:set myAddon api_key xyz123
php bin/console config:set myAddon api_secret abc456
php bin/console config:set myAddon mode production

Custom Command erstellen

// In lib/console/my_command.php

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;

class rex_command_my_custom extends rex_console_command
{
    protected function configure(): void
    {
        $this
            ->setDescription('Does something custom')
            ->addArgument('name', InputArgument::REQUIRED, 'Name parameter')
            ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force execution');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        $name = $input->getArgument('name');
        $force = $input->getOption('force');
        
        // Logik
        if (!$force && !$this->confirm('Really proceed?')) {
            $io->warning('Aborted');
            return 1;
        }
        
        // Verarbeitung
        $io->success('Successfully processed: ' . $name);
        
        return 0; // 0 = success, 1+ = error
    }
}

Command in Boot registrieren

// In boot.php eines Addons

if (rex::isConsole()) {
    rex_console::addCommand('myAddon:import', new rex_command_my_import());
    rex_console::addCommand('myAddon:export', new rex_command_my_export());
    rex_console::addCommand('myAddon:sync', new rex_command_my_sync());
}

// Verwendung
// php bin/console myAddon:import data.json
// php bin/console myAddon:export output.json

Input-Argumente & Options

class rex_command_example extends rex_console_command
{
    protected function configure(): void
    {
        $this
            ->setDescription('Example command')
            // Required Argument
            ->addArgument('file', InputArgument::REQUIRED, 'File path')
            // Optional Argument
            ->addArgument('output', InputArgument::OPTIONAL, 'Output file', 'default.txt')
            // Array Argument (mehrere Werte)
            ->addArgument('ids', InputArgument::IS_ARRAY, 'Multiple IDs')
            
            // Boolean Option (Flag)
            ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force')
            // Option mit Wert
            ->addOption('format', null, InputOption::VALUE_REQUIRED, 'Format', 'json')
            // Option mit optionalem Wert
            ->addOption('verbose', 'v', InputOption::VALUE_OPTIONAL, 'Verbose level', 1);
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        // Arguments
        $file = $input->getArgument('file');
        $outputFile = $input->getArgument('output');
        $ids = $input->getArgument('ids'); // Array
        
        // Options
        $force = $input->getOption('force'); // bool
        $format = $input->getOption('format'); // string
        $verbose = $input->getOption('verbose'); // int|null
        
        $io->success('Done');
        return 0;
    }
}

// Aufruf:
// php bin/console example input.json output.json 1 2 3 --force --format=xml -v

User-Interaktion

class rex_command_interactive extends rex_console_command
{
    protected function configure(): void
    {
        $this->setDescription('Interactive command');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        // Frage stellen
        $name = $io->ask('What is your name?', 'default');
        
        // Passwort abfragen (hidden)
        $password = $io->askHidden('Enter password');
        
        // Ja/Nein-Frage
        if ($io->confirm('Continue?', true)) {
            // ...
        }
        
        // Auswahl (Choice)
        $format = $io->choice('Select format', ['json', 'xml', 'csv'], 'json');
        
        // Ausgabe
        $io->title('My Command');
        $io->section('Processing');
        $io->text('Some text');
        $io->success('Success message');
        $io->error('Error message');
        $io->warning('Warning message');
        $io->note('Note message');
        $io->caution('Caution message');
        
        // Tabelle
        $io->table(
            ['ID', 'Name', 'Status'],
            [
                [1, 'Item 1', 'Active'],
                [2, 'Item 2', 'Inactive'],
            ]
        );
        
        // Progress Bar
        $io->progressStart(100);
        for ($i = 0; $i < 100; $i++) {
            $io->progressAdvance();
            usleep(10000);
        }
        $io->progressFinish();
        
        return 0;
    }
}

Batch-Installation (Deployment)

#!/bin/bash
# install-packages.sh

# Core-Addons
php bin/console package:install phpmailer
php bin/console package:install yform
php bin/console package:install cronjob
php bin/console package:install yrewrite

# Optional
php bin/console package:install debug
php bin/console package:install developer

# Custom
php bin/console package:install myAddon

echo "✓ All packages installed"

Error Handling

class rex_command_safe extends rex_console_command
{
    protected function configure(): void
    {
        $this->setDescription('Safe command');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        try {
            // Risikante Operation
            $this->doSomethingRisky();
            
            $io->success('Success');
            return 0;
            
        } catch (Exception $e) {
            // Fehler ausgeben
            $io->error($e->getMessage());
            
            // Optional: Stack Trace
            if ($input->getOption('verbose')) {
                $io->text($e->getTraceAsString());
            }
            
            return 1; // Error-Code
        }
    }
}

Validation

class rex_command_validate extends rex_console_command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        $file = $input->getArgument('file');
        
        // File existiert?
        if (!file_exists($file)) {
            throw new InvalidArgumentException('File not found: ' . $file);
        }
        
        // Format korrekt?
        $format = $input->getOption('format');
        if (!in_array($format, ['json', 'xml', 'csv'])) {
            throw new InvalidArgumentException('Invalid format: ' . $format);
        }
        
        $io->success('Validation passed');
        return 0;
    }
}

HTML-Messages dekodieren

class rex_command_i18n extends rex_console_command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        // rex_i18n liefert HTML (z.B. <br>)
        $message = rex_i18n::msg('my_message');
        // Output: "Line 1<br />Line 2"
        
        // Für CLI dekodieren
        $cliMessage = $this->decodeMessage($message);
        // Output: "Line 1\nLine 2"
        
        $io->text($cliMessage);
        
        return 0;
    }
}

Package-Kontext

// Command mit Package-Kontext
class myAddon_command extends rex_console_command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        // Package abrufen
        $package = $this->getPackage();
        
        if ($package) {
            $io->text('Package: ' . $package->getPackageId());
            $io->text('Version: ' . $package->getVersion());
            $io->text('Path: ' . $package->getPath());
        }
        
        return 0;
    }
}

// Registrierung mit Package
if (rex::isConsole()) {
    $addon = rex_addon::get('myAddon');
    $command = new myAddon_command();
    $command->setPackage($addon);
    rex_console::addCommand('myAddon:info', $command);
}

Cronjob via Console

# Cronjob-Skript
#!/bin/bash
# /usr/local/bin/redaxo-cronjobs.sh

cd /var/www/html

# Cache aufräumen
php bin/console cache:clear

# Custom Commands
php bin/console myAddon:cleanup
php bin/console myAddon:sync
php bin/console myAddon:backup

# Log
echo "$(date): Cronjobs executed" >> /var/log/redaxo-cron.log

Crontab-Eintrag

# Täglich um 2:00 Uhr
0 2 * * * /usr/local/bin/redaxo-cronjobs.sh

# Alle 5 Minuten
*/5 * * * * cd /var/www/html && php bin/console myAddon:sync

DB-Update in CI/CD

# .gitlab-ci.yml / .github/workflows/deploy.yml

deploy:
  script:
    - php bin/console cache:clear
    - php bin/console db:update
    - php bin/console package:run-update-script yform
    - php bin/console assets:sync

Setup-Automation

#!/bin/bash
# setup.sh - Komplettes REDAXO-Setup

# User erstellen
php bin/console user:create admin "$ADMIN_PASSWORD" --admin --name "Administrator"

# Packages installieren
php bin/console package:install phpmailer
php bin/console package:install yform
php bin/console package:install yrewrite
php bin/console package:install cronjob

# Config setzen
php bin/console config:set yrewrite url "https://example.com"
php bin/console config:set yrewrite ssl 1

# Cache löschen
php bin/console cache:clear

echo "✓ Setup complete"

Testing Commands

// In tests/console_test.php

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

class ConsoleTest extends PHPUnit\Framework\TestCase
{
    public function testCacheClear()
    {
        $application = new Application();
        $application->add(new rex_command_cache_clear());
        
        $command = $application->find('cache:clear');
        $tester = new CommandTester($command);
        $tester->execute([]);
        
        $output = $tester->getDisplay();
        $this->assertStringContainsString('erfolgreich', $output);
        $this->assertEquals(0, $tester->getStatusCode());
    }
}

Multi-Step-Command

class rex_command_multi_step extends rex_console_command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        
        $io->title('Multi-Step Process');
        
        // Step 1
        $io->section('Step 1: Validation');
        if (!$this->validate()) {
            $io->error('Validation failed');
            return 1;
        }
        $io->success('Validation passed');
        
        // Step 2
        $io->section('Step 2: Processing');
        $io->progressStart(100);
        for ($i = 0; $i < 100; $i++) {
            $this->process($i);
            $io->progressAdvance();
        }
        $io->progressFinish();
        
        // Step 3
        $io->section('Step 3: Cleanup');
        $this->cleanup();
        $io->success('Cleanup done');
        
        $io->success('All steps completed successfully');
        return 0;
    }
}

Logging in Commands

class rex_command_logged extends rex_console_command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        $logger = rex_logger::factory();
        
        $logger->info('Command started', ['command' => $this->getName()]);
        
        try {
            // Verarbeitung
            $result = $this->doSomething();
            
            $logger->info('Command completed', ['result' => $result]);
            $io->success('Done');
            return 0;
            
        } catch (Exception $e) {
            $logger->error('Command failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            $io->error($e->getMessage());
            return 1;
        }
    }
}

Silent Mode

class rex_command_silent extends rex_console_command
{
    protected function configure(): void
    {
        $this
            ->setDescription('Silent command')
            ->addOption('quiet', 'q', InputOption::VALUE_NONE, 'No output');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        $quiet = $input->getOption('quiet');
        
        // Verarbeitung
        $result = $this->process();
        
        if (!$quiet) {
            $io->success('Processed: ' . $result);
        }
        
        return 0;
    }
}

// Aufruf:
// php bin/console silent:command --quiet

Dry-Run-Modus

class rex_command_dryrun extends rex_console_command
{
    protected function configure(): void
    {
        $this
            ->setDescription('Command with dry-run')
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Simulate without changes');
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getStyle($input, $output);
        $dryRun = $input->getOption('dry-run');
        
        if ($dryRun) {
            $io->note('DRY-RUN MODE - No changes will be made');
        }
        
        $items = $this->getItems();
        
        foreach ($items as $item) {
            if ($dryRun) {
                $io->text('Would delete: ' . $item);
            } else {
                $this->delete($item);
                $io->text('Deleted: ' . $item);
            }
        }
        
        $io->success($dryRun ? 'Dry-run completed' : 'Completed');
        return 0;
    }
}