addOption( 'output', null, InputOption::VALUE_OPTIONAL, 'Output format (plain, json or json_pretty, default is plain)', $this->defaultOutputFormat ) ; } protected function writeArrayInOutputFormat(InputInterface $input, OutputInterface $output, iterable $items, string $prefix = ' - '): void { switch ($input->getOption('output')) { case self::OUTPUT_FORMAT_JSON: $items = (is_array($items) ? $items : iterator_to_array($items)); $output->writeln(json_encode($items)); break; case self::OUTPUT_FORMAT_JSON_PRETTY: $items = (is_array($items) ? $items : iterator_to_array($items)); $output->writeln(json_encode($items, JSON_PRETTY_PRINT)); break; default: foreach ($items as $key => $item) { if (is_iterable($item)) { $output->writeln($prefix . $key . ':'); $this->writeArrayInOutputFormat($input, $output, $item, ' ' . $prefix); continue; } if (!is_int($key) || get_class($this) === ListCommand::class) { $value = $this->valueToString($item); if (!is_null($value)) { $output->writeln($prefix . $key . ': ' . $value); } else { $output->writeln($prefix . $key); } } else { $output->writeln($prefix . $this->valueToString($item)); } } break; } } protected function writeTableInOutputFormat(InputInterface $input, OutputInterface $output, array $items): void { switch ($input->getOption('output')) { case self::OUTPUT_FORMAT_JSON: $output->writeln(json_encode($items)); break; case self::OUTPUT_FORMAT_JSON_PRETTY: $output->writeln(json_encode($items, JSON_PRETTY_PRINT)); break; default: $table = new Table($output); $table->setRows($items); if (!empty($items) && is_string(array_key_first(reset($items)))) { $table->setHeaders(array_keys(reset($items))); } $table->render(); break; } } /** * @param mixed $item */ protected function writeMixedInOutputFormat(InputInterface $input, OutputInterface $output, $item) { if (is_array($item)) { $this->writeArrayInOutputFormat($input, $output, $item, ''); return; } switch ($input->getOption('output')) { case self::OUTPUT_FORMAT_JSON: $output->writeln(json_encode($item)); break; case self::OUTPUT_FORMAT_JSON_PRETTY: $output->writeln(json_encode($item, JSON_PRETTY_PRINT)); break; default: $output->writeln($this->valueToString($item, false)); break; } } protected function valueToString($value, bool $returnNull = true): ?string { if ($value === false) { return 'false'; } elseif ($value === true) { return 'true'; } elseif ($value === null) { return $returnNull ? null : 'null'; } else { return $value; } } /** * Throw InterruptedException when interrupted by user * * @throws InterruptedException */ protected function abortIfInterrupted() { if ($this->php_pcntl_signal === false) { return; } pcntl_signal_dispatch(); if ($this->interrupted === true) { throw new InterruptedException('Command interrupted by user'); } } /** * Changes the status of the command to "interrupted" if ctrl-c has been pressed * * Gives a chance to the command to properly terminate what it's doing */ public function cancelOperation(): void { $this->interrupted = true; } public function run(InputInterface $input, OutputInterface $output): int { // check if the php pcntl_signal functions are accessible $this->php_pcntl_signal = function_exists('pcntl_signal'); if ($this->php_pcntl_signal) { // Collect interrupts and notify the running command pcntl_signal(SIGTERM, [$this, 'cancelOperation']); pcntl_signal(SIGINT, [$this, 'cancelOperation']); } return parent::run($input, $output); } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'output') { return ['plain', 'json', 'json_pretty']; } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { return []; } }