From a2e93e6aadc9b22c9e43d2bbc48cc6dbc9bcda28 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Thu, 13 Nov 2025 23:53:07 +0100 Subject: [PATCH] Add support for JSON in metrics commands --- src/Model/Metrics/Format.php | 8 ++++---- src/Service/Table.php | 31 ++++++++++++++++++++++++++++++- src/Util/Csv.php | 2 +- src/Util/PlainFormat.php | 2 +- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/Model/Metrics/Format.php b/src/Model/Metrics/Format.php index 476f46e7b..efa4058c6 100644 --- a/src/Model/Metrics/Format.php +++ b/src/Model/Metrics/Format.php @@ -35,10 +35,10 @@ private function formatPercent(?float $pc, bool $warn = true): string return \sprintf('%.1f%%', $pc); } - public function format(?float $value, bool $warn = true): string + public function format(?float $value, bool $warn = true): string|float|int|null { if (null === $value) { - return ''; + return null; } if (PHP_INT_MAX === (int) $value) { @@ -46,8 +46,8 @@ public function format(?float $value, bool $warn = true): string } return match ($this) { - Format::Rounded => (string) round($value), - Format::Rounded2p => (string) round($value, 2), + Format::Rounded => round($value), + Format::Rounded2p => round($value, 2), Format::Percent => $this->formatPercent($value, $warn), Format::Disk, Format::Memory => FormatterHelper::formatMemory((int) $value), }; diff --git a/src/Service/Table.php b/src/Service/Table.php index 75adb26b2..c27e6b802 100644 --- a/src/Service/Table.php +++ b/src/Service/Table.php @@ -244,6 +244,10 @@ public function render(array $rows, array $header = [], array $defaultColumns = $this->renderPlain($rows, $header); break; + case 'json': + $this->renderJson($rows, $header); + break; + case null: case 'table': $this->renderTable($rows, $header); @@ -263,7 +267,7 @@ public function render(array $rows, array $header = [], array $defaultColumns = */ public function formatIsMachineReadable(): bool { - return in_array($this->getFormat(), ['csv', 'tsv', 'plain']); + return in_array($this->getFormat(), ['csv', 'tsv', 'plain', 'json']); } /** @@ -384,6 +388,31 @@ protected function renderCsv(array $rows, array $header, string $delimiter = ',' $this->output->write((new Csv($delimiter, "\n"))->format($rows)); } + /** + * Renders JSON output. + * + * @param array|TableSeparator> $rows + * @param array $header + */ + protected function renderJson(array $rows, array $header): void + { + // Remove TableSeparator objects. + $rows = array_values(array_filter($rows, '\\is_array')); + + $data = []; + foreach ($rows as $row) { + $d = []; + + foreach ($header as $k => $h) { + $d[(string) $h] = is_scalar($row[$k]) ? $row[$k] : (string) $row[$k]; + } + + $data[] = $d; + } + + $this->output->write(json_encode(['data' => $data], JSON_THROW_ON_ERROR)); + } + /** * Render plain, line-based output. * diff --git a/src/Util/Csv.php b/src/Util/Csv.php index 864eabaf2..7c2fff0e3 100644 --- a/src/Util/Csv.php +++ b/src/Util/Csv.php @@ -57,7 +57,7 @@ private function formatRow(array $data): string * * @return string */ - protected function formatCell(string|\Stringable $cell): string + protected function formatCell(string|int|float|null|bool|\Stringable $cell): string { // Cast cell data to a string. $cell = (string) $cell; diff --git a/src/Util/PlainFormat.php b/src/Util/PlainFormat.php index 8b91b2490..d09402940 100644 --- a/src/Util/PlainFormat.php +++ b/src/Util/PlainFormat.php @@ -17,7 +17,7 @@ public function __construct() parent::__construct("\t", "\n"); } - protected function formatCell(string|\Stringable $cell): string + protected function formatCell(string|int|float|null|bool|\Stringable $cell): string { // Replace any newline or tab characters with a space. return \preg_replace('#[\r\n\t]+#', ' ', (string) $cell);