Installation:
composer require dariuszp/cli-progress-bar
First Use Case: Add a progress bar to a loop in an Artisan command or script:
use Dariuszp\CliProgressBar;
$bar = new CliProgressBar(100); // Total iterations
$bar->display();
for ($i = 0; $i <= 100; $i++) {
// Your processing logic here
$bar->setDetails("Processing record $i");
sleep(0.1); // Simulate work
}
$bar->end();
Where to Look First:
examples/ for use cases like colors, animations, and alternate styles.Usage section for core methods (display(), setDetails(), end()).displayAlternateProgressBar().Artisan Commands:
Integrate into Laravel’s CLI workflows by extending Illuminate\Console\Command:
use Dariuszp\CliProgressBar;
protected function handle() {
$bar = new CliProgressBar(100, 0, "Migrating data...");
$bar->display();
foreach ($this->records as $record) {
$this->processRecord($record);
$bar->increment(); // Update progress
}
$bar->end();
}
Queue Workers:
Use in handle() methods of Laravel jobs for async progress feedback:
public function handle() {
$bar = new CliProgressBar(10, 0, "Exporting files...");
$bar->display();
foreach ($this->files as $file) {
$this->exportFile($file);
$bar->increment();
}
$bar->end();
}
Dynamic Updates: Update progress bars asynchronously (e.g., during API calls or DB queries):
$bar = new CliProgressBar(5, 0, "Fetching data...");
$bar->display();
foreach ($this->apiCalls as $call) {
$response = Http::get($call);
$bar->setDetails("Fetched {$response->status()} for {$call}");
$bar->increment();
}
Progress Bar Lifecycle:
display() to render the bar.increment(), setDetails(), or setProgress() during loops.end() to finalize output.Cross-Platform Handling: Auto-detect Windows and switch to ASCII style:
$bar = new CliProgressBar(100);
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$bar->displayAlternateProgressBar();
}
$bar->display();
Customization:
setDetails() or pass during initialization.new CliProgressBar(100, 0, "Text", 30) for a 30-character bar).examples/colors.php).Laravel Service Container: Bind the progress bar to the container for dependency injection:
$this->app->singleton(CliProgressBar::class, function ($app) {
return new CliProgressBar(100, 0, "Default text");
});
Command Options: Allow users to enable/disable progress bars via CLI flags:
protected $signature = 'command {--progress : Show progress bar}';
protected function handle() {
if ($this->option('progress')) {
$bar = new CliProgressBar(100);
$bar->display();
// ... loop with updates
$bar->end();
}
}
Testing: Mock progress bars in unit tests by extending the class:
class MockProgressBar extends CliProgressBar {
public function display() {}
public function end() {}
public function increment() {}
}
Windows UTF-8 Issues:
▓░).displayAlternateProgressBar() or set the environment variable DARIUSZP_CLI_PROGRESS_BAR_ALTERNATE=1.Async Updates:
setDetails() calls may cause output corruption or lag.Non-Interactive Shells:
if (php_sapi_name() !== 'cli' || !stream_isatty(STDERR)) {
return; // Skip progress bar
}
Memory Leaks:
end() to clean up output buffers.Broken Output:
echo -e "\e[31mRed Text\e[0m" in your terminal to verify ANSI support.Progress Not Updating:
increment() or setProgress() is called in the correct loop iteration.sleep(0.1) after updates to force terminal refreshes.Windows-Specific Issues:
displayAlternateProgressBar() or install a UTF-8-compatible terminal (e.g., Windows Terminal).Bar Length:
getBarLength() method.Text Truncation:
setDetails() text may overflow. Limit text length or adjust terminal width dynamically:
$bar->setDetails(substr("Long text...", 0, 30));
Percentage Precision:
formatPercentage() method for custom formatting.Custom Styling: Extend the class to add colors or symbols:
class ColoredProgressBar extends CliProgressBar {
protected function getFilledChar(): string {
return "\033[32m▓\033[0m"; // Green filled block
}
protected function getEmptyChar(): string {
return "\033[31m░\033[0m"; // Red empty block
}
}
Dynamic Length: Adjust bar length based on terminal width:
$bar = new CliProgressBar(100);
$bar->setBarLength(exec('tput cols') - 20); // Leave space for text
Event-Based Updates:
Hook into Laravel events (e.g., job.processed) to update progress bars:
event(new JobProcessed($job));
$bar->setDetails("Processed {$job->payload['data']['command']}");
$bar->increment();
Fallback to Symfony Console:
Create a wrapper that falls back to symfony/console if issues arise:
class ProgressBarService {
public function create(int $total, string $text = ''): CliProgressBar {
try {
return new CliProgressBar($total, 0, $text);
} catch (\Exception $e) {
return new SymfonyProgressBar($total, $text);
}
}
}
Artisan Output:
Use Artisan::output() alongside progress bars for mixed output:
Artisan::output("Starting migration...");
$bar = new CliProgressBar(10);
$bar->display();
// ... loop
$bar->end();
Artisan::output("Migration complete!");
Queue Workers:
Integrate with laravel-horizon or backstage by extending the worker class:
class ProgressWorker extends Worker {
protected function getProgressBar(int $total): CliProgressBar {
return new CliProgress
How can I help you explore Laravel packages today?