addArgument('travel-id', InputArgument::REQUIRED, 'The travel product ID to fetch') ->addOption('filename', 'f', InputOption::VALUE_REQUIRED, 'Output filename (default: Ziel_{travel-id}.xml)') ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Fetch and display info without saving'); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $travelId = (int) $input->getArgument('travel-id'); $filename = $input->getOption('filename') ?? sprintf('Ziel_%d.xml', $travelId); $dryRun = $input->getOption('dry-run'); $io->text(sprintf('Fetching travel data for product ID %d...', $travelId)); try { $xml = $this->apiClient->getTravelDataXml($travelId); } catch (ApiClientException $e) { $io->error(sprintf('API request failed: %s', $e->getMessage())); $this->logger->error('Failed to fetch travel data from API', [ 'travelId' => $travelId, 'error' => $e->getMessage(), ]); return Command::FAILURE; } $io->text(sprintf('Received %d bytes of XML data', strlen($xml))); if ($dryRun) { $io->note('Dry-run mode: not saving to file'); $io->text($xml); return Command::SUCCESS; } try { $this->xmlExport->write($filename, $xml); } catch (FilesystemException $e) { $io->error(sprintf('Failed to write file: %s', $e->getMessage())); $this->logger->error('Failed to write travel XML to file', [ 'travelId' => $travelId, 'filename' => $filename, 'error' => $e->getMessage(), ]); return Command::FAILURE; } $this->invalidateCaches(); $io->success(sprintf('Saved to %s and invalidated travel mapping cache', $filename)); $this->logger->info('Travel data fetched and saved', [ 'travelId' => $travelId, 'filename' => $filename, 'bytes' => strlen($xml), ]); return Command::SUCCESS; } private function invalidateCaches(): void { foreach (self::CACHE_KEYS_TO_INVALIDATE as $key) { $this->cache->delete($key); } } }