serendipity_hq/component-console-styles
A compact PHP component from Serendipity HQ for styling console output, helping make CLI messages easier to read with colors and formatting. Useful for adding clear, consistent visual cues to Laravel Artisan or Symfony Console commands.
Install with Composer and pin a Symfony Console range that matches your app:
composer require serendipity_hq/component-console-styles
This is a small, low-adoption package (2 stars, 0 dependents), so the source is the documentation. Read composer.json for the supported symfony/console constraint, then skim src/ — it is small enough to read end-to-end in a few minutes. The README is the second stop; treat any method name in it as needing verification against the actual classes.
First use case: render a single styled status line in an existing command, without rewriting the command's output layer. The typical shape is:
use SerendipityHQ\Component\Console\Styles\Style;
protected function execute(InputInterface $input, OutputInterface $output): int
{
$style = new Style($input, $output);
$style->title('Deploy report');
$style->success('Assets compiled');
$style->warning('Cache warmed with stale config');
$style->error('Migration 0042 failed');
return self::SUCCESS;
}
If Style is not a SymfonyStyle subclass in the version you install, the package is likely exposing formatter styles (tags) instead. In that case the entry point is registering them on the output's formatter:
$formatter = $output->getFormatter();
$formatter->setStyle('success', new OutputFormatterStyle('green', null, ['bold']));
$output->writeln('<success>Assets compiled</success>');
Confirm which model the package uses before building abstractions on top of it — that single check determines the rest of your integration.
Wrap it once, not in every command. Create a small factory or container service that returns the styled output object, so commands depend on your abstraction rather than on the package directly:
final class ConsoleStyleFactory
{
public function create(InputInterface $in, OutputInterface $out): Style
{
return new Style($in, $out);
}
}
This is the single most valuable pattern here: it isolates a 2-star dependency behind a seam you control, and lets you swap in plain SymfonyStyle later without touching command code.
Use it as the presentation layer of a command, not the logic layer. Keep execute() doing work, collect results into arrays/DTOs, and render at the end. This makes the styled output easy to snapshot-test and keeps the package out of your domain code.
Centralize the theme. If the package registers formatter tags, define them in one place (a config array or enum of tag → OutputFormatterStyle) and register in a bootstrap or an Application::configureIO override. Day-to-day you then just write <success>…</success> in commands and change colors in one file.
Compose with existing helpers. Use the package for headline blocks (titles, sections, alerts) and keep Symfony's Table, ProgressBar, and QuestionHelper for structured data. Don't fight the framework — the package's value is cosmetic consistency, not new I/O primitives.
Test through CommandTester. Assert on the rendered text with decoration disabled ($output->setDecorated(false) or --no-ansi), so tag markup does not leak into assertions:
$tester = new CommandTester($command);
$tester->execute([], ['decorated' => false]);
$this->assertStringContainsString('Assets compiled', $tester->getDisplay());
Environment-aware rendering. Gate the styled path on $output->isDecorated() and on CI (CI=true) so logs stay readable in pipelines and plain in cron/redirected output.
src/ and the composer.json constraint; do not assume SymfonyStyle compatibility.setStyle('info', …) or setStyle('error', …) mutates the shared formatter and affects every helper and third-party command in the same Application. Use custom tag names (<success>, <alert>) instead of redefining Symfony's.isDecorated() and terminal capability detection. On Windows or when piping to a file, styles silently disappear — never encode meaning in color alone; keep the words ("FAILED", "WARN") in the message.CommandTester defaults can leave ANSI escapes in the display. Always assert with decoration off, or strip with OutputFormatter::escape awareness.SymfonyStyle into the package's constructor, check whether it re-wraps the input/output stream. Nested SymfonyStyle instances can produce duplicate blank lines and inconsistent indentation.SerendipityHQ; the Packagist name uses serendipity_hq. On case-sensitive filesystems, a mismatch between the namespace you use and the actual src/ path fails only in production — run composer dump-autoload -o in CI.composer.json and avoid extending package classes. If you need a custom style, prefer implementing it against Symfony\Component\Console\Formatter\OutputFormatterStyleInterface directly so you own the code.OutputFormatterStyle (or your own theme class) are cleaner than monkey-patching the package. Register them alongside the package's styles in the same bootstrap, and you can drop the dependency later without losing formatting.How can I help you explore Laravel packages today?