Progress Indicators
Yalla provides comprehensive progress tracking components for long-running tasks. These indicators give users visual feedback about the status and progress of operations.
Available Indicators
Yalla offers three types of progress indicators:
- Progress Bars - Show percentage completion with time estimates
- Spinners - Animated indicators for indeterminate progress
- Step Indicators - Track multi-step processes
Progress Bars
Progress bars are ideal when you know the total amount of work to be done.
Basic Usage
use Yalla\Output\Output;
$output = new Output();
$progress = $output->createProgressBar(100);
$progress->start();
for ($i = 0; $i < 100; $i++) {
// Do work...
usleep(50000);
$progress->advance();
}
$progress->finish();Output:
50/100 [===============>--------------] 50%Formats
Progress bars support multiple display formats:
// Normal format (default)
$progress->setFormat('normal');
// Output: 50/100 [===============>--------------] 50%
// Verbose format with custom messages
$progress->setFormat('verbose');
$progress->setMessage('Processing files...');
// Output: 50/100 [===============>--------------] 50% - Processing files...
// Detailed format with time estimates
$progress->setFormat('detailed');
// Output: 50/100 [===============>--------------] 50% - 00:05 / 00:10
// Minimal format
$progress->setFormat('minimal');
// Output: [===============>--------------] 50%
// Memory format
$progress->setFormat('memory');
// Output: 50/100 [===============>--------------] 50% - Memory: 4.25 MBCustom Format
You can create custom format templates:
$progress->setCustomFormat('Progress: {current}/{total} ({percent}%) - {message}');
$progress->setMessage('Downloading...');Advanced Options
// Set custom bar width
$progress->setBarWidth(50);
// Set redraw frequency for performance
$progress->setRedrawFrequency(10); // Only redraw every 10 items
// Set progress directly
$progress->setProgress(75);
// Clear the progress bar
$progress->clear();Time Estimates
Progress bars automatically calculate:
- Elapsed time since start
- Estimated time remaining based on current rate
- Formatted as HH:MM:SS for long operations
Spinners
Spinners are perfect for operations where the duration is unknown.
Basic Usage
$spinner = $output->createSpinner('Loading data...');
$spinner->start();
// Do work...
for ($i = 0; $i < 50; $i++) {
usleep(100000);
$spinner->advance();
}
$spinner->success('Data loaded successfully!');Frame Styles
Spinners support various animation styles:
// Dots (default)
$spinner = $output->createSpinner('Processing...', 'dots');
// Animation: ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏
// Line
$spinner = $output->createSpinner('Processing...', 'line');
// Animation: - \ | /
// Pipe
$spinner = $output->createSpinner('Processing...', 'pipe');
// Animation: ┤ ┘ ┴ └ ├ ┌ ┬ ┐
// Arrow
$spinner = $output->createSpinner('Processing...', 'arrow');
// Animation: ← ↖ ↑ ↗ → ↘ ↓ ↙
// Bounce
$spinner = $output->createSpinner('Processing...', 'bounce');
// Animation: ⠁ ⠂ ⠄ ⠂
// Box
$spinner = $output->createSpinner('Processing...', 'box');
// Animation: ▖ ▘ ▝ ▗Custom Frames
You can define custom animation frames:
$spinner->setFrames(['🌍', '🌎', '🌏']);
$spinner->setInterval(200); // Milliseconds between framesDynamic Messages
Update the message while the spinner is running:
$spinner->start();
$steps = ['Connecting...', 'Authenticating...', 'Downloading...', 'Processing...'];
foreach ($steps as $step) {
$spinner->setMessage($step);
sleep(1);
}Completion States
Spinners can finish with different states:
// Success (green checkmark)
$spinner->success('Process completed!');
// Error (red cross)
$spinner->error('Process failed!');
// Warning (yellow exclamation)
$spinner->warning('Process completed with warnings');
// Info (blue info symbol)
$spinner->info('Process terminated by user');Performance
// Get elapsed time
$elapsed = $spinner->getElapsedTime();
// Clear the spinner output
$spinner->clear();Step Indicators
Step indicators are ideal for workflows with discrete stages.
Basic Usage
$steps = $output->steps([
'Download package',
'Extract files',
'Install dependencies',
'Run migrations',
'Clear cache'
]);
$steps->start();
// Complete steps as you go
$steps->complete(0, 'Package downloaded (2.3MB)');
sleep(1);
$steps->complete(1, 'Files extracted to /tmp');
sleep(1);
$steps->complete(2, '42 dependencies installed');
sleep(1);
$steps->skip(3, 'No migrations to run');
$steps->fail(4, 'Failed to clear cache');
$steps->finish();Output:
[1/5] Download package
✅ Package downloaded (2.3MB) [0.5s]
[2/5] Extract files
✅ Files extracted to /tmp [0.3s]
[3/5] Install dependencies
✅ 42 dependencies installed [2.1s]
[4/5] Run migrations
⏭️ No migrations to run
[5/5] Clear cache
❌ Failed to clear cache
═══ Summary ═══
Completed: 3
Failed: 1
Skipped: 1
Total time: 3.2sAlternative Syntax
You can also use array format with step descriptions:
$steps = $output->steps([
['download', 'Download package from repository'],
['extract', 'Extract compressed files'],
['install', 'Install required dependencies'],
['migrate', 'Run database migrations'],
['cache', 'Clear application cache']
]);Step States
Each step can be in one of several states:
// Mark as running (shows spinner)
$steps->running(0, 'Downloading package...');
// Mark as completed
$steps->complete(0, 'Download complete');
// Mark as failed
$steps->fail(1, 'Extraction failed: Invalid archive');
// Mark as skipped
$steps->skip(2, 'Dependencies already installed');Advanced Features
// Auto-advance to next step
$steps->next();
// Get timing for individual steps
$time = $steps->getStepTime(0);
// Custom symbols
$steps = $output->steps($tasks, [
'pending' => '○',
'running' => '◉',
'complete' => '✓',
'failed' => '✗',
'skipped' => '→'
]);
// Custom colors
$steps = $output->steps($tasks, [], [
'pending' => 'gray',
'running' => 'yellow',
'complete' => 'green',
'failed' => 'red',
'skipped' => 'cyan'
]);
// Show step numbers
$steps = $output->steps($tasks, [], [], true);Integration Examples
File Processing
$files = glob('data/*.csv');
$progress = $output->createProgressBar(count($files));
$progress->setFormat('verbose');
$progress->start();
foreach ($files as $file) {
$progress->setMessage('Processing: ' . basename($file));
// Process file...
processFile($file);
$progress->advance();
}
$progress->finish();
$output->success('All files processed!');Multi-Stage Deployment
$deployment = $output->steps([
'Run tests',
'Build assets',
'Upload files',
'Run migrations',
'Clear cache',
'Restart services'
]);
$deployment->start();
// Run tests
$deployment->running(0);
$testResult = runTests();
if ($testResult['passed']) {
$deployment->complete(0, "{$testResult['count']} tests passed");
} else {
$deployment->fail(0, "{$testResult['failures']} tests failed");
$deployment->finish();
return;
}
// Build assets
$deployment->running(1);
$buildSize = buildAssets();
$deployment->complete(1, "Assets built ({$buildSize}MB)");
// Continue with deployment...API Data Sync
$spinner = $output->createSpinner('Connecting to API...');
$spinner->start();
try {
$api = connectToAPI();
$spinner->setMessage('Fetching records...');
$records = $api->getRecords();
$spinner->success("Connected! Found {$records->count()} records");
// Now process with progress bar
$progress = $output->createProgressBar($records->count());
$progress->setFormat('detailed');
$progress->start();
foreach ($records as $record) {
processRecord($record);
$progress->advance();
}
$progress->finish();
} catch (Exception $e) {
$spinner->error('API connection failed: ' . $e->getMessage());
}Best Practices
Choose the Right Indicator
- Use progress bars when you know the total amount of work
- Use spinners for indeterminate operations or quick tasks
- Use step indicators for multi-stage workflows
Performance Optimization
// For large datasets, reduce redraw frequency
$progress->setRedrawFrequency(100); // Update every 100 items
// For spinners, adjust animation speed
$spinner->setInterval(100); // Default is 80msUser Experience
// Provide meaningful messages
$progress->setMessage('Processing order #' . $orderId);
// Show completion with context
$spinner->success("Import complete: {$imported} records imported, {$skipped} skipped");
// Include timing in step completions
$steps->complete(0, sprintf('Backup complete (%.1fs)', $elapsed));Error Handling
try {
$progress->start();
// ... work ...
$progress->finish();
} catch (Exception $e) {
$progress->clear();
$output->error('Operation failed: ' . $e->getMessage());
}Testing
When testing code with progress indicators, you can capture output:
ob_start();
$progress = new ProgressBar($output, 100);
$progress->start();
$progress->setProgress(50);
$result = ob_get_clean();
expect($result)->toContain('50/100');
expect($result)->toContain('50%');