addArgument('module', InputArgument::REQUIRED, 'Modul-Identifier (z.B. "billing")') ->addOption('keep-license', null, InputOption::VALUE_NONE, 'Lizenz behalten (nicht widerrufen)') ->addOption('keep-db-entry', null, InputOption::VALUE_NONE, 'Datenbank-Eintrag behalten (Permission-System)') ->addOption('force', 'f', InputOption::VALUE_NONE, 'Keine Bestätigung erforderlich') ; } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $moduleIdentifier = $input->getArgument('module'); $keepLicense = $input->getOption('keep-license'); $keepDbEntry = $input->getOption('keep-db-entry'); $force = $input->getOption('force'); $io->title(sprintf('Modul "%s" entfernen', $moduleIdentifier)); // 1. Modul-Informationen sammeln $modulePlugin = $this->moduleRegistry->getModule($moduleIdentifier); $moduleEntity = $this->findModuleEntity($moduleIdentifier); if (!$modulePlugin && !$moduleEntity) { $io->error(sprintf('Modul "%s" wurde nicht gefunden (weder als Plugin noch in der Datenbank).', $moduleIdentifier)); return Command::FAILURE; } // 2. Informationen anzeigen $this->displayModuleInfo($io, $modulePlugin, $moduleEntity); // 3. Bestätigung einholen if (!$force && !$io->confirm('Möchten Sie dieses Modul wirklich entfernen?', false)) { $io->info('Abgebrochen.'); return Command::SUCCESS; } $io->section('Entferne Modul'); $steps = []; // 4. Lizenz widerrufen if (!$keepLicense && $modulePlugin && $modulePlugin->isLicensed()) { $io->text('⏳ Widerrufe Lizenz...'); try { $this->licenseValidator->revokeLicense($moduleIdentifier); $io->success('✓ Lizenz erfolgreich widerrufen'); $steps[] = '✓ Lizenz widerrufen'; } catch (\Exception $e) { $io->warning(sprintf('Lizenz konnte nicht widerrufen werden: %s', $e->getMessage())); $steps[] = '⚠ Lizenz-Widerruf fehlgeschlagen'; } } elseif ($keepLicense) { $io->text('⏭ Lizenz wird behalten (--keep-license)'); $steps[] = '⏭ Lizenz behalten'; } else { $io->text('⏭ Keine Lizenz vorhanden'); $steps[] = '⏭ Keine Lizenz'; } // 5. Datenbank-Eintrag entfernen if (!$keepDbEntry && $moduleEntity) { $io->text('⏳ Entferne Datenbank-Eintrag (Permission-System)...'); // Warnung, wenn Permissions existieren $permissionCount = $moduleEntity->getPermissions()->count(); if ($permissionCount > 0) { $io->warning(sprintf( 'ACHTUNG: Dieses Modul hat %d verknüpfte Permission(s). Diese werden ebenfalls gelöscht!', $permissionCount )); if (!$force && !$io->confirm('Trotzdem fortfahren?', false)) { $io->info('Abgebrochen.'); return Command::SUCCESS; } } try { $this->entityManager->remove($moduleEntity); $this->entityManager->flush(); $io->success('✓ Datenbank-Eintrag erfolgreich entfernt'); $steps[] = '✓ Datenbank-Eintrag gelöscht'; } catch (\Exception $e) { $io->error(sprintf('Datenbank-Eintrag konnte nicht entfernt werden: %s', $e->getMessage())); $steps[] = '✗ Datenbank-Eintrag Fehler'; return Command::FAILURE; } } elseif ($keepDbEntry) { $io->text('⏭ Datenbank-Eintrag wird behalten (--keep-db-entry)'); $steps[] = '⏭ DB-Eintrag behalten'; } else { $io->text('⏭ Kein Datenbank-Eintrag vorhanden'); $steps[] = '⏭ Kein DB-Eintrag'; } // 6. Nächste Schritte anzeigen $io->section('Zusammenfassung'); $io->listing($steps); $io->section('Nächste Schritte (manuell)'); $nextSteps = []; // Composer-Package entfernen if ($modulePlugin) { $packageName = $this->guessPackageName($moduleIdentifier); $nextSteps[] = sprintf('1. Composer-Package entfernen: composer remove %s', $packageName); } // Bundle aus config/bundles.php entfernen $nextSteps[] = '2. Bundle aus config/bundles.php entfernen (falls vorhanden)'; // Migrationen $nextSteps[] = '3. Optional: Migrationen zurückrollen (falls benötigt)'; $nextSteps[] = ' php bin/console doctrine:migrations:migrate prev'; // Cache leeren $nextSteps[] = '4. Cache leeren: php bin/console cache:clear'; $io->listing($nextSteps); $io->success(sprintf('Modul "%s" wurde vorbereitet zum Entfernen. Führen Sie die obigen Schritte manuell aus.', $moduleIdentifier)); return Command::SUCCESS; } private function displayModuleInfo(SymfonyStyle $io, $modulePlugin, ?Module $moduleEntity): void { $io->section('Modul-Informationen'); $rows = []; if ($modulePlugin) { $rows[] = ['Plugin-Informationen', '']; $rows[] = [' Name', $modulePlugin->getDisplayName()]; $rows[] = [' Version', $modulePlugin->getVersion()]; $rows[] = [' Beschreibung', $modulePlugin->getDescription()]; $rows[] = [' Lizenziert', $modulePlugin->isLicensed() ? '✓ Ja' : '✗ Nein']; $rows[] = [' Aktiv', $this->moduleRegistry->isModuleActive($modulePlugin->getIdentifier()) ? '✓ Ja' : '✗ Nein']; } if ($moduleEntity) { if (!empty($rows)) { $rows[] = ['', '']; } $rows[] = ['Datenbank-Informationen (Permission-System)', '']; $rows[] = [' Name', $moduleEntity->getName()]; $rows[] = [' Code', $moduleEntity->getCode()]; $rows[] = [' Aktiv', $moduleEntity->isActive() ? '✓ Ja' : '✗ Nein']; $rows[] = [' Permissions', (string)$moduleEntity->getPermissions()->count()]; } $io->table(['Eigenschaft', 'Wert'], $rows); } private function findModuleEntity(string $identifier): ?Module { return $this->entityManager ->getRepository(Module::class) ->findOneBy(['code' => $identifier]); } private function guessPackageName(string $identifier): string { // Versuche Package-Name zu erraten (z.B. billing -> mycrm/billing-module) return sprintf('mycrm/%s-module', $identifier); } }