symfony/tui
The Symfony TUI component provides a terminal UI framework for building rich, interactive CLI applications in PHP. It offers building blocks for dynamic terminal interfaces, though it is experimental and not covered by Symfony's backward compatibility promise.
Installation:
composer require symfony/tui
Add to composer.json under require-dev if only for CLI tools.
First Use Case: Create a simple interactive CLI app:
use Symfony\Component\Console\Application;
use Symfony\Component\Tui\Application as TuiApplication;
use Symfony\Component\Tui\Style\Style;
use Symfony\Component\Tui\Widget\Text;
$tuiApp = new TuiApplication();
$tuiApp->add(new class extends \Symfony\Component\Tui\Command\Command {
protected function configure(): void {
$this->setName('hello');
}
protected function execute(): int {
$this->render(new Text('Hello, Symfony TUI!'));
return Command::SUCCESS;
}
});
$tuiApp->run();
Run with:
php your-script.php hello
Key Files to Explore:
src/Command/ – Core command structure.src/Widget/ – UI components (e.g., Text, List, Form).src/Style/ – Styling utilities (Style, Color, Ansi).src/Event/ – Event-driven interactions (e.g., KeyPressEvent).Building Interactive Forms:
use Symfony\Component\Tui\Widget\Form;
$form = new Form();
$form->addTextInput('name', 'Your Name');
$form->addSelectInput('language', 'Language', ['php', 'js', 'go']);
$this->render($form);
Event-Driven UI: Handle user input dynamically:
$this->onKeyPress(function (KeyPressEvent $event) {
if ($event->key === 'q') {
$this->stop();
}
});
Layout Management:
Use Grid or Box for structured layouts:
use Symfony\Component\Tui\Widget\Box;
use Symfony\Component\Tui\Widget\Grid;
$box = new Box(new Text('Sidebar'));
$grid = new Grid([$box, new Text('Main Content')]);
$this->render($grid);
Styling Consistency: Define reusable styles:
$style = new Style(
new Color(255, 0, 0), // Red
new Ansi(1) // Bold
);
$this->render(new Text('Error!')->setStyle($style));
Integration with Symfony Console: Combine with Symfony Console commands for hybrid CLI/TUI apps:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class HybridCommand extends Command {
protected function execute(InputInterface $input, OutputInterface $output): int {
$tuiApp = new TuiApplication();
$tuiApp->add(new TuiCommand());
$tuiApp->run();
return Command::SUCCESS;
}
}
Terminal Compatibility:
Table) may render poorly on older terminals. Test on xterm-256color.$this->getTerminal()->isSupported() to check capabilities.Event Handling:
KeyPressEvent are not automatically bound to widgets. Explicitly attach them:
$widget->onKeyPress(...);
Performance with Large Data:
List widget) is supported, but custom implementations may lag. Use ->setItemsPerPage() for large datasets.Styling Overrides:
Style::merge() to combine styles predictably:
$merged = $style1->merge($style2);
Debugging:
$tuiApp->setDebug(true);
$this->getTerminal()->getSize() to verify screen dimensions during layout issues.Reusable Components: Create base classes for common widgets:
abstract class BaseForm extends Command {
protected function buildForm(): Form {
$form = new Form();
// Shared form logic
return $form;
}
}
Keyboard Shortcuts:
Use KeyPressEvent to implement shortcuts (e.g., Ctrl+C for exit):
$this->onKeyPress(function (KeyPressEvent $event) {
if ($event->isControlPressed() && $event->key === 'c') {
$this->stop();
}
});
Theming: Extract styles to a config file for consistency:
$styles = require __DIR__.'/styles.php';
$widget->setStyle($styles['error']);
Testing: Mock the terminal for unit tests:
$terminal = $this->createMock(Terminal::class);
$terminal->method('getSize')->willReturn([80, 24]);
$command = new YourCommand($terminal);
Extension Points:
TuiApplication to add global event listeners or middleware.Widget\WidgetInterface for custom components (e.g., ProgressBar).How can I help you explore Laravel packages today?