Skip to content

Instantly share code, notes, and snippets.

@damsfx
Last active July 30, 2025 18:35
Show Gist options
  • Select an option

  • Save damsfx/e0a0132970cc682054207c7ad141d57f to your computer and use it in GitHub Desktop.

Select an option

Save damsfx/e0a0132970cc682054207c7ad141d57f to your computer and use it in GitHub Desktop.

WinterCMS console command output

This is a console command used as a demonstration to quickly find the various possibilities offered by the output of a console command.

Infos

  1. Copy the file as TestOutputCommand.php in your plugin console directory
  2. Adapt namespace Acme\Myplugin\Console to your plugin
  3. Register the command in your plugin's plugin.php file
    public function register(): void
    {
        // ... 
        $this->registerConsoleCommand(
            'myplugin.testoutput',
            \Acme\Myplugin\Console\TestOutputCommand::class
        );
    }

Usage

# Show all
php artisan myplugin:testoutput

# Show default output commands
php artisan myplugin:testoutput default

# Show laravel output commands
php artisan myplugin:testoutput laravel

# Show availables styles
php artisan myplugin:testoutput styles

# Show a filtered list of commands matching a keyword
php artisan myplugin:testoutput  --keyword=list
# Same combined with choosen command
php artisan myplugin:testoutput default --keyword=list

Warning

Some commands are not rendered in the same way on all OS, especially Windows.

TestOutputCommand.php file

<?php

namespace Acme\Myplugin\Console;

use ReflectionProperty;
use Symfony\Component\Console\Color;
use Symfony\Component\Console\Helper\TableSeparator;
use Winter\Storm\Console\Command;

class TestOutputCommand extends Command
{
    /**
     * @var string The console command name.
     */
    protected static $defaultName = 'myplugin:testoutput';

    /**
     * @var string The name and signature of this command.
     */
    protected $signature = 'myplugin:testoutput
        {outputStyle? : Type of command to display (none, default, laravel or styles).}
        {--keyword=* : Filter the output functions based on keyword(s) (optional, multiple values possible).}
        ';

    /**
     * @var string The console command description.
     */
    protected $description = 'Demonstration of console output methods';


    private array $titles = [
        'default' => [
            '    ____       ____            ____                 __              __',
            '   / __ \___  / __/___ ___  __/ / /_   ____  __  __/ /_____  __  __/ /______',
            '  / / / / _ \/ /_/ __ `/ / / / / __/  / __ \/ / / / __/ __ \/ / / / __/ ___/',
            ' / /_/ /  __/ __/ /_/ / /_/ / / /_   / /_/ / /_/ / /_/ /_/ / /_/ / /_(__  )',
            '/_____/\___/_/  \__,_/\__,_/_/\__/   \____/\__,_/\__/ .___/\__,_/\__/____/',
            '                                                   /_/',
        ],
        'laravel' => [
            '    __                                __               __              __',
            '   / /   ____ __________ __   _____  / /  ____  __  __/ /_____  __  __/ /______',
            '  / /   / __ `/ ___/ __ `/ | / / _ \/ /  / __ \/ / / / __/ __ \/ / / / __/ ___/',
            ' / /___/ /_/ / /  / /_/ /| |/ /  __/ /  / /_/ / /_/ / /_/ /_/ / /_/ / /_(__  )',
            '/_____/\__,_/_/   \__,_/ |___/\___/_/   \____/\__,_/\__/ .___/\__,_/\__/____/',
            '                                                      /_/',
        ],
        'styles' => [
            '    ___    ____        __        __',
            '   /   |  / / /  _____/ /___  __/ /__  _____',
            '  / /| | / / /  / ___/ __/ / / / / _ \/ ___/',
            ' / ___ |/ / /  (__  ) /_/ /_/ / /  __(__  )',
            '/_/  |_/_/_/  /____/\__/\__, /_/\___/____/',
            '                       /____/',
        ],
    ];


    public function __construct()
    {
        parent::__construct();

        $this->outputs = collect([
            // Titles
            'title' => [
                'display' => 'Title',
                'description' => 'Display a title in the console output.',
                'keywords' => ['title'],
                'methods' => [
                    'default' => 'title',
                ],
                'arguments' => ['This is a title'],
            ],

            // Sections
            'section' => [
                'display' => 'Section',
                'description' => 'Display a section title in the console output.',
                'keywords' => ['section'],
                'methods' => [
                    'default' => 'section',
                ],
                'arguments' => ['This is a section'],
            ],

            // Texts
            'text' => [
                'display' => 'Text',
                'description' => 'Display a text in the console output.',
                'keywords' => ['text', 'line'],
                'methods' => [
                    'default' => 'text',
                    // 'laravel' => 'line',
                ],
                'arguments' => ['This is a text'],
            ],
            'text (multiple)' => [
                'display' => 'Text',
                'description' => 'Display a text in the console output.',
                'keywords' => ['text', 'line'],
                'methods' => [
                    'default' => 'text',
                ],
                'arguments' => [[
                    'This is a text',
                    'in a multi-line format',
                ]],
            ],

            // Tables
            'table' => [
                'display' => 'Table',
                'description' => 'Display a table with headers and rows.',
                'keywords' => ['table', 'row', 'column'],
                'methods' => [
                    'default' => 'table',
                    'short' => 'default',
                ],
                'arguments' => [
                    ['Header 1', 'Header 2'],
                    [
                        ['Cell 1-1', 'Cell 1-2'],
                        ['Cell 2-1', 'Cell 2-2'],
                        ['Cell 3-1', 'Cell 3-2'],
                    ]
                ],
            ],
            'horizontalTable' => [
                'display' => 'Horizontal Table',
                'description' => 'Display a horizontal table with headers and rows.',
                'keywords' => ['table', 'row', 'column'],
                'methods' => [
                    'default' => 'horizontalTable',
                ],
                'arguments' => [
                    ['Header 1', 'Header 2'],
                    [
                        ['Cell 1-1', 'Cell 1-2'],
                        ['Cell 2-1', 'Cell 2-2'],
                        ['Cell 3-1', 'Cell 3-2'],
                    ]
                ],
            ],
            'twoColumnDetail' => [
                'display' => 'Two Column Detail',
                'description' => 'Display two columns of details.',
                'keywords' => ['table', 'row', 'column', 'detail'],
                'methods' => [
                    'laravel' => 'twoColumnDetail',
                ],
                'arguments' => [
                    'Column 1: Lorem ipsum dolor sit amet',
                    'Column 2: Consectetur adipiscing elit',
                ],
            ],

            // Definition List
            'definitionList' => [
                'display' => 'Definition List',
                'description' => 'Display a definition list with terms and descriptions.',
                'keywords' => ['list', 'definition'],
                'methods' => [
                    'default' => 'definitionList',
                ],
                'arguments' => [
                    'This is a title',
                    ['foo1' => 'bar1'],
                    ['foo2' => 'bar2'],
                    ['foo3' => 'bar3'],
                    new TableSeparator(),
                    'This is another title',
                    ['foo4' => 'bar4'],
                ],
            ],

            // Listing
            'listing' => [
                'display' => 'Listing',
                'description' => 'Display a list of items.',
                'keywords' => ['list', 'definition'],
                'methods' => [
                    'default' => 'listing',
                    'laravel' => 'bulletList',
                ],
                'arguments' => [
                    [
                        'Element #1 Lorem ipsum dolor sit amet',
                        'Element #2 Lorem ipsum dolor sit amet',
                        'Element #3 Lorem ipsum dolor sit amet',
                    ],
                ],
            ],

            // Info
            'info' => [
                'display' => 'Info',
                'description' => 'Display an informational message.',
                'keywords' => ['message', 'info'],
                'methods' => [
                    'default' => 'info',
                    'laravel' => 'info',
                ],
                'arguments' => [
                    'This is an informational message.',
                ],
            ],
            'info (multiple)' => [
                'display' => 'Info',
                'description' => 'Display an informational message.',
                'keywords' => ['message', 'info'],
                'methods' => [
                    'default' => 'info',
                ],
                'arguments' => [
                    [
                        'This is an informational message.',
                        'This is another informational message.',
                    ],
                ],
            ],

            // Success
            'success' => [
                'display' => 'Success',
                'description' => 'Display a success message.',
                'keywords' => ['message', 'success'],
                'methods' => [
                    'default' => 'success',
                ],
                'arguments' => [
                    'This is a success message.',
                ],
            ],
            'success (multiple)' => [
                'display' => 'Success',
                'description' => 'Display a success message.',
                'keywords' => ['message', 'success'],
                'methods' => [
                    'default' => 'success',
                ],
                'arguments' => [
                    [
                        'This is a success message.',
                        'This is another success message.',
                    ],
                ],
            ],

            // Note
            'note' => [
                'display' => 'Note',
                'description' => 'Display a note message.',
                'keywords' => ['message', 'note'],
                'methods' => [
                    'default' => 'note',
                ],
                'arguments' => [
                    'This is a note message.',
                ],
            ],
            'note (multiple)' => [
                'display' => 'Note',
                'description' => 'Display a note message.',
                'keywords' => ['message', 'note'],
                'methods' => [
                    'default' => 'note',
                ],
                'arguments' => [
                    [
                        'This is a note message.',
                        'This is another note message.',
                    ],
                ],
            ],

            // Warning
            'warning' => [
                'display' => 'Warning',
                'description' => 'Display a warning message.',
                'keywords' => ['message', 'warning'],
                'methods' => [
                    'default' => 'caution',
                    'laravel' => 'warn',
                ],
                'arguments' => [
                    'This is a warning message.',
                ],
            ],
            'warning (multiple)' => [
                'display' => 'Warning',
                'description' => 'Display a warning message.',
                'keywords' => ['message', 'warning'],
                'methods' => [
                    'default' => 'caution',
                ],
                'arguments' => [
                    [
                        'This is an warning message.',
                        'This is another warning message.',
                    ],
                ],
            ],

            // Error
            'error' => [
                'display' => 'Error',
                'description' => 'Display an error message.',
                'keywords' => ['message', 'error'],
                'methods' => [
                    'default' => 'error',
                    'laravel' => 'error',
                ],
                'arguments' => [
                    'This is an error message.',
                ],
            ],
            'error (multiple)' => [
                'display' => 'Error',
                'description' => 'Display an error message.',
                'keywords' => ['message', 'error'],
                'methods' => [
                    'default' => 'error',
                ],
                'arguments' => [
                    [
                        'This is an error message.',
                        'This is another error message.',
                    ],
                ],
            ],

            // Alert
            'alert' => [
                'display' => 'Alert',
                'description' => 'Display an alert message.',
                'keywords' => ['message', 'alert'],
                'methods' => [
                    'laravel' => 'alert',
                ],
                'arguments' => [
                    'This is an alert message.',
                ],
            ],

            // Task
            'task' => [
                'display' => 'Task',
                'description' => 'Display a task with a description and a callable function.',
                'keywords' => ['task', 'function', 'callable'],
                'methods' => [
                    'laravel' => 'task',
                ],
                'arguments' => [
                    'Task description',
                    fn() => $this->fakeCallable(),
                ],
            ],

            // Ask
            'ask' => [
                'display' => 'Ask',
                'description' => 'Ask a question and get an answer.',
                'keywords' => ['question', 'answer'],
                'methods' => [
                    'default' => 'ask',
                    'laravel' => 'ask',
                ],
                'arguments' => [
                    'What is your name?',
                    'John Doe',
                ],
                'response' => true,
            ],

            // Ask with completion
            'askWithCompletion' => [
                'display' => 'Ask with Completion',
                'description' => 'Ask a question with autocompletion options.',
                'keywords' => ['question', 'answer', 'completion'],
                'methods' => [
                    'laravel' => 'askWithCompletion',
                ],
                'arguments' => [
                    'What is your favorite color?',
                    ['red', 'green', 'blue', 'yellow'],
                    'blue'
                ],
                'response' => true,
            ],

            // Choice
            'choice' => [
                'display' => 'Choice',
                'description' => 'Ask a question with multiple choice options.',
                'keywords' => ['question', 'answer', 'choice'],
                'methods' => [
                    'default' => 'choice',
                    'laravel' => 'choice',
                ],
                'arguments' => [
                    'What is your favorite color?',
                    ['red', 'green', 'blue', 'yellow'],
                    'blue',
                    1,
                    false,
                ],
                'response' => true,
            ],
            'choice (multiple)' => [
                'display' => 'Choice',
                'description' => 'Ask a question with multiple choice options.',
                'keywords' => ['question', 'answer', 'choice', 'multiple'],
                'methods' => [
                    'default' => 'choice',
                    'laravel' => 'choice',
                ],
                'arguments' => [
                    'What is your favorite color?',
                    ['red', 'green', 'blue', 'yellow'],
                    'blue',
                    1,
                    true,
                ],
                'response' => true,
            ],

            // Confirm
            'confirm' => [
                'display' => 'Confirm',
                'description' => 'Ask a yes/no question and get a confirmation response.',
                'keywords' => ['question', 'answer', 'confirmation'],
                'methods' => [
                    'default' => 'confirm',
                    'laravel' => 'confirm',
                ],
                'arguments' => [
                    'Do you want to proceed?',
                    'yes',
                ],
                'confirm' => true,
            ],

            // Tree - only available in Symfony 7.3+
            // 'tree' => [
            //     'display' => 'Tree',
            //     'description' => 'Display a tree structure.',
            //     'keywords' => ['tree', 'structure'],
            //     'methods' => [
            //         'default' => 'tree',
            //     ],
            //     'arguments' => [
            //         [
            //             'src' =>  [
            //                 'Controller' => [
            //                     'DefaultController.php',
            //                 ],
            //                 'Kernel.php',
            //             ],
            //             'templates' => [
            //                 'base.html.twig',
            //             ],
            //         ]
            //     ],
            // ],
        ]);
    }

    /**
     * Execute the console command.
     * @return void
     */
    public function handle()
    {
        $availableModes = ['default', 'laravel', 'styles'];

        if (!$this->argument('outputStyle')) {
            if ($this->option('keyword')) {
                // Remove styles from $availableModes
                $availableModes = ['default', 'laravel'];
            }

            foreach ($availableModes as $key) {
                $this->output->text($this->titles[$key]);
                $this->output->newLine();
                $outputMethod = $key .'Outputs';
                $this->{$outputMethod}();
            }
        } elseif (in_array($this->argument('outputStyle'), $availableModes, true)) {
            $mode = $this->argument('commandType');
            $this->output->text($this->titles[$mode]);
            $this->output->newLine();
            $outputMethod = $mode .'Outputs';
            $this->{$outputMethod}();
        } else {
            return Command::FAILURE;
        }

        return Command::SUCCESS;
    }


    /**
     * Display default console outputs.
     */
    private function defaultOutputs(): void
    {
        $defaultOutputs = $this->outputs->filter(function ($output, $key) {
            return array_get($output, 'methods.default', false);
        });

        $defaultOutputs = $this->filterOutputsByKeywords($defaultOutputs, $this->option('keyword'));

        if ($defaultOutputs->isEmpty()) {
            $this->output->text('<fg=red>No default outputs found for the given keywords.</>');
            return;
        } else {
            $this->showOutputs($defaultOutputs, 'default');
        }
    }

    /**
     * Display Laravel console outputs.
     */
    private function laravelOutputs(): void
    {
        $laravelOutputs = $this->outputs->filter(function ($output, $key) {
            return array_get($output, 'methods.laravel', false);
        });

        $laravelOutputs = $this->filterOutputsByKeywords($laravelOutputs, $this->option('keyword'));

        if ($laravelOutputs->isEmpty()) {
            $this->output->text('<fg=red>No Laravel outputs found for the given keywords.</>');
            return;
        } else {
            $this->showOutputs($laravelOutputs, 'laravel');
        }
    }

    /**
     * Display available console styles.
     */
    private function stylesOutputs(): void
    {
        $reflect = new \ReflectionClass(Color::class);
        $availableColorsAndOptions = $reflect->getConstants(\ReflectionProperty::IS_PRIVATE);
        $lines= [];

        foreach ($availableColorsAndOptions as $key => $options) {
            $lines[] = '';
            $lines[] = 'πŸš€ '. $key;
            $lines[] = '-------------------------------';

            foreach ($options as $color => $value) {
                switch ($key) {
                    case 'COLORS':
                        $lines[] = "<fg={$color}>{$color}</>";
                        break;
                    case 'BRIGHT_COLORS':
                        $lines[] = "<fg={$color}>{$color}</>";
                        break;
                    case 'AVAILABLE_OPTIONS':
                        $lines[] = "<options={$color}>{$color}</>";
                        break;
                }
            }
        }

        $this->output->text($lines);
        $this->output->text([
            '',
            'πŸš€ Styles',
            '-------------------------------',
            '<info>info</info>',
            '<comment>comment</comment>',
            '<question>question</question>',
            '<error>error</error>',
        ]);
        $this->output->text([
            '',
            'πŸš€ Custom combos',
        ]);

        $this->output->definitionList(
            ['Custom foreground and background' => '<fg=blue;options=blink;bg=yellow>blue text on yellow background</>'],
            ['Clickable URL' => '<fg=bright-blue;href=https://gist.github.com/damsfx/e0a0132970cc682054207c7ad141d57f;>Edit this gist on github.com</>'],
        );

        $this->output->newLine();
    }

    private function showOutputs($outputs, string $method): void
    {
        $outputToUse = $method === 'laravel' ? 'components' : 'output';

        foreach ($outputs as $key => $output) {
            $this->output->text([
                "<fg=bright-yellow>πŸš€ {$key} : \$this->{$outputToUse}->{$output['methods'][$method]}</>",
                "<fg=bright-yellow>        {$output['description']}</>",
            ]);
            $needResponse = array_get($output, 'response', false);
            $confirmation = array_get($output, 'confirm', false);

            if ($needResponse) {
                $response = $this->{$outputToUse}->{$output['methods'][$method]}(...$output['arguments']);
                if (is_array($response)) {
                    $response = implode(', ', $response);
                }
                $this->output->writeln('<info>Response: </info>' . $response);
            } elseif ($confirmation) {
                $response = $this->{$outputToUse}->{$output['methods'][$method]}(...$output['arguments']);
                $this->output->writeln('<info>Confirmation: </info>' . ($response ? 'Yes' : 'No'));
            } else {
                $this->{$outputToUse}->{$output['methods'][$method]}(...$output['arguments']);
            }

            if (array_get($output['methods'], 'short', null) === $method) {
                $this->output->block(">> {$key} (short) : \$this->{$output['methods'][$method]}", null, 'fg=yellow');
                $this->{$output['methods'][$method]}(...$output['arguments']);
            }

            $this->newLine();
        }
    }

    private function filterOutputsByKeywords($outputs, $keywords)
    {
        if (!$keywords = $this->option('keyword')) {
            return $outputs;
        }
        // Ensure keywords is an array
        if (!is_array($keywords)) {
            $keywords = [$keywords];
        }

        // Filter outputs by keywords
        $outputs = $outputs->filter(function ($output) use ($keywords) {
            $outputKeywords = array_get($output, 'keywords', []);
            return !empty(array_intersect($keywords, $outputKeywords));
        });

        return $outputs;
    }

    /**
     * Simulate a callable function for demonstration purposes.
     * This is just a placeholder to simulate some processing time.
     */
    private function fakeCallable(): void
    {
        // Simulate a delay with a random sleep
        usleep(rand(100000, 500000));
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment