Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Cli Tools Laravel Package

wp-cli/php-cli-tools

PHP Command Line Tools is a collection of functions and classes for building command-line apps in PHP. It provides formatted output, input prompts, menus, progress indicators, ASCII tables, tree displays, and argument parsing. Requires PHP 5.6 or newer.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require wp-cli/php-cli-tools
    

    Add to composer.json under require-dev if only needed for testing/scaffolding.

  2. First Use Case: Display a formatted table in a Laravel Artisan command:

    use cli\Table;
    
    $table = new Table(['ID', 'Name', 'Status']);
    $table->addRow([1, 'User 1', 'Active']);
    $table->addRow([2, 'User 2', 'Inactive']);
    $table->display();
    
  3. Where to Look First:

    • Examples: vendor/wp-cli/php-cli-tools/examples/ for ready-to-use snippets.
    • API Docs: Focus on cli\Table, cli\progress\Bar, and cli\out() for daily use.
    • TTY Detection: Check cli\is_tty() for conditional CLI output logic.
    • Iterable Rows (v0.13.2+): If you render large result sets, check examples/table.php in the installed version for the iterator example before choosing between addRow() and streaming rows.

Implementation Patterns

Core Workflows

1. Artisan Command Output

Replace echo/var_dump with structured output:

use cli\out;

out('Processing...', 'green');
out('Done!', 'bold green');

2. Progress Feedback

Use progress bars for long-running tasks (e.g., migrations, imports):

use cli\progress\Bar;

$bar = new Bar('Migrating data', 100);
for ($i = 0; $i < 100; $i++) {
    $bar->tick();
    // Simulate work
    sleep(0.1);
}

3. Interactive Prompts

Collect user input in CLI tools:

use cli\prompt;

$confirm = prompt('Overwrite existing file?', 'n');
if ($confirm === 'y') {
    // Proceed
}

4. Tabular Data

Display query results or logs:

use cli\Table;

$table = new Table(['User ID', 'Email', 'Role']);
foreach ($users as $user) {
    $table->addRow([$user->id, $user->email, $user->role]);
}
$table->display();

5. Streaming Rows From an Iterator (v0.13.2+)

Since v0.13.2 a table can render rows fed from a Traversable/Generator, which lets you stream rows without first materialising a big array:

use cli\Table;

$table = new Table(['ID', 'Email', 'Role']);

$rows = (function () use ($users) {
    foreach ($users->cursor() as $user) {
        yield [$user->id, $user->email, $user->role];
    }
})();

$table->setRows($rows);   // check examples/table.php for the exact method name in your installed version
$table->display();

Prefer this over addRow() in a loop when the underlying query is a cursor(), a LazyCollection, or a PDOStatement — the point is to keep memory flat while still producing an aligned table.

6. Tree Structures

Visualize directory/file hierarchies:

use cli\Tree;

$tree = new Tree();
$tree->setData(['folder' => ['file1.txt', 'subfolder' => ['file2.txt']]]);
$tree->display();

Laravel-Specific Patterns

1. Artisan Command Integration

Extend Laravel’s Command class with CLI tools:

use Illuminate\Console\Command;
use cli\out;

class MyCommand extends Command {
    protected $signature = 'my:command {--force}';

    public function handle() {
        out('Command executed!', 'yellow');
        // ...
    }
}

2. Testing CLI Output

Use cli\Table/cli\progress\Bar in PHPUnit tests:

use cli\Table;
use Tests\TestCase;

class TableTest extends TestCase {
    public function testTableOutput() {
        $table = new Table(['ID', 'Name']);
        $table->addRow([1, 'Test']);
        $this->expectOutputRegex('/\|\s*1\s*\|\s*Test\s*\|\s*/');
        $table->display();
    }
}

3. Streaming Eloquent Results Into a Table

Combine cursor() with the v0.13.2 iterator support so a php artisan report:export command doesn’t blow the memory limit:

$rows = (function () {
    foreach (User::query()->cursor() as $user) {
        yield [$user->id, $user->email, $user->role];
    }
})();

(new Table(['ID', 'Email', 'Role']))->setRows($rows)->display();

4. Dynamic Menus

Build interactive CLI menus (e.g., for admin tools):

use cli\menu;

$choices = ['Option 1', 'Option 2', 'Quit'];
$choice = menu('Select an option:', $choices, 'Option 1');

5. Cross-Platform Compatibility

Handle Windows/Linux differences:

if (cli\is_windows()) {
    // Windows-specific logic
}

Integration Tips

1. Composer Scripts

Add to composer.json for reusable CLI tasks:

"scripts": {
    "test": "phpunit && php-cs-fixer fix --dry-run",
    "lint": "php-cs-fixer fix"
}

2. Custom Renderers

Extend cli\table\Renderer for custom table styles:

class MyRenderer extends \cli\table\Renderer {
    public function renderCell($value) {
        return '<span style="color: red;">' . parent::renderCell($value) . '</span>';
    }
}

3. TTY-Aware Output

Detect piped vs. interactive output:

if (cli\is_tty()) {
    out('Interactive mode: ', 'green');
} else {
    out('Piped output: ', 'yellow');
}

4. Process Execution

Run shell commands with error handling:

use cli\run_command;

$result = run_command('git status');
if ($result['success']) {
    out($result['output']);
} else {
    err('Git error: ' . $result['error']);
}

5. Version Pinning for Iterator Tables

If you rely on iterator-backed tables, pin "wp-cli/php-cli-tools": "^0.13.2" rather than a looser constraint so CI and teammates on older installs don’t silently lose the feature.


Gotchas and Tips

Pitfalls

1. TTY Detection Issues

  • Problem: cli\is_tty() may return false in CI/CD pipelines even when output is to a terminal.
  • Fix: Use environment variables or manual checks:
    $isTty = !defined('CI') && posix_isatty(STDERR);
    

2. Windows Line Endings

  • Problem: Progress bars or tables may render incorrectly on Windows.
  • Fix: Use cli\is_windows() and adjust rendering logic:
    if (cli\is_windows()) {
        $bar->setInterval(200); // Slower updates for Windows
    }
    

3. Color Output in Pipes

  • Problem: ANSI colors may break when piped to files/tools.
  • Fix: Disable colors in non-TTY contexts:
    if (!cli\is_tty()) {
        cli\Colors::disable();
    }
    

4. Table Column Wrapping

  • Problem: Long text in tables may overflow or wrap unpredictably.
  • Fix: Configure column width and wrapping:
    $table->setColumnWidths([10, 30, 'auto']); // Fixed, fixed, auto
    $table->setWrap(true);
    

5. Iterators Are Single-Pass

  • Problem: A Generator can only be traversed once. Feeding the same generator to two tables (or to display() twice) throws Cannot traverse an already closed generator.
  • Fix: Build a factory closure and create a fresh generator per render:
    $makeRows = fn () => (function () { yield [1, 'A']; })();
    (new Table(['ID', 'Name']))->setRows($makeRows())->display();
    
    If you need to re-render (e.g. after a retry), call the factory again rather than reusing the object. Also avoid mixing addRow() and setRows() on the same instance, and remember that lazy iteration means the first row isn’t rendered until the iterator is actually consumed.

6. Iterator Exceptions Surface Mid-Render

  • Problem: With streaming rows, a DB error inside the generator fires after the table header has already printed, leaving mangled output.
  • Fix: Wrap the generator body in a try/catch and emit err() + an explicit exit code, or pre-validate the query before rendering.

7. PHP Version Quirks

  • Problem: Some functions (e.g., grapheme_strlen) may not work on older PHP versions.
  • Fix: Use fallbacks:
    if (!function_exists('grapheme_strlen')) {
        require 'vendor/wp-cli/php-cli-tools/src/cli/fallbacks.php';
    }
    

Debugging Tips

1. Enable Debug Output

cli\out('Debug: ' . print_r($variable, true), 'red');

2. Check TTY State

out('TTY: ' . (cli\is_tty() ? 'Yes' : 'No'), 'blue');

3. Validate Table Data

$table->setHeaders(['ID', 'Name']);
$table->setRows([['1', 'Test']]);
$table->display();

4. Progress Bar Debugging

$bar = new Bar('Test', 5);
$bar->setInterval(50); // Faster updates for debugging

5. Debugging a Streaming Table

Materialise the iterator temporarily to confirm the data is correct before switching back to lazy mode:

$rows = $makeRows();
$preview = iterator_to_array($rows, false);
out('Row count: ' . count($preview), 'cyan');
(new Table(['ID', 'Name']))->setRows($preview)->display();

If the count is right but the table is empty, you’re likely reusing a spent generator.


Extension Points

1. Custom Table Renderers

Override cli\table\Renderer for custom styles (e.g., Markdown, HTML):

class MarkdownRenderer extends \cli\table\Renderer {
    public function renderHeader() { /* ... */ }
    public function renderRow() { /* ... */ }
}

2. Extend Argument Parser

Customize cli\ArgumentParser for project-specific CLI flags:

$parser = new \cli\ArgumentParser();
$parser->addOption('verbose', 'v', 'Enable verbose output');
$args = $parser->parse($_SERVER['argv']);

3. Add Custom Notifiers

Extend cli\notify\Notifier for new progress indicators (e.g., ASCII art):

class HeartbeatNotifier extends \cli\notify\Notifier {
    public function render($msg) { /* ... */ }
}

4. Hook into Output

Override cli\out() globally via autoloading:

// In a service provider
cli\out::setHandler(function ($msg, $color) {
    // Custom logic (e.g., log to file)
    echo $msg . PHP_EOL;
});

5. Wrap Row Sources Behind a Factory

When you standardise table rendering in a base command, accept a Closure that returns an iterable rather than the iterable itself. This gives you one place to add iterator re-creation, error wrapping, and row-count estimation for the new iterator-aware table API.


Configuration Quirks

  • No config file: php-cli-tools is configured entirely in code; there’s nothing published to config/.
  • Global colour state: cli\Colors::disable() mutates process-wide state — call it once early (e.g. in a service provider or base command handle()) rather than per-table, or subsequent commands in the same process (queue workers, test suites) inherit it.
  • Terminal width detection: Table and progress rendering depends on the detected terminal width, which is unreliable when output is redirected. Set a width explicitly if output must be byte-identical across environments.
  • Version-gated features: Iterator table support landed in v0.13.2. Anything older silently lacks it, so check composer show wp-cli/php-cli-tools when a teammate reports a missing method.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus