diff --git a/README.md b/README.md index 4330d6c4..4d0c0555 100644 --- a/README.md +++ b/README.md @@ -382,6 +382,8 @@ class IndexController extends Controller # display ratio list ./bin/console tbbc:money:ratio-list +./bin/console tbbc:money:ratio-list --format=table +./bin/console tbbc:money:ratio-list --format=json # fetch all the ratio for all defined currencies from an external API ./bin/console tbbc:money:ratio-fetch diff --git a/Tests/Command/RatioListCommandTest.php b/Tests/Command/RatioListCommandTest.php index 538068ff..ab7c5091 100644 --- a/Tests/Command/RatioListCommandTest.php +++ b/Tests/Command/RatioListCommandTest.php @@ -27,4 +27,39 @@ public function testCanWriteRatioList(): void $output = $tester->getDisplay(); self::assertStringContainsString('USD;1.2', $output); } + + public function testGetRatioListAsTable(): void + { + $data = ['EUR' => 1.1, 'USD' => 1.2]; + $pairManager = $this->createMock(PairManagerInterface::class); + $pairManager + ->expects($this->once()) + ->method('getRatioList') + ->willReturn($data); + + $command = new RatioListCommand($pairManager); + $tester = new CommandTester($command); + $tester->execute(['--format' => 'table']); + self::assertSame(Command::SUCCESS, $tester->getStatusCode()); + self::assertStringContainsString('EUR | 1.1', $tester->getDisplay()); + self::assertStringContainsString('USD | 1.2', $tester->getDisplay()); + } + + public function testGetRatioListAsJson(): void + { + $data = ['EUR' => 1.1, 'USD' => 1.2]; + $pairManager = $this->createMock(PairManagerInterface::class); + $pairManager + ->expects($this->once()) + ->method('getRatioList') + ->willReturn($data); + + $command = new RatioListCommand($pairManager); + $tester = new CommandTester($command); + $tester->execute(['--format' => 'json']); + self::assertSame(Command::SUCCESS, $tester->getStatusCode()); + self::assertJson($tester->getDisplay()); + $output = json_decode($tester->getDisplay(), true); + self::assertSame($data, $output); + } } diff --git a/src/Command/RatioListCommand.php b/src/Command/RatioListCommand.php index 2117e9fd..d03762a2 100644 --- a/src/Command/RatioListCommand.php +++ b/src/Command/RatioListCommand.php @@ -5,15 +5,21 @@ namespace Tbbc\MoneyBundle\Command; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; use Tbbc\MoneyBundle\Pair\PairManagerInterface; -/** - * Class RatioListCommand. - */ class RatioListCommand extends Command { + private string $format = 'txt'; + public function __construct(private PairManagerInterface $pairManager) { parent::__construct(); @@ -23,21 +29,86 @@ protected function configure(): void { $this ->setName('tbbc:money:ratio-list') + ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt') ->setHelp('The tbbc:money:ratio-list display list of registered ratio') ->setDescription('display list of registered ratio'); } - protected function execute(InputInterface $input, OutputInterface $output): int + /** + * @param array $ratioList + */ + protected function displayTxt(array $ratioList, OutputInterface $output, SymfonyStyle $io): int { - $ratioList = $this->pairManager->getRatioList(); - $output->writeln('Ratio list'); - /** - * @var float $ratio - */ + $io->writeln('Ratio list'); + foreach ($ratioList as $currencyCode => $ratio) { - $output->writeln($currencyCode.';'.(string) $ratio); + $io->writeln($currencyCode.';'.(string) $ratio); + } + + return Command::SUCCESS; + } + + /** + * @param array $ratioList + */ + protected function displayTable(array $ratioList, OutputInterface $output, SymfonyStyle $io): int + { + $table = new Table($io); + $table->setHeaderTitle('Ratio list'); + $table->setHeaders(['Currency', 'Ratio']); + + foreach ($ratioList as $currencyCode => $ratio) { + $table->addRow([$currencyCode, $ratio]); + } + + $table->render(); + + return Command::SUCCESS; + } + + /** + * @param array $ratioList + */ + protected function displayJson(array $ratioList, OutputInterface $output): int + { + $output->writeln(json_encode($ratioList, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)); + + return Command::SUCCESS; + } + + private function display(OutputInterface $output, SymfonyStyle $io): int + { + $ratioList = $this->pairManager->getRatioList(); + + return match ($this->format) { + 'txt' => $this->displayTxt($ratioList, $output, $io), + 'json' => $this->displayJson($ratioList, $output), + 'table' => $this->displayTable($ratioList, $output, $io), + default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), + }; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + /** @var string $format */ + $format = $input->getOption('format') ?? 'txt'; + $this->format = $format; + + return $this->display($output, $io); + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestOptionValuesFor('format')) { + $suggestions->suggestValues($this->getAvailableFormatOptions()); } + } - return 0; + /** @return list $values */ + private function getAvailableFormatOptions(): array + { + return ['txt', 'json', 'table']; } } diff --git a/src/Pair/PairManagerInterface.php b/src/Pair/PairManagerInterface.php index 1763a0b0..f360f8b6 100644 --- a/src/Pair/PairManagerInterface.php +++ b/src/Pair/PairManagerInterface.php @@ -48,6 +48,8 @@ public function getReferenceCurrencyCode(): string; /** * return ratio list for currencies in comparison to reference currency * array of type array("EUR" => 1, "USD" => 1.25);. + * + * @return array */ public function getRatioList(): array;