Skip to content

feat: split the CLI output into Output, Terminal, ProgressBar, Table and Color - #10628

Open
paulbalandan wants to merge 1 commit into
codeigniter4:4.8from
paulbalandan:cli-output-object
Open

paulbalandan wants to merge 1 commit into
codeigniter4:4.8from
paulbalandan:cli-output-object

Conversation

@paulbalandan

Copy link
Copy Markdown
Member

Description
The static CLI class mixes five jobs: writing to streams, colouring text, laying out tables, drawing a progress bar, and probing the terminal. Its state is process-global, so a command cannot own its output, callSilently() swaps that state by hand, and the planned verbosity levels would add more statics.

This PR moves each job into an instance class and turns CLI into a facade that delegates to them. Every CLI::write() keeps working, and the output is byte-identical apart from the behaviour changes listed below.

  • Output is the writer: print(), write(), error(), newLine(), beep(), clearScreen(), color(). It targets STDOUT, sends error() to STDERR, detects colour support per stream, and tracks whether the cursor sits at the start of a line. forStderr() returns a copy whose STDOUT writes go to STDERR.
  • Terminal holds the dimensions (read once per instance) and the hasColorSupport()/streamSupports() probes.
  • ProgressBar draws the ten-cell bar and rejects a negative step or a total below one. Table renders the bordered table as a string. Color applies and strips ANSI codes.
  • CLI::getOutput() and CLI::getTerminal() return the shared instances, and CLI::setOutput() replaces the writer. The facade keeps every released signature and normalises its inputs (?string colours, showProgress(false), negative or zero progress values) before delegating. The output-related protected statics stay declared, deprecated and unused.
  • Modern commands reach the writer through $this->getOutput(). AbstractCommand::run() and Commands::runCommand() accept an Output, which Console passes down, sub-commands inherit, and callSilently() replaces with one backed by NullInputOutput. The facade is swapped for the duration of the run and restored afterwards, so legacy writers see the same instance.

Behaviour changes, documented in the changelog and the upgrade guide:

  • CLI::beep() goes through the InputOutput transport instead of echo.
  • CLI::print() of text ending in a line feed, or a progress bar, no longer causes a blank line before the next CLI::write().
  • CLI::error() no longer leaves colour support disabled after an invalid colour name, and an empty foreground with a background no longer throws.
  • CLI::showProgress() past the total draws a full bar instead of throwing a ValueError.
  • A subclass of CLI overriding fwrite() or color(), or reading the deprecated statics, no longer affects the output.

The framework commands keep using the CLI facade. Migrating them to $this->getOutput(), moving the prompts out of CLI, and modernising the colour detection are follow-up PRs.

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication)
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@carson-codeigniter4 carson-codeigniter4 Bot added the 4.8 PRs that target the `4.8` branch. label Oct 13, 2026
@paulbalandan
paulbalandan requested a balanced review from Copilot October 13, 2026 08:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

ANSI handling, table compatibility, test-state cleanup, static-analysis suppressions, and extension compatibility need resolution.

6 open findings
What changed in this PR

Splits CLI output responsibilities into injectable instance classes while retaining the static facade. Reviewed under the inferred 4.8 minor-branch policy.

Changes:

  • Adds Output, Terminal, ProgressBar, Table, and Color.
  • Propagates output instances through modern commands and silent child calls.
  • Adds tests, documentation, upgrade notes, and changelog entries.

Validation: Reviewed all diffs and performed a focused WeakMap retention check; project test suites remain for CI.

File Description
utils/​phpstan-baseline/​loader.neon Updates baseline count.
utils/​phpstan-baseline/​arguments.count.neon Adds Output test suppressions.
user_guide_src/​source/​testing/​cli/​002.php Demonstrates output-backed testing.
user_guide_src/​source/​testing/​cli.rst Documents modern command testing.
user_guide_src/​source/​installation/​upgrade_480.rst Adds migration guidance.
user_guide_src/​source/​cli/​cli_modern_commands/​018.php Demonstrates modern output usage.
user_guide_src/​source/​cli/​cli_modern_commands.rst Documents command output APIs.
user_guide_src/​source/​cli/​cli_library/​024.php Demonstrates new CLI classes.
user_guide_src/​source/​cli/​cli_library.rst Documents facade components.
user_guide_src/​source/​changelogs/​v4.8.0.rst Records API and behavior changes.
tests/​system/​Test/​TestCaseTest.php Updates CLI state reset.
tests/​system/​CLI/​TerminalTest.php Tests terminal detection.
tests/​system/​CLI/​TableTest.php Tests table rendering.
tests/​system/​CLI/​ProgressBarTest.php Tests progress behavior.
tests/​system/​CLI/​OutputTest.php Tests output transport and state.
tests/​system/​CLI/​NullInputOutputTest.php Updates transport restoration.
tests/​system/​CLI/​CommandsTest.php Tests output propagation and events.
tests/​system/​CLI/​ColorTest.php Tests ANSI handling.
tests/​system/​CLI/​CLITest.php Updates facade coverage.
tests/​system/​CLI/​AbstractCommandTest.php Tests command output lifecycle.
tests/​_support/​Commands/​Modern/​SilentCallCommand.php Adds silent-call fixture.
tests/​_support/​Commands/​Modern/​OutputProbeCommand.php Adds output-routing fixture.
tests/​_support/​Commands/​Modern/​CallsAboutCommand.php Adds nested-command fixture.
tests/​_support/​CLI/​RecordingInputOutput.php Adds stream-recording transport.
system/​CLI/​Terminal.php Encapsulates terminal capabilities.
system/​CLI/​Table.php Extracts table rendering.
system/​CLI/​ProgressBar.php Extracts progress rendering.
system/​CLI/​Output.php Adds instance output writer.
system/​CLI/​InputOutput.php Clarifies supported handles.
system/​CLI/​Console.php Passes shared output to commands.
system/​CLI/​Commands.php Routes output through command execution.
system/​CLI/​Color.php Extracts ANSI operations.
system/​CLI/​CLI.php Converts CLI into a facade.
system/​CLI/​AbstractCommand.php Adds per-run output access.
rector.php Excludes mock-only is_cli() calls.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread system/CLI/AbstractCommand.php
Comment thread system/CLI/CLI.php Outdated
Comment thread system/CLI/Color.php Outdated
Comment thread system/CLI/Table.php Outdated
Comment thread tests/system/CLI/TerminalTest.php
Comment thread utils/phpstan-baseline/arguments.count.neon
@paulbalandan paulbalandan added the new feature PRs for new features label Oct 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.8 PRs that target the `4.8` branch. new feature PRs for new features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants