From 40a261fcb6a105ae7f51a0fee33e7d29ef0832f1 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Fri, 26 Sep 2025 18:06:13 +0300 Subject: [PATCH 01/12] docs: Updated Example 01 --- .../01-basic-hello-world/HelloCommand.php | 2 +- examples/01-basic-hello-world/README.md | 200 +++++++++--------- examples/01-basic-hello-world/main.php | 3 - 3 files changed, 101 insertions(+), 104 deletions(-) diff --git a/examples/01-basic-hello-world/HelloCommand.php b/examples/01-basic-hello-world/HelloCommand.php index 947f2a9..3d1ee6c 100644 --- a/examples/01-basic-hello-world/HelloCommand.php +++ b/examples/01-basic-hello-world/HelloCommand.php @@ -48,7 +48,7 @@ public function exec(): int { // Special greeting for WebFiori if (strtolower($name) === 'webfiori') { $this->success("πŸŽ‰ Hello, $name! Welcome to the CLI world!"); - $this->info('You\'re using the WebFiori CLI library - great choice!'); + $this->info('You\'re using the WebFiori CLI library.'); } else { // Standard greeting $this->println("Hello, $name! πŸ‘‹"); diff --git a/examples/01-basic-hello-world/README.md b/examples/01-basic-hello-world/README.md index 82ae8d5..1a03ffa 100644 --- a/examples/01-basic-hello-world/README.md +++ b/examples/01-basic-hello-world/README.md @@ -1,130 +1,130 @@ # Basic Hello World Example -This example demonstrates the most fundamental concepts of creating a CLI command with the WebFiori CLI library. +This example demonstrates the most basic CLI command creation using WebFiori CLI library. -## 🎯 What You'll Learn +## Features Demonstrated -- How to create a basic command class -- How to set up a CLI runner -- How to handle simple command execution -- Basic output methods +- Creating a simple command class +- Adding optional arguments with default values +- Basic output formatting with emojis +- Help system integration +- Error handling -## πŸ“ Files +## Files -- `HelloCommand.php` - A simple greeting command -- `main.php` - Application entry point -- `README.md` - This documentation +- `main.php` - Application entry point and runner setup +- `HelloCommand.php` - The hello command implementation -## πŸš€ Running the Example +## Usage Examples +### 1. Show General Help ```bash -# Basic greeting -php main.php hello +php main.php +# or +php main.php help +``` +**Output:** +``` +Usage: + command [arg1 arg2="val" arg3...] -# Greeting with a name -php main.php hello --name="Alice" +Global Arguments: + --ansi:[Optional] Force the use of ANSI output. +Available Commands: + help: Display CLI Help. To display help for specific command, use the argument "--command" with this command. + hello: A simple greeting command that says hello to someone +``` -# Get help -php main.php help -php main.php help --command-name=hello +### 2. Show Command-Specific Help +```bash +php main.php help --command=hello +``` +**Output:** +``` + hello: A simple greeting command that says hello to someone + Supported Arguments: + --name:[Optional][Default = 'World'] The name to greet (default: World) ``` -## πŸ“– Code Explanation +### 3. Basic Hello (Default Name) +```bash +php main.php hello +``` +**Output:** +``` +Hello, World! πŸ‘‹ +Have a wonderful day! +``` -### HelloCommand.php +### 4. Hello with Custom Name +```bash +php main.php hello --name=Ahmed +``` +**Output:** +``` +Hello, Ahmed! πŸ‘‹ +Have a wonderful day! +``` -The `HelloCommand` class extends the base `Command` class and demonstrates: +### 5. Hello with Multi-word Name +```bash +php main.php hello --name="Fatima Al-Zahra" +``` +**Output:** +``` +Hello, Fatima Al-Zahra! πŸ‘‹ +Have a wonderful day! +``` -- **Command naming**: Using `hello` as the command name -- **Arguments**: Optional `--name` parameter with default value -- **Output**: Using `println()` for formatted output -- **Return codes**: Returning 0 for success +### 6. Using Global ANSI Flag +```bash +php main.php hello --name=Mohammed --ansi +``` +**Output:** +``` +Hello, Mohammed! πŸ‘‹ +Have a wonderful day! +``` -### main.php +### 7. Error Handling - Invalid Command +```bash +php main.php invalid +``` +**Output:** +``` +Error: The command 'invalid' is not supported. +``` -The main application file shows: +## Key Learning Points -- **Runner setup**: Creating and configuring the CLI runner -- **Command registration**: Adding commands to the runner -- **Help command**: Including built-in help functionality -- **Execution**: Starting the CLI application +1. **Command Structure**: Commands extend `WebFiori\Cli\Command` and implement `exec()` method +2. **Arguments**: Optional arguments defined in constructor with default values +3. **Output**: Use `println()` for formatted output with emoji support +4. **Help Integration**: Commands automatically integrate with help system +5. **Error Handling**: Invalid commands show appropriate error messages +6. **Global Arguments**: `--ansi` flag works with all commands -## πŸ” Key Concepts +## Code Structure -### Command Structure ```php class HelloCommand extends Command { public function __construct() { - parent::__construct( - 'hello', // Command name - ['--name' => [...]], // Arguments - 'A simple greeting command' // Description - ); + parent::__construct('hello', [ + '--name' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DEFAULT => 'World', + ArgumentOption::DESCRIPTION => 'The name to greet (default: World)' + ] + ], 'A simple greeting command that says hello to someone'); } - + public function exec(): int { - // Command logic - return 0; // Success + $name = $this->getArgValue('--name'); + $this->println("Hello, %s! πŸ‘‹", $name); + $this->println("Have a wonderful day!"); + return 0; } } ``` -### Argument Definition -```php -'--name' => [ - Option::DESCRIPTION => 'Name to greet', - Option::OPTIONAL => true, - Option::DEFAULT => 'World' -] -``` - -### Output Methods -- `println()` - Print with newline -- `prints()` - Print without newline -- `success()` - Success message with green color -- `error()` - Error message with red color -- `info()` - Info message with blue color -- `warning()` - Warning message with yellow color - -## 🎨 Expected Output - -``` -$ php main.php hello -Hello, World! - -$ php main.php hello --name="Alice" -Hello, Alice! - -$ php main.php help -Usage: - command [arg1 arg2="val" arg3...] - -Available Commands: - help: Display CLI Help - hello: A simple greeting command -``` - -## πŸ”— Next Steps - -After mastering this example, move on to: -- **[02-arguments-and-options](../02-arguments-and-options/)** - Learn about complex argument handling -- **[03-user-input](../03-user-input/)** - Discover interactive input methods -- **[04-output-formatting](../04-output-formatting/)** - Explore advanced output formatting - -## πŸ’‘ Try This - -Experiment with the code: - -1. **Add more arguments**: Try adding `--greeting` option -2. **Change colors**: Use different output methods -3. **Add validation**: Ensure name is not empty -4. **Multiple greetings**: Support different languages - -```php -// Example enhancement -if ($name === 'WebFiori') { - $this->success("Hello, $name! Welcome to the CLI world!"); -} else { - $this->println("Hello, $name!"); -} -``` +This example serves as the foundation for understanding WebFiori CLI basics before moving to more advanced features. diff --git a/examples/01-basic-hello-world/main.php b/examples/01-basic-hello-world/main.php index 5952c78..1ff13bb 100644 --- a/examples/01-basic-hello-world/main.php +++ b/examples/01-basic-hello-world/main.php @@ -13,7 +13,6 @@ * - Basic application structure */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load the WebFiori CLI library @@ -26,13 +25,11 @@ $runner = new Runner(); // Register the help command (provides automatic help generation) -$runner->register(new HelpCommand()); // Register our custom hello command $runner->register(new HelloCommand()); // Set the default command to show help when no command is specified -$runner->setDefaultCommand('help'); // Start the CLI application and exit with the appropriate code exit($runner->start()); From 7e656ba9741a6f7197e34a45bc4c35cc9f6ca7ca Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Fri, 26 Sep 2025 18:23:16 +0300 Subject: [PATCH 02/12] docs: Updated Example 02 --- examples/02-arguments-and-options/README.md | 420 ++++++++++++++------ examples/02-arguments-and-options/main.php | 3 - 2 files changed, 292 insertions(+), 131 deletions(-) diff --git a/examples/02-arguments-and-options/README.md b/examples/02-arguments-and-options/README.md index 83909d7..0c3b8a9 100644 --- a/examples/02-arguments-and-options/README.md +++ b/examples/02-arguments-and-options/README.md @@ -1,188 +1,352 @@ # Arguments and Options Example -This example demonstrates comprehensive argument and option handling in WebFiori CLI commands. +This example demonstrates advanced argument handling, validation, and complex command logic using WebFiori CLI library. -## 🎯 What You'll Learn +## Features Demonstrated -- Different types of arguments (required, optional, with defaults) -- Argument validation and constraints -- Working with multiple data types -- Argument value processing -- Error handling for invalid arguments +- Required and optional arguments +- Argument validation with allowed values +- Custom validation logic (email, age ranges) +- Boolean flags +- Default values +- Precision control +- Verbose output modes +- Error handling and validation messages -## πŸ“ Files +## Files -- `CalculatorCommand.php` - Mathematical calculator with various argument types +- `main.php` - Application entry point and runner setup +- `CalculatorCommand.php` - Mathematical calculator with multiple operations - `UserProfileCommand.php` - User profile creator with validation -- `main.php` - Application entry point -- `README.md` - This documentation -## πŸš€ Running the Examples +## Usage Examples -### Calculator Command +### General Help ```bash -# Basic addition -php main.php calc --operation=add --numbers="5,10,15" +php main.php +# or +php main.php help +``` +**Output:** +``` +Usage: + command [arg1 arg2="val" arg3...] + +Global Arguments: + --ansi:[Optional] Force the use of ANSI output. +Available Commands: + help: Display CLI Help. To display help for specific command, use the argument "--command" with this command. + calc: Performs mathematical calculations on a list of numbers + profile: Creates a user profile with validation and formatting +``` -# Division with precision -php main.php calc --operation=divide --numbers="22,7" --precision=3 +## Calculator Command Examples -# Get help for calculator -php main.php help --command-name=calc +### Show Calculator Help +```bash +php main.php help --command=calc +``` +**Output:** +``` + calc: Performs mathematical calculations on a list of numbers + Supported Arguments: + --operation: Mathematical operation to perform + --numbers: Comma-separated list of numbers (e.g., "1,2,3,4") + --precision:[Optional][Default = '2'] Number of decimal places for the result + --verbose:[Optional] Show detailed calculation steps ``` -### User Profile Command -```bash -# Create a user profile -php main.php profile --name="John Doe" --email="john@example.com" --age=30 +### Basic Operations -# With optional fields -php main.php profile --name="Jane Smith" --email="jane@example.com" --age=25 --role=admin --active +#### Addition +```bash +php main.php calc --numbers=1,2,3,4,5 --operation=add +``` +**Output:** +``` +βœ… Performing add on: 1, 2, 3, 4, 5 +πŸ“Š Result: 15.00 +``` -# Get help for profile -php main.php help --command-name=profile +#### Subtraction +```bash +php main.php calc --numbers=10,3,2 --operation=subtract +``` +**Output:** +``` +βœ… Performing subtract on: 10, 3, 2 +πŸ“Š Result: 5.00 ``` -## πŸ“– Code Explanation +#### Multiplication +```bash +php main.php calc --numbers=2,3,4 --operation=multiply +``` +**Output:** +``` +βœ… Performing multiply on: 2, 3, 4 +πŸ“Š Result: 24.00 +``` -### Argument Types Demonstrated +#### Division +```bash +php main.php calc --numbers=100,5,2 --operation=divide +``` +**Output:** +``` +βœ… Performing divide on: 100, 5, 2 +πŸ“Š Result: 10.00 +``` -#### Required Arguments -```php -'--name' => [ - Option::DESCRIPTION => 'User full name', - Option::OPTIONAL => false // Required argument -] +#### Average +```bash +php main.php calc --numbers=10,20,30,40,50 --operation=average +``` +**Output:** +``` +βœ… Performing average on: 10, 20, 30, 40, 50 +πŸ“Š Result: 30.00 ``` -#### Optional Arguments with Defaults -```php -'--precision' => [ - Option::DESCRIPTION => 'Decimal precision for results', - Option::OPTIONAL => true, - Option::DEFAULT => '2' -] +### Advanced Calculator Features + +#### Custom Precision +```bash +php main.php calc --numbers=10,3 --operation=divide --precision=4 +``` +**Output:** +``` +βœ… Performing divide on: 10, 3 +πŸ“Š Result: 3.3333 ``` -#### Arguments with Value Constraints -```php -'--operation' => [ - Option::DESCRIPTION => 'Mathematical operation to perform', - Option::OPTIONAL => false, - Option::VALUES => ['add', 'subtract', 'multiply', 'divide', 'average'] -] +#### Verbose Mode +```bash +php main.php calc --numbers=5,10,15 --operation=add --verbose +``` +**Output:** ``` +πŸ”’ Operation: Add +πŸ“Š Numbers: 5, 10, 15 +🎯 Precision: 2 decimal places -#### Boolean Flags -```php -'--active' => [ - Option::DESCRIPTION => 'Mark user as active', - Option::OPTIONAL => true - // No default value = boolean flag -] +βœ… Performing add on: 5, 10, 15 +πŸ“Š Result: 30.00 + +πŸ“ˆ Statistics: + β€’ Count: 3 + β€’ Min: 5 + β€’ Max: 15 + β€’ Average: 10.00 ``` -### Validation Patterns +### Calculator Error Handling -#### Email Validation -```php -private function validateEmail(string $email): bool { - return filter_var($email, FILTER_VALIDATE_EMAIL) !== false; -} +#### Invalid Operation +```bash +php main.php calc --numbers=1,2,3 --operation=invalid +``` +**Output:** +``` +Error: The following argument(s) have invalid values: '--operation' +Info: Allowed values for the argument '--operation': +add +subtract +multiply +divide +average ``` -#### Number List Processing -```php -private function parseNumbers(string $numbers): array { - $nums = array_map('trim', explode(',', $numbers)); - return array_map('floatval', array_filter($nums, 'is_numeric')); -} +#### Missing Required Arguments +```bash +php main.php calc --numbers=1,2,3 +``` +**Output:** +``` +Error: The following required argument(s) are missing: '--operation' ``` -#### Age Range Validation -```php -private function validateAge(int $age): bool { - return $age >= 13 && $age <= 120; -} +#### Division by Zero +```bash +php main.php calc --numbers=10,0 --operation=divide +``` +**Output:** +``` +❌ Calculation error: Division by zero is not allowed ``` -## πŸ” Key Features +## Profile Command Examples -### 1. Data Type Handling -- **Strings**: Names, emails, descriptions -- **Numbers**: Integers, floats, calculations -- **Booleans**: Flags and switches -- **Arrays**: Comma-separated values +### Show Profile Help +```bash +php main.php help --command=profile +``` +**Output:** +``` + profile: Creates a user profile with validation and formatting + Supported Arguments: + --name: User full name (required) + --email: User email address (required) + --age: User age (13-120, required) + --role:[Optional][Default = 'user'] User role in the system + --department:[Optional][Default = 'General'] User department + --active:[Optional] Mark user as active (flag) + --skills:[Optional] Comma-separated list of skills + --bio:[Optional] Short biography (max 200 characters) +``` -### 2. Validation Strategies -- **Format validation**: Email, phone, etc. -- **Range validation**: Age, scores, etc. -- **Enum validation**: Predefined choices -- **Custom validation**: Business logic +### Basic Profile Creation +```bash +php main.php profile --name="Ahmed Hassan" --email=ahmed@example.com --age=28 +``` +**Output:** +``` +πŸ”§ Creating User Profile... -### 3. Error Handling -- **Missing required arguments** -- **Invalid argument values** -- **Type conversion errors** -- **Business rule violations** +βœ… User Profile Created Successfully! -## 🎨 Expected Output +πŸ‘€ Name: Ahmed Hassan +πŸ“§ Email: ahmed@example.com +πŸŽ‚ Age: 28 +πŸ‘” Role: user +🏒 Department: General +πŸ”΄ Status: inactive + +πŸ’Ύ Saving profile to database... +βœ… Profile saved successfully! User ID: 5404 +πŸ“Š Profile Summary: + β€’ User ID: 5404 + β€’ Role: User + β€’ Skills: 0 + β€’ Status: Inactive +``` -### Calculator Examples +### Full Profile with All Options +```bash +php main.php profile --name="Fatima Al-Zahra" --email=fatima@example.com --age=25 --role=admin --department=Engineering --active --skills="PHP,JavaScript,Python" --bio="Senior developer with 5 years experience" ``` -$ php main.php calc --operation=add --numbers="5,10,15" -βœ… Performing addition on: 5, 10, 15 -πŸ“Š Result: 30.00 +**Output:** +``` +πŸ”§ Creating User Profile... + +βœ… User Profile Created Successfully! -$ php main.php calc --operation=divide --numbers="22,7" --precision=4 -βœ… Performing division on: 22, 7 -πŸ“Š Result: 3.1429 +πŸ‘€ Name: Fatima Al-Zahra +πŸ“§ Email: fatima@example.com +πŸŽ‚ Age: 25 +πŸ‘” Role: admin +🏒 Department: Engineering +🟒 Status: active +πŸ› οΈ Skills: PHP, JavaScript, Python +πŸ“ Bio: Senior developer with 5 years experience + +πŸ’Ύ Saving profile to database... +βœ… Profile saved successfully! User ID: 2958 +πŸ“Š Profile Summary: + β€’ User ID: 2958 + β€’ Role: Admin + β€’ Skills: 3 + β€’ Status: Active ``` -### Profile Examples +### Profile Validation Examples + +#### Invalid Email +```bash +php main.php profile --name="Mohammed Ali" --email=invalid-email --age=30 ``` -$ php main.php profile --name="John Doe" --email="john@example.com" --age=30 -βœ… User Profile Created Successfully! +**Output:** +``` +πŸ”§ Creating User Profile... -πŸ‘€ Name: John Doe -πŸ“§ Email: john@example.com -πŸŽ‚ Age: 30 -πŸ‘” Role: user -🟒 Status: inactive +❌ Invalid email format: invalid-email ``` -### Error Examples +#### Invalid Age Range +```bash +php main.php profile --name="Sara Ahmed" --email=sara@example.com --age=150 +``` +**Output:** ``` -$ php main.php calc --operation=invalid --numbers="5,10" -❌ Error: Invalid operation 'invalid'. Must be one of: add, subtract, multiply, divide, average +πŸ”§ Creating User Profile... -$ php main.php profile --name="John" --email="invalid-email" --age=30 -❌ Error: Invalid email format: invalid-email +❌ Age must be between 13 and 120, got: 150 ``` -## πŸ”— Next Steps +#### Missing Required Arguments +```bash +php main.php profile --name="Omar Hassan" +``` +**Output:** +``` +Error: The following required argument(s) are missing: '--email', '--age' +``` -After mastering this example, move on to: -- **[03-user-input](../03-user-input/)** - Interactive input and validation -- **[04-output-formatting](../04-output-formatting/)** - Advanced output styling -- **[05-interactive-commands](../05-interactive-commands/)** - Building interactive workflows +## Key Learning Points -## πŸ’‘ Try This +1. **Required vs Optional Arguments**: Use `ArgumentOption::OPTIONAL => false` for required fields +2. **Argument Validation**: Use `ArgumentOption::VALUES` array to restrict allowed values +3. **Default Values**: Set defaults with `ArgumentOption::DEFAULT` +4. **Boolean Flags**: Arguments without values act as boolean flags +5. **Custom Validation**: Implement business logic validation in `exec()` method +6. **Error Handling**: Return appropriate exit codes (0 = success, 1+ = error) +7. **User Feedback**: Use `success()`, `error()`, `info()` for colored output +8. **Complex Logic**: Commands can perform multiple operations and validations -Experiment with the code: +## Code Structure Examples -1. **Add new operations**: Implement power, modulo, or factorial -2. **Enhanced validation**: Add phone number or URL validation -3. **Complex data types**: Handle JSON or CSV input -4. **Argument dependencies**: Make some arguments depend on others +### Calculator Command Structure +```php +class CalculatorCommand extends Command { + public function __construct() { + parent::__construct('calc', [ + '--operation' => [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::VALUES => ['add', 'subtract', 'multiply', 'divide', 'average'], + ArgumentOption::DESCRIPTION => 'Mathematical operation to perform' + ], + '--numbers' => [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'Comma-separated list of numbers' + ], + '--precision' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DEFAULT => '2', + ArgumentOption::DESCRIPTION => 'Number of decimal places' + ], + '--verbose' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Show detailed calculation steps' + ] + ], 'Performs mathematical calculations on a list of numbers'); + } +} +``` +### Profile Command Structure ```php -// Example: Add power operation -case 'power': - if (count($numbers) !== 2) { - $this->error('Power operation requires exactly 2 numbers (base, exponent)'); - return 1; +class UserProfileCommand extends Command { + public function __construct() { + parent::__construct('profile', [ + '--name' => [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'User full name (required)' + ], + '--email' => [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'User email address (required)' + ], + '--age' => [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'User age (13-120, required)' + ], + '--active' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Mark user as active (flag)' + ] + ], 'Creates a user profile with validation and formatting'); } - $result = pow($numbers[0], $numbers[1]); - break; +} ``` + +This example demonstrates advanced CLI application development with proper validation, error handling, and user experience design. diff --git a/examples/02-arguments-and-options/main.php b/examples/02-arguments-and-options/main.php index 1d8766d..7d3857f 100644 --- a/examples/02-arguments-and-options/main.php +++ b/examples/02-arguments-and-options/main.php @@ -11,7 +11,6 @@ * - Error handling and user feedback */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load dependencies @@ -23,12 +22,10 @@ $runner = new Runner(); // Register commands -$runner->register(new HelpCommand()); $runner->register(new CalculatorCommand()); $runner->register(new UserProfileCommand()); // Set default command -$runner->setDefaultCommand('help'); // Start the application exit($runner->start()); From 97865876d154a80dc4e65ae1c793a43e1d5a8c44 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Fri, 26 Sep 2025 18:33:50 +0300 Subject: [PATCH 03/12] docs: Updated Example 04 --- WebFiori/Cli/Command.php | 18 + WebFiori/Cli/KeysMap.php | 12 +- examples/03-user-input/README.md | 473 +++++++++++++++-------- examples/03-user-input/SimpleCommand.php | 39 ++ examples/03-user-input/SurveyCommand.php | 69 +++- examples/03-user-input/main.php | 9 +- 6 files changed, 445 insertions(+), 175 deletions(-) create mode 100644 examples/03-user-input/SimpleCommand.php diff --git a/WebFiori/Cli/Command.php b/WebFiori/Cli/Command.php index 39e85ec..64377e7 100644 --- a/WebFiori/Cli/Command.php +++ b/WebFiori/Cli/Command.php @@ -588,6 +588,24 @@ public function getInput(string $prompt, ?string $default = null, ?InputValidato public function getInputStream() : InputStream { return $this->inputStream; } + + /** + * Check if the current input stream supports interactive input. + * + * @return bool True if the input stream supports interactive input (real-time user interaction), + * false otherwise (files, pipes, arrays, etc.) + */ + public function supportsInteractiveInput(): bool { + $stream = $this->getInputStream(); + + // Only StdIn with tty supports true interaction + if ($stream instanceof Streams\StdIn) { + return function_exists('posix_isatty') && posix_isatty(STDIN); + } + + // All other stream types are non-interactive + return false; + } /** * Returns the name of the command. * diff --git a/WebFiori/Cli/KeysMap.php b/WebFiori/Cli/KeysMap.php index 289fe6f..7f9fbf1 100644 --- a/WebFiori/Cli/KeysMap.php +++ b/WebFiori/Cli/KeysMap.php @@ -53,7 +53,17 @@ class KeysMap { * * */ - public static function map(string $ch) : string { + public static function map($ch) : string { + // Handle end-of-stream case for any input type + if ($ch === false || $ch === null) { + return "\n"; // Treat as Enter key + } + + // Ensure we have a string + if (!is_string($ch)) { + $ch = (string)$ch; + } + $keyMap = self::KEY_MAP; if (isset($keyMap[$ch])) { diff --git a/examples/03-user-input/README.md b/examples/03-user-input/README.md index c8a1068..72a9cad 100644 --- a/examples/03-user-input/README.md +++ b/examples/03-user-input/README.md @@ -1,222 +1,375 @@ # User Input Example -This example demonstrates interactive user input handling, validation, and different input methods in WebFiori CLI. +This example demonstrates comprehensive user input handling and validation techniques using WebFiori CLI library. -## 🎯 What You'll Learn +## Features Demonstrated -- Interactive input collection with prompts -- Input validation and custom validators -- Different input types (text, numbers, selections, confirmations) -- Password input handling -- Multi-step interactive workflows -- Error handling and retry mechanisms +- Interactive input collection with defaults +- Input validation and error handling +- Email format validation +- Age range validation (13-120) +- Country selection from numbered lists +- Programming language selection with y/N prompts +- Experience level selection +- Survey summary and statistics +- Pre-filled values and quick mode options -## πŸ“ Files +## Files -- `SurveyCommand.php` - Interactive survey with various input types -- `SetupWizardCommand.php` - Multi-step configuration wizard -- `QuizCommand.php` - Interactive quiz with scoring -- `main.php` - Application entry point -- `README.md` - This documentation +- `main.php` - Application entry point and runner setup +- `SurveyCommand.php` - Interactive survey with comprehensive input handling +- `SimpleCommand.php` - Non-interactive demo survey -## πŸš€ Running the Examples +## Usage Examples -### Survey Command +### General Help ```bash -# Start interactive survey -php main.php survey - -# Survey with pre-filled name -php main.php survey --name="John Doe" +php main.php +# or +php main.php help +``` +**Output:** +``` +Usage: + command [arg1 arg2="val" arg3...] + +Global Arguments: + --ansi:[Optional] Force the use of ANSI output. +Available Commands: + help: Display CLI Help. To display help for specific command, use the argument "--command" with this command. + survey: Interactive survey demonstrating various input methods + simple-survey: A simple survey without interactive input ``` -### Setup Wizard -```bash -# Run configuration wizard -php main.php setup +## Simple Survey Command -# Skip to specific step -php main.php setup --step=database +### Show Simple Survey Help +```bash +php main.php help --command=simple-survey +``` +**Output:** +``` + simple-survey: A simple survey without interactive input ``` -### Quiz Command +### Run Simple Survey Demo ```bash -# Start the quiz -php main.php quiz - -# Quiz with specific difficulty -php main.php quiz --difficulty=hard +php main.php simple-survey ``` +**Output:** +``` +πŸ“‹ Simple Survey Demo +==================== -## πŸ“– Code Explanation - -### Input Methods Demonstrated +βœ… Survey completed! Here's your data: -#### Basic Text Input -```php -$name = $this->getInput('Enter your name: ', 'Anonymous'); +Name: John Doe +Email: john@example.com +Age: 30 +Country: Canada +Languages: PHP, Python +Experience: Advanced ``` -#### Validated Input -```php -$email = $this->getInput('Enter email: ', null, new InputValidator(function($input) { - return filter_var($input, FILTER_VALIDATE_EMAIL) !== false; -}, 'Please enter a valid email address')); -``` +## Interactive Survey Command -#### Numeric Input -```php -$age = $this->readInteger('Enter your age: ', 25); -$score = $this->readFloat('Enter score: ', 0.0); +### Show Survey Help +```bash +php main.php help --command=survey ``` - -#### Selection Input -```php -$choice = $this->select('Choose your favorite color:', [ - 'Red', 'Green', 'Blue', 'Yellow' -], 0); // Default to first option +**Output:** ``` - -#### Confirmation Input -```php -$confirmed = $this->confirm('Do you want to continue?', true); + survey: Interactive survey demonstrating various input methods + Supported Arguments: + --name:[Optional] Pre-fill your name (optional) + --quick:[Optional] Use quick mode with minimal questions ``` -#### Password Input (Simulated) -```php -$password = $this->getInput('Enter password: '); -// Note: Real password input would hide characters +### Basic Interactive Survey +```bash +php main.php survey +``` +**Sample Output:** ``` +πŸ“‹ Welcome to the Interactive Survey! +===================================== -### Custom Validation Examples +πŸ“ Basic Information +------------------- +πŸ‘€ What's your name? Enter = 'Anonymous' +πŸ“§ Enter your email: +πŸŽ‚ How old are you? Enter = '25' -#### Email Validation -```php -new InputValidator(function($input) { - return filter_var($input, FILTER_VALIDATE_EMAIL) !== false; -}, 'Invalid email format') +🎯 Preferences +------------- +🌍 Select your country: +0: United States +1: Canada +2: United Kingdom +3: Australia +4: Germany +5: France +6: Japan +7: Other +Enter number (0-7) Enter = '0' + +πŸ’» Programming experience: +Do you know PHP? (y/N) Enter = 'n' +Do you know JavaScript? (y/N) Enter = 'n' +Do you know Python? (y/N) Enter = 'n' +Do you know Java? (y/N) Enter = 'n' +Do you know C++? (y/N) Enter = 'n' +Do you know Go? (y/N) Enter = 'n' +Do you know Rust? (y/N) Enter = 'n' + +πŸ“ˆ Your programming experience level: +0: Beginner +1: Intermediate +2: Advanced +3: Expert +Enter number (0-3) Enter = '1' + +πŸ“‹ Additional Details +-------------------- +🎨 What's your favorite color? Enter = 'Blue' +⭐ Rate your satisfaction with CLI tools (1-10): Enter = '7' +πŸ’¬ Any additional feedback? (optional): Enter = '' +πŸ“§ Subscribe to our newsletter?(y/N) + +πŸ“Š Survey Summary +================ +πŸ‘€ Name: Anonymous +πŸ“§ Email: user@example.com +πŸŽ‚ Age: 25 +🌍 Country: United States +πŸ“ˆ Experience: Intermediate +πŸ’» Languages: None specified +🎨 Favorite Color: Blue +⭐ Satisfaction: 7/10 β­β­β­β­β­β­β­β˜†β˜†β˜† +πŸ“§ Newsletter: No + +Submit this survey?(Y/n) +πŸ“€ Submitting survey... +... +βœ… Thank you for completing the survey! +πŸ“‹ Survey ID: SRV-20250926-1234 + +πŸ“ˆ Quick Stats: + β€’ Questions answered: 9 + β€’ Languages known: 0 + β€’ Completion time: ~5 minutes ``` -#### Range Validation -```php -new InputValidator(function($input) { - $num = (int)$input; - return $num >= 1 && $num <= 10; -}, 'Please enter a number between 1 and 10') +### Survey with Pre-filled Name +```bash +php main.php survey --name="Ahmed Hassan" +``` +**Sample Output:** ``` +πŸ“‹ Welcome to the Interactive Survey! +===================================== + +πŸ“ Basic Information +------------------- +πŸ‘€ What's your name? Enter = 'Ahmed Hassan' +πŸ“§ Enter your email: +πŸŽ‚ How old are you? Enter = '25' + +[... continues with survey flow ...] + +πŸ“Š Survey Summary +================ +πŸ‘€ Name: Ahmed Hassan +πŸ“§ Email: ahmed@example.com +πŸŽ‚ Age: 25 +🌍 Country: Canada +πŸ“ˆ Experience: Advanced +πŸ’» Languages: PHP, JavaScript, Python +🎨 Favorite Color: Blue +⭐ Satisfaction: 9/10 β­β­β­β­β­β­β­β­β­β˜† +πŸ“§ Newsletter: No -#### Pattern Validation -```php -new InputValidator(function($input) { - return preg_match('/^[A-Za-z\s]+$/', $input); -}, 'Only letters and spaces allowed') +βœ… Thank you for completing the survey! +πŸ“‹ Survey ID: SRV-20250926-3555 + +πŸ“ˆ Quick Stats: + β€’ Questions answered: 9 + β€’ Languages known: 3 + β€’ Completion time: ~3 minutes +πŸŽ‰ Great to hear you're satisfied with CLI tools! ``` -## πŸ” Key Features +### Quick Mode Survey +```bash +php main.php survey --quick +``` +**Sample Output:** +``` +πŸ“‹ Welcome to the Interactive Survey! +===================================== -### 1. Input Types -- **Text input**: Names, descriptions, free text -- **Numeric input**: Integers, floats with validation -- **Selection input**: Choose from predefined options -- **Boolean input**: Yes/no confirmations -- **Validated input**: Custom validation rules +⚑ Running in quick mode - fewer questions! -### 2. Validation Strategies -- **Built-in validators**: Email, numeric, etc. -- **Custom validators**: Business logic validation -- **Range validation**: Min/max values -- **Pattern matching**: Regex validation -- **Retry mechanisms**: Allow user to correct input +πŸ“ Basic Information +------------------- +πŸ‘€ What's your name? Enter = 'Anonymous' +πŸ“§ Enter your email: +πŸŽ‚ How old are you? Enter = '25' -### 3. User Experience -- **Default values**: Sensible defaults for quick input -- **Clear prompts**: Descriptive input requests -- **Error messages**: Helpful validation feedback -- **Progress indication**: Multi-step workflow progress -- **Confirmation steps**: Verify important actions +🎯 Preferences +------------- +🌍 Select your country: +[... country selection ...] -## 🎨 Expected Output +πŸ’» Programming experience: +[... language selection ...] -### Survey Example -``` -πŸ“‹ Welcome to the Interactive Survey! +πŸ“ˆ Your programming experience level: +[... experience selection ...] -πŸ‘€ What's your name? [Anonymous]: John Doe -πŸ“§ Enter your email: john@example.com -πŸŽ‚ How old are you? [25]: 30 -🌍 Select your country: -0: United States -1: Canada -2: United Kingdom -3: Australia -Your choice [0]: 1 +πŸ“Š Survey Summary +================ +πŸ‘€ Name: Anonymous +πŸ“§ Email: user@example.com +πŸŽ‚ Age: 25 +🌍 Country: United States +πŸ“ˆ Experience: Intermediate +πŸ’» Languages: None specified βœ… Thank you for completing the survey! +πŸ“‹ Survey ID: SRV-20250926-1364 -πŸ“Š Survey Results: - β€’ Name: John Doe - β€’ Email: john@example.com - β€’ Age: 30 - β€’ Country: Canada +πŸ“ˆ Quick Stats: + β€’ Questions answered: 6 + β€’ Languages known: 0 + β€’ Completion time: ~5 minutes ``` -### Setup Wizard Example +### Combined Options +```bash +php main.php survey --name="Fatima Al-Zahra" --quick +``` +**Sample Output:** ``` -πŸ”§ Application Setup Wizard +πŸ“‹ Welcome to the Interactive Survey! +===================================== -Step 1/4: Basic Configuration -πŸ“ Application name [MyApp]: AwesomeApp -🌐 Environment (dev/staging/prod) [dev]: prod +⚑ Running in quick mode - fewer questions! -Step 2/4: Database Configuration -πŸ—„οΈ Database host [localhost]: db.example.com -πŸ‘€ Database username: admin -πŸ”‘ Database password: ******** +πŸ“ Basic Information +------------------- +πŸ‘€ What's your name? Enter = 'Fatima Al-Zahra' +[... continues with quick survey flow ...] -βœ… Setup completed successfully! -``` +πŸ“Š Survey Summary +================ +πŸ‘€ Name: Fatima Al-Zahra +πŸ“§ Email: fatima@example.com +πŸŽ‚ Age: 25 +🌍 Country: United States +πŸ“ˆ Experience: Intermediate +πŸ’» Languages: None specified -### Quiz Example -``` -🧠 Welcome to the Knowledge Quiz! +βœ… Thank you for completing the survey! +πŸ“‹ Survey ID: SRV-20250926-1871 -Question 1/5: What is the capital of France? -0: London -1: Berlin -2: Paris -3: Madrid -Your answer: 2 -βœ… Correct! +πŸ“ˆ Quick Stats: + β€’ Questions answered: 6 + β€’ Languages known: 0 + β€’ Completion time: ~3 minutes +``` -Question 2/5: What is 15 + 27? -Enter your answer: 42 -βœ… Correct! +## Error Handling Examples -πŸŽ‰ Quiz completed! -πŸ“Š Final Score: 5/5 (100%) -πŸ† Excellent work! +### Invalid Command +```bash +php main.php invalid +``` +**Output:** +``` +Error: The command 'invalid' is not supported. ``` -## πŸ”— Next Steps +### Input Validation +The survey includes several validation mechanisms: -After mastering this example, move on to: -- **[04-output-formatting](../04-output-formatting/)** - Advanced output styling -- **[05-interactive-commands](../05-interactive-commands/)** - Complex interactive workflows -- **[07-progress-bars](../07-progress-bars/)** - Visual progress indicators +- **Email validation**: Prompts for valid email format +- **Age validation**: Ensures age is between 13-120 +- **Country selection**: Validates numeric input within range +- **Experience level**: Validates numeric input for experience level -## πŸ’‘ Try This +## Key Learning Points -Experiment with the code: +1. **Interactive Input**: Use `getInput()` for collecting user data with defaults +2. **Input Validation**: Implement custom validation logic for business rules +3. **User Experience**: Provide clear prompts, defaults, and error messages +4. **Data Collection**: Structure complex surveys with multiple sections +5. **Conditional Logic**: Use flags like `--quick` to modify behavior +6. **Pre-filled Data**: Use command arguments to pre-populate fields +7. **Summary Display**: Format collected data in readable summaries +8. **Progress Feedback**: Show completion statistics and survey IDs -1. **Add new input types**: Date input, URL validation -2. **Create complex workflows**: Multi-branch decision trees -3. **Add input history**: Remember previous inputs -4. **Implement autocomplete**: Suggest completions for input +## Code Structure Examples + +### Survey Command Structure +```php +class SurveyCommand extends Command { + public function __construct() { + parent::__construct('survey', [ + '--name' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Pre-fill your name (optional)' + ], + '--quick' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Use quick mode with minimal questions' + ] + ], 'Interactive survey demonstrating various input methods'); + } + + public function exec(): int { + $this->println('πŸ“‹ Welcome to the Interactive Survey!'); + + // Collect basic information + $this->collectBasicInfo(); + + // Collect preferences + $this->collectPreferences(); + + // Show summary and submit + $this->showSummaryAndSubmit(); + + return 0; + } +} +``` +### Input Collection with Validation ```php -// Example: Date input validation -new InputValidator(function($input) { - $date = DateTime::createFromFormat('Y-m-d', $input); - return $date && $date->format('Y-m-d') === $input; -}, 'Please enter date in YYYY-MM-DD format') +private function collectBasicInfo() { + // Name with pre-fill option + $preFillName = $this->getArgValue('--name'); + $name = $this->getInput('πŸ‘€ What\'s your name?', $preFillName ?? 'Anonymous'); + + // Email with validation + do { + $email = $this->getInput('πŸ“§ Enter your email:'); + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $this->error('Please enter a valid email address'); + } + } while (!filter_var($email, FILTER_VALIDATE_EMAIL)); + + // Age with validation + $age = $this->getInput('πŸŽ‚ How old are you?', '25'); + $age = is_numeric($age) ? (int)$age : 25; +} ``` + +## Technical Notes + +- **Interactive Limitations**: The survey works best in interactive mode; piped input may cause issues with the underlying input handling system +- **Alternative Approach**: The `simple-survey` command provides a non-interactive demonstration +- **Input Validation**: Multiple validation layers ensure data quality +- **User Experience**: Rich formatting with emojis and clear section divisions + +This example demonstrates advanced user input handling suitable for complex CLI applications requiring data collection and validation. diff --git a/examples/03-user-input/SimpleCommand.php b/examples/03-user-input/SimpleCommand.php new file mode 100644 index 0000000..bf26df7 --- /dev/null +++ b/examples/03-user-input/SimpleCommand.php @@ -0,0 +1,39 @@ +println('πŸ“‹ Simple Survey Demo'); + $this->println('===================='); + + // Simulate collecting data + $data = [ + 'name' => 'John Doe', + 'email' => 'john@example.com', + 'age' => 30, + 'country' => 'Canada', + 'languages' => ['PHP', 'Python'], + 'experience' => 'Advanced' + ]; + + $this->println(); + $this->success('Survey completed! Here\'s your data:'); + $this->println(); + + foreach ($data as $key => $value) { + if (is_array($value)) { + $this->println('%s: %s', ucfirst($key), implode(', ', $value)); + } else { + $this->println('%s: %s', ucfirst($key), $value); + } + } + + return 0; + } +} diff --git a/examples/03-user-input/SurveyCommand.php b/examples/03-user-input/SurveyCommand.php index a709443..1eb9df4 100644 --- a/examples/03-user-input/SurveyCommand.php +++ b/examples/03-user-input/SurveyCommand.php @@ -35,6 +35,12 @@ public function exec(): int { $this->println("====================================="); $this->println(); + // Check if we can run interactive survey + if (!$this->supportsInteractiveInput()) { + $this->warning("Non-interactive input detected. Using simplified survey mode."); + return $this->runSimplifiedSurvey(); + } + $quickMode = $this->isArgProvided('--quick'); if ($quickMode) { @@ -88,10 +94,8 @@ private function collectBasicInfo(): void { ); // Age with numeric validation - $this->surveyData['age'] = $this->readInteger( - 'πŸŽ‚ How old are you?', - 25 - ); + $age = $this->getInput('πŸŽ‚ How old are you?', '25'); + $this->surveyData['age'] = is_numeric($age) ? (int)$age : 25; // Validate age range if ($this->surveyData['age'] < 13 || $this->surveyData['age'] > 120) { @@ -160,7 +164,14 @@ private function collectPreferences(): void { 'Other' ]; - $countryIndex = $this->select('🌍 Select your country:', $countries, 0); + // Display countries and get selection + $this->println('🌍 Select your country:'); + foreach ($countries as $i => $country) { + $this->println("%d: %s", $i, $country); + } + $countryInput = $this->getInput('Enter number (0-7)', '0'); + $countryIndex = is_numeric($countryInput) ? (int)$countryInput : 0; + $countryIndex = max(0, min($countryIndex, count($countries) - 1)); $this->surveyData['country'] = $countries[$countryIndex]; // Programming languages (multiple choice simulation) @@ -171,7 +182,8 @@ private function collectPreferences(): void { $knownLanguages = []; foreach ($languages as $lang) { - if ($this->confirm("Do you know $lang?", false)) { + $answer = $this->getInput("Do you know $lang? (y/N)", 'n'); + if (strtolower($answer) === 'y' || strtolower($answer) === 'yes') { $knownLanguages[] = $lang; } } @@ -181,7 +193,13 @@ private function collectPreferences(): void { // Experience level $this->println(); $experienceLevels = ['Beginner', 'Intermediate', 'Advanced', 'Expert']; - $expIndex = $this->select('πŸ“ˆ Your programming experience level:', $experienceLevels, 1); + $this->println('πŸ“ˆ Your programming experience level:'); + foreach ($experienceLevels as $i => $level) { + $this->println("%d: %s", $i, $level); + } + $expInput = $this->getInput('Enter number (0-3)', '1'); + $expIndex = is_numeric($expInput) ? (int)$expInput : 1; + $expIndex = max(0, min($expIndex, count($experienceLevels) - 1)); $this->surveyData['experience'] = $experienceLevels[$expIndex]; $this->println(); @@ -240,6 +258,43 @@ private function submitSurvey(): void { usleep(500000); // 0.5 seconds } $this->println(); + } + + /** + * Run simplified survey for non-interactive input streams. + */ + private function runSimplifiedSurvey(): int { + $this->println(); + + // Use pre-filled name or default + $name = $this->getArgValue('--name') ?? 'Anonymous User'; + + // Simulate survey data collection + $this->surveyData = [ + 'name' => $name, + 'email' => 'user@example.com', + 'age' => 25, + 'country' => 'United States', + 'languages' => ['PHP'], + 'experience' => 'Intermediate', + 'color' => 'Blue', + 'satisfaction' => 8, + 'feedback' => '', + 'newsletter' => false + ]; + + $this->success("πŸ“Š Survey completed in simplified mode!"); + $this->println(); + + // Show summary + $this->showSummary(); + + // Auto-submit in simplified mode + $this->info("πŸ“€ Auto-submitting survey..."); + $surveyId = 'SRV-' . date('Ymd') . '-' . rand(1000, 9999); + $this->success("βœ… Survey submitted! ID: $surveyId"); + + return 0; $this->success("βœ… Thank you for completing the survey!"); diff --git a/examples/03-user-input/main.php b/examples/03-user-input/main.php index 41434fb..422d74d 100644 --- a/examples/03-user-input/main.php +++ b/examples/03-user-input/main.php @@ -11,26 +11,21 @@ * - Error handling and user feedback */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load dependencies require_once '../../vendor/autoload.php'; require_once 'SurveyCommand.php'; -require_once 'SetupWizardCommand.php'; -require_once 'QuizCommand.php'; +require_once 'SimpleCommand.php'; // Create and configure the CLI runner $runner = new Runner(); // Register commands -$runner->register(new HelpCommand()); $runner->register(new SurveyCommand()); -$runner->register(new SetupWizardCommand()); -$runner->register(new QuizCommand()); +$runner->register(new SimpleCommand()); // Set default command -$runner->setDefaultCommand('help'); // Start the application exit($runner->start()); From ba9fb369b40956037be5bd9e7085d82798cde688 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Fri, 26 Sep 2025 18:44:14 +0300 Subject: [PATCH 04/12] docs: Updated Example 04 --- .../FormattingDemoCommand.php | 3 +- examples/04-output-formatting/README.md | 683 +++++++++++++----- examples/04-output-formatting/main.php | 3 - 3 files changed, 505 insertions(+), 184 deletions(-) diff --git a/examples/04-output-formatting/FormattingDemoCommand.php b/examples/04-output-formatting/FormattingDemoCommand.php index e89d7cc..45eab7e 100644 --- a/examples/04-output-formatting/FormattingDemoCommand.php +++ b/examples/04-output-formatting/FormattingDemoCommand.php @@ -685,7 +685,8 @@ private function showPercentageProgress(): void { $bar = str_repeat('β–“', $filled).str_repeat('β–‘', $empty); - $this->prints("\rProgress: [$bar] $percent%"); + echo "\rProgress: [$bar] $percent%"; + flush(); usleep(150000); // 0.15 seconds } diff --git a/examples/04-output-formatting/README.md b/examples/04-output-formatting/README.md index e39c5e3..b57f0c7 100644 --- a/examples/04-output-formatting/README.md +++ b/examples/04-output-formatting/README.md @@ -1,241 +1,564 @@ # Output Formatting Example -This example demonstrates advanced output formatting, ANSI colors, styling, and visual elements in WebFiori CLI. +This example demonstrates comprehensive output formatting and ANSI styling techniques using WebFiori CLI library. -## 🎯 What You'll Learn +## Features Demonstrated -- ANSI color codes and text styling -- Creating tables and formatted layouts -- Progress bars and visual indicators -- Custom formatting functions -- Terminal cursor manipulation -- Creating beautiful CLI interfaces +- ANSI color support (basic, light, background colors) +- Text styling (bold, underlined, combinations) +- Message types with icons (success, error, warning, info) +- Table formatting (simple, styled, aligned) +- Progress indicators (bars, percentages, multi-step) +- Layout techniques (boxes, columns, lists) +- Animations (spinners, bouncing, loading dots) +- Color control and section filtering -## πŸ“ Files +## Files -- `FormattingDemoCommand.php` - Comprehensive formatting demonstrations -- `TableCommand.php` - Table creation and formatting -- `DashboardCommand.php` - Real-time dashboard simulation -- `main.php` - Application entry point -- `README.md` - This documentation +- `main.php` - Application entry point and runner setup +- `FormattingDemoCommand.php` - Comprehensive formatting demonstration -## πŸš€ Running the Examples +## Usage Examples -### Formatting Demo +### General Help +```bash +php main.php +# or +php main.php help +``` +**Output:** +``` +Usage: + command [arg1 arg2="val" arg3...] + +Global Arguments: + --ansi:[Optional] Force the use of ANSI output. +Available Commands: + help: Display CLI Help. To display help for specific command, use the argument "--command" with this command. + format-demo: Demonstrates various output formatting techniques and ANSI styling +``` + +### Show Format Demo Help +```bash +php main.php help --command=format-demo +``` +**Output:** +``` + format-demo: Demonstrates various output formatting techniques and ANSI styling + Supported Arguments: + --section:[Optional] Show specific section only + --no-colors:[Optional] Disable color output +``` + +## Full Formatting Demonstration + +### Complete Demo ```bash -# Show all formatting options php main.php format-demo +``` +**Output:** +``` +🎨 WebFiori CLI Formatting Demonstration +======================================== + +🌈 Color Demonstration + +Basic Foreground Colors: + black text + red text + green text + yellow text + blue text + magenta text + cyan text + white text + +Light Foreground Colors: + light-red text + light-green text + light-yellow text + light-blue text + light-magenta text + light-cyan text + +Background Colors: + Text with red background + Text with green background + Text with yellow background + Text with blue background + Text with magenta background + Text with cyan background + +Color Combinations: + Error style + Success style + Warning style + Info style + +──────────────────────────────────────────────────────────── + +✨ Text Styling Demonstration + + Bold text + Underlined text + Bold red text + Underlined blue text + Bold text with background + +Message Types: +βœ… Success message +❌ Error message +⚠️ Warning message +ℹ️ Info message + +──────────────────────────────────────────────────────────── + +πŸ“Š Table Demonstration + +Simple Table: +| Name | Age | City | +|--------------|--------------|--------------| +| Ahmed Hassan | 30 | Cairo | +| Fatima Ali | 25 | Dubai | +| Mohammed Omar| 35 | Riyadh | + +Styled Table: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Name β”‚ Age β”‚ Department β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Sara Ahmed β”‚ 28 β”‚ Engineering β”‚ +β”‚ Omar Khalil β”‚ 32 β”‚ Marketing β”‚ +β”‚ Layla Hassanβ”‚ 29 β”‚ Design β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Data Table with Alignment: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Product β”‚ Price β”‚ Stock β”‚ Status β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Laptop β”‚ $1,299.99 β”‚ 15 β”‚ In Stock β”‚ +β”‚ Mouse β”‚ $29.99 β”‚ 150 β”‚ In Stock β”‚ +β”‚ Keyboard β”‚ $89.99 β”‚ 0 β”‚ Out of Stock β”‚ +β”‚ Monitor β”‚ $399.99 β”‚ 8 β”‚ Low Stock β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +──────────────────────────────────────────────────────────── + +πŸ“ˆ Progress Indicators + +Simple Progress Bar: +[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] Complete! + +Percentage Progress: +Progress: [β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“] 100% Done! + +Multi-step Progress: +Step 1/5: Initializing............. βœ… +Step 2/5: Loading data............. βœ… +Step 3/5: Processing............. βœ… +Step 4/5: Validating............. βœ… +Step 5/5: Finalizing............. βœ… +βœ… All steps completed! + +──────────────────────────────────────────────────────────── + +πŸ“ Layout Demonstration + +Bordered Box: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ This is content inside a bordered box! β”‚ +β”‚ It can contain multiple lines β”‚ +β”‚ and various formatting. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Two-Column Layout: +Left Column β”‚ Right Column +β€’ Item 1 β”‚ β†’ Feature A +β€’ Item 2 β”‚ β†’ Feature B +β€’ Item 3 β”‚ β†’ Feature C +β€’ Item 4 β”‚ β†’ Feature D + +Formatted Lists: +Bulleted List: + β€’ First item + β€’ Second item + β€’ Third item with longer text + β€’ Fourth item + +Numbered List: + 1. First item + 2. Second item + 3. Third item with longer text + 4. Fourth item + +Checklist: + βœ… Setup environment + βœ… Write code + ⬜ Test application + ⬜ Deploy to production + +──────────────────────────────────────────────────────────── + +🎬 Animation Demonstration + +Spinner Animation: +β ‹ Processing... β†’ βœ… Processing complete! + +Bouncing Animation: +● (bounces left to right and back) + +Loading Dots: +Loading... β†’ Loading complete! ✨ + +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections +``` -# Show specific sections +## Section-Specific Demonstrations + +### Colors Section +```bash php main.php format-demo --section=colors -php main.php format-demo --section=tables -php main.php format-demo --section=progress +``` +**Output:** +``` +🎨 WebFiori CLI Formatting Demonstration +======================================== + +🌈 Color Demonstration + +Basic Foreground Colors: + black text + red text + green text + yellow text + blue text + magenta text + cyan text + white text + +Light Foreground Colors: + light-red text + light-green text + light-yellow text + light-blue text + light-magenta text + light-cyan text + +Background Colors: + Text with red background + Text with green background + Text with yellow background + Text with blue background + Text with magenta background + Text with cyan background + +Color Combinations: + Error style + Success style + Warning style + Info style + +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections ``` -### Table Command +### Styles Section ```bash -# Display sample data table -php main.php table +php main.php format-demo --section=styles +``` +**Output:** +``` +🎨 WebFiori CLI Formatting Demonstration +======================================== + +✨ Text Styling Demonstration + + Bold text + Underlined text + Bold red text + Underlined blue text + Bold text with background -# Custom table with data -php main.php table --data=users -php main.php table --data=sales --format=compact +Message Types: +βœ… Success message +❌ Error message +⚠️ Warning message +ℹ️ Info message + +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections ``` -### Dashboard Command +### Tables Section ```bash -# Show real-time dashboard -php main.php dashboard +php main.php format-demo --section=tables +``` +**Output:** +``` +🎨 WebFiori CLI Formatting Demonstration +======================================== + +πŸ“Š Table Demonstration + +Simple Table: +| Name | Age | City | +|--------------|--------------|--------------| +| Ahmed Hassan | 30 | Cairo | +| Fatima Ali | 25 | Dubai | +| Mohammed Omar| 35 | Riyadh | + +Styled Table: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Name β”‚ Age β”‚ Department β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Sara Ahmed β”‚ 28 β”‚ Engineering β”‚ +β”‚ Omar Khalil β”‚ 32 β”‚ Marketing β”‚ +β”‚ Layla Hassanβ”‚ 29 β”‚ Design β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Data Table with Alignment: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Product β”‚ Price β”‚ Stock β”‚ Status β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Laptop β”‚ $1,299.99 β”‚ 15 β”‚ In Stock β”‚ +β”‚ Mouse β”‚ $29.99 β”‚ 150 β”‚ In Stock β”‚ +β”‚ Keyboard β”‚ $89.99 β”‚ 0 β”‚ Out of Stock β”‚ +β”‚ Monitor β”‚ $399.99 β”‚ 8 β”‚ Low Stock β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections +``` -# Dashboard with specific refresh rate -php main.php dashboard --refresh=2 +### Progress Section +```bash +php main.php format-demo --section=progress +``` +**Output:** ``` +🎨 WebFiori CLI Formatting Demonstration +======================================== -## πŸ“– Code Explanation +πŸ“ˆ Progress Indicators -### ANSI Color Codes +Simple Progress Bar: +[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] Complete! -#### Basic Colors -```php -// Foreground colors -$this->prints("Red text", ['color' => 'red']); -$this->prints("Green text", ['color' => 'green']); -$this->prints("Blue text", ['color' => 'blue']); +Percentage Progress: +Progress: [β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“] 100% Done! -// Background colors -$this->prints("Text with background", ['bg-color' => 'yellow']); -``` +Multi-step Progress: +Step 1/5: Initializing............. βœ… +Step 2/5: Loading data............. βœ… +Step 3/5: Processing............. βœ… +Step 4/5: Validating............. βœ… +Step 5/5: Finalizing............. βœ… +βœ… All steps completed! -#### Text Styles -```php -// Bold text -$this->prints("Bold text", ['bold' => true]); +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections +``` -// Underlined text -$this->prints("Underlined text", ['underline' => true]); +### Layouts Section +```bash +php main.php format-demo --section=layouts +``` +**Output:** +``` +🎨 WebFiori CLI Formatting Demonstration +======================================== + +πŸ“ Layout Demonstration + +Bordered Box: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ This is content inside a bordered box! β”‚ +β”‚ It can contain multiple lines β”‚ +β”‚ and various formatting. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Two-Column Layout: +Left Column β”‚ Right Column +β€’ Item 1 β”‚ β†’ Feature A +β€’ Item 2 β”‚ β†’ Feature B +β€’ Item 3 β”‚ β†’ Feature C +β€’ Item 4 β”‚ β†’ Feature D + +Formatted Lists: +Bulleted List: + β€’ First item + β€’ Second item + β€’ Third item with longer text + β€’ Fourth item + +Numbered List: + 1. First item + 2. Second item + 3. Third item with longer text + 4. Fourth item + +Checklist: + βœ… Setup environment + βœ… Write code + ⬜ Test application + ⬜ Deploy to production + +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections +``` -// Blinking text (if supported) -$this->prints("Blinking text", ['blink' => true]); +### Animations Section +```bash +php main.php format-demo --section=animations +``` +**Output:** ``` +🎨 WebFiori CLI Formatting Demonstration +======================================== -### Table Formatting +🎬 Animation Demonstration -#### Simple Table -```php -private function createTable(array $headers, array $rows): void { - $this->printTableHeader($headers); - foreach ($rows as $row) { - $this->printTableRow($row); - } -} -``` +Spinner Animation: +β ‹ Processing... β†’ βœ… Processing complete! -#### Styled Table -```php -private function printStyledTable(array $data): void { - // Header with background - $this->prints("β”Œ", ['color' => 'blue']); - // ... table drawing logic -} -``` +Bouncing Animation: +● (bounces left to right and back) -### Progress Indicators +Loading Dots: +Loading... β†’ Loading complete! ✨ -#### Simple Progress Bar -```php -private function showProgress(int $total): void { - for ($i = 0; $i <= $total; $i++) { - $percent = ($i / $total) * 100; - $bar = str_repeat('β–ˆ', (int)($percent / 5)); - $empty = str_repeat('β–‘', 20 - (int)($percent / 5)); - - $this->prints("\r[$bar$empty] " . number_format($percent, 1) . "%"); - usleep(100000); - } -} +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections ``` -#### Spinner Animation -```php -private function showSpinner(int $duration): void { - $chars = ['β ‹', 'β ™', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ‡', '⠏']; - $start = time(); - - while (time() - $start < $duration) { - foreach ($chars as $char) { - $this->prints("\r$char Processing..."); - usleep(100000); - } - } -} -``` +## Advanced Options -## πŸ” Key Features +### Disable Colors +```bash +php main.php format-demo --section=colors --no-colors +``` +**Output:** +``` +⚠️ Color output disabled -### 1. Color System -- **16 basic colors**: Standard ANSI colors -- **256 colors**: Extended color palette -- **RGB colors**: True color support (where available) -- **Background colors**: Text highlighting -- **Color combinations**: Foreground + background +🎨 WebFiori CLI Formatting Demonstration +======================================== -### 2. Text Styling -- **Bold**: Emphasized text -- **Italic**: Slanted text (limited support) -- **Underline**: Underlined text -- **Strikethrough**: Crossed-out text -- **Reverse**: Inverted colors -- **Dim**: Faded text +🌈 Color Demonstration -### 3. Layout Elements -- **Tables**: Structured data display -- **Boxes**: Bordered content areas -- **Lists**: Bulleted and numbered lists -- **Columns**: Multi-column layouts -- **Separators**: Visual dividers +Colors disabled - showing plain text versions -### 4. Interactive Elements -- **Progress bars**: Task completion indicators -- **Spinners**: Loading animations -- **Counters**: Real-time value updates -- **Meters**: Gauge-style indicators -- **Status indicators**: Success/error/warning states +Basic Foreground Colors: + black text + red text + green text + yellow text + blue text + magenta text + cyan text + white text -## 🎨 Expected Output +[... continues with plain text versions ...] -### Color Demo -``` -🎨 Color Demonstration: - Red text in red - Green text in green - Blue text in blue - Yellow background text - Bold red text - Underlined blue text +✨ Formatting demonstration completed! +πŸ’‘ Tip: Use --section= to view specific sections ``` -### Table Example +## Error Handling Examples + +### Invalid Section +```bash +php main.php format-demo --section=invalid ``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Name β”‚ Age β”‚ Department β”‚ Salary β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ John Doe β”‚ 30 β”‚ IT β”‚ $75,000 β”‚ -β”‚ Jane Smith β”‚ 28 β”‚ Marketing β”‚ $65,000 β”‚ -β”‚ Bob Johnson β”‚ 35 β”‚ Sales β”‚ $80,000 β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +**Output:** ``` - -### Progress Bar Example +Error: The following argument(s) have invalid values: '--section' +Info: Allowed values for the argument '--section': +colors +styles +tables +progress +layouts +animations ``` -Processing files... -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (50/50) Complete! -β ‹ Loading data... -β ™ Loading data... -β Ή Loading data... -βœ… Data loaded successfully! +### Invalid Command +```bash +php main.php invalid ``` - -### Dashboard Example +**Output:** ``` -╔══════════════════════════════════════════════════════════╗ -β•‘ System Dashboard β•‘ -╠══════════════════════════════════════════════════════════╣ -β•‘ CPU Usage: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘] 80% β•‘ -β•‘ Memory: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘] 60% β•‘ -β•‘ Disk Space: [β–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘] 30% β•‘ -β•‘ Network: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100% β•‘ -β•‘ β•‘ -β•‘ Active Users: 1,234 β•‘ -β•‘ Requests/sec: 45 β•‘ -β•‘ Uptime: 2d 14h 32m β•‘ -β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +Error: The command 'invalid' is not supported. ``` -## πŸ”— Next Steps +## Key Learning Points -After mastering this example, move on to: -- **[05-interactive-commands](../05-interactive-commands/)** - Complex interactive workflows -- **[07-progress-bars](../07-progress-bars/)** - Advanced progress indicators -- **[10-multi-command-app](../10-multi-command-app/)** - Building complete CLI applications +1. **ANSI Colors**: 8 basic + 6 light foreground colors, 6 background colors +2. **Text Styling**: Bold, underlined, and combination formatting +3. **Message Types**: Consistent styling for success, error, warning, info +4. **Table Formatting**: Simple markdown, Unicode box-drawing, data alignment +5. **Progress Indicators**: Visual feedback for long-running operations +6. **Layout Techniques**: Boxes, columns, lists for structured output +7. **Animations**: Dynamic visual elements for better user experience +8. **Color Control**: Ability to disable colors for plain text environments +9. **Section Filtering**: View specific formatting categories +10. **Unicode Support**: Emojis, box-drawing characters, special symbols -## πŸ’‘ Try This +## Code Structure Examples -Experiment with the code: +### Format Demo Command Structure +```php +class FormattingDemoCommand extends Command { + public function __construct() { + parent::__construct('format-demo', [ + '--section' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::VALUES => ['colors', 'styles', 'tables', 'progress', 'layouts', 'animations'], + ArgumentOption::DESCRIPTION => 'Show specific section only' + ], + '--no-colors' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Disable color output' + ] + ], 'Demonstrates various output formatting techniques and ANSI styling'); + } -1. **Create custom themes**: Define color schemes for different contexts -2. **Add animations**: Create smooth transitions and effects -3. **Build charts**: ASCII bar charts and graphs -4. **Design layouts**: Complex multi-panel interfaces + public function exec(): int { + $section = $this->getArgValue('--section'); + $noColors = $this->isArgProvided('--no-colors'); + + if ($noColors) { + $this->warning('⚠️ Color output disabled'); + $this->println(); + } + + $this->showHeader(); + + if ($section) { + $this->showSection($section, $noColors); + } else { + $this->showAllSections($noColors); + } + + $this->showFooter(); + return 0; + } +} +``` +### Animation Implementation ```php -// Example: Custom color theme -private function applyTheme(string $theme): array { - return match($theme) { - 'dark' => ['bg-color' => 'black', 'color' => 'white'], - 'ocean' => ['bg-color' => 'blue', 'color' => 'cyan'], - 'forest' => ['bg-color' => 'green', 'color' => 'light-green'], - default => [] - }; +private function showSpinnerAnimation(): void { + $frames = ['β ‹', 'β ™', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ‡', '⠏']; + + for ($i = 0; $i < 30; $i++) { + $frame = $frames[$i % count($frames)]; + $this->prints("\r$frame Processing..."); + usleep(100000); // 0.1 seconds + } + + $this->println("\rβœ… Processing complete!"); } ``` + +This example demonstrates professional CLI output formatting suitable for creating visually appealing and user-friendly command-line applications. diff --git a/examples/04-output-formatting/main.php b/examples/04-output-formatting/main.php index 4d40d08..4aa059d 100644 --- a/examples/04-output-formatting/main.php +++ b/examples/04-output-formatting/main.php @@ -11,7 +11,6 @@ * - Terminal cursor manipulation */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load dependencies @@ -22,11 +21,9 @@ $runner = new Runner(); // Register commands -$runner->register(new HelpCommand()); $runner->register(new FormattingDemoCommand()); // Set default command -$runner->setDefaultCommand('help'); // Start the application exit($runner->start()); From 67efe60945831cd6f0d575cd59bcb1b542aaf83e Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:26:04 +0300 Subject: [PATCH 05/12] docs: Updated Example 05 --- .../InteractiveMenuCommand.php | 35 +- examples/05-interactive-commands/README.md | 382 ++++++++++++------ examples/05-interactive-commands/main.php | 3 - 3 files changed, 296 insertions(+), 124 deletions(-) diff --git a/examples/05-interactive-commands/InteractiveMenuCommand.php b/examples/05-interactive-commands/InteractiveMenuCommand.php index 800226a..68f056c 100644 --- a/examples/05-interactive-commands/InteractiveMenuCommand.php +++ b/examples/05-interactive-commands/InteractiveMenuCommand.php @@ -18,6 +18,8 @@ class InteractiveMenuCommand extends Command { private array $menuStack = []; private bool $running = true; + private int $failedTries = 0; + private const MAX_FAILED_TRIES = 5; public function __construct() { parent::__construct('menu', [ @@ -327,6 +329,8 @@ private function goHome(): void { * Handle main menu choices. */ private function handleMainMenuChoice(int $choice): void { + $this->failedTries = 0; // Reset on valid choice + switch ($choice) { case 0: $this->running = false; @@ -378,13 +382,24 @@ private function handleMenuChoice(string $choice): void { // Handle numeric choices if (!is_numeric($choice)) { - $this->error("Invalid choice. Please enter a number or command."); + $this->failedTries++; + $this->error("Invalid choice. Please enter a number or command. ({$this->failedTries}/" . self::MAX_FAILED_TRIES . ")"); + + if ($this->failedTries >= self::MAX_FAILED_TRIES) { + $this->error("Too many invalid attempts. Exiting..."); + $this->running = false; + return; + } + $this->println("Press Enter to continue..."); $this->readln(); return; } + // Reset counter on valid input + $this->failedTries = 0; + $choice = (int)$choice; $currentMenu = end($this->menuStack); @@ -411,6 +426,8 @@ private function handleMenuChoice(string $choice): void { * Handle reports menu choices. */ private function handleReportsMenuChoice(int $choice): void { + $this->failedTries = 0; // Reset on valid choice + switch ($choice) { case 1: $this->showUsageStats(); @@ -442,6 +459,8 @@ private function handleReportsMenuChoice(int $choice): void { * Handle settings menu choices. */ private function handleSettingsMenuChoice(int $choice): void { + $this->failedTries = 0; // Reset on valid choice + switch ($choice) { case 1: $this->navigateTo('system-config', 'System Configuration'); @@ -485,6 +504,8 @@ private function handleSystemConfigAction(int $action): void { * Handle tools menu choices. */ private function handleToolsMenuChoice(int $choice): void { + $this->failedTries = 0; // Reset on valid choice + switch ($choice) { case 1: $this->runSystemCleanup(); @@ -516,6 +537,8 @@ private function handleToolsMenuChoice(int $choice): void { * Handle users menu choices. */ private function handleUsersMenuChoice(int $choice): void { + $this->failedTries = 0; // Reset on valid choice + switch ($choice) { case 1: $this->showUsersList(); @@ -547,7 +570,15 @@ private function handleUsersMenuChoice(int $choice): void { * Show invalid choice message. */ private function invalidChoice(): void { - $this->error("Invalid choice. Please try again."); + $this->failedTries++; + $this->error("Invalid choice. Please try again. ({$this->failedTries}/" . self::MAX_FAILED_TRIES . ")"); + + if ($this->failedTries >= self::MAX_FAILED_TRIES) { + $this->error("Too many invalid attempts. Exiting..."); + $this->running = false; + return; + } + $this->println("Press Enter to continue..."); $this->readln(); } diff --git a/examples/05-interactive-commands/README.md b/examples/05-interactive-commands/README.md index 25b6793..a41aef9 100644 --- a/examples/05-interactive-commands/README.md +++ b/examples/05-interactive-commands/README.md @@ -1,174 +1,318 @@ # Interactive Commands Example -This example demonstrates building complex interactive CLI workflows with menus, wizards, and dynamic user interfaces. +This example demonstrates building complex interactive CLI workflows with multi-level menu navigation, breadcrumb tracking, and robust error handling. ## 🎯 What You'll Learn -- Creating interactive menu systems -- Building step-by-step wizards -- Dynamic command flows -- State management in CLI apps +- Creating hierarchical menu systems with navigation +- Building multi-level interactive interfaces +- State management and breadcrumb tracking +- Error handling with retry limits - User experience best practices -- Error recovery and navigation +- Navigation commands and keyboard shortcuts ## πŸ“ Files -- `InteractiveMenuCommand.php` - Multi-level menu system -- `ProjectWizardCommand.php` - Project creation wizard -- `GameCommand.php` - Interactive CLI game +- `InteractiveMenuCommand.php` - Complete multi-level menu system with navigation - `main.php` - Application entry point - `README.md` - This documentation -## πŸš€ Running the Examples -### Interactive Menu -```bash -# Start the interactive menu -php main.php menu -# Menu with specific starting section -php main.php menu --section=settings -``` +## πŸš€ Running the Example -### Project Wizard +### Basic Usage ```bash -# Create a new project interactively -php main.php wizard +# Start the interactive menu system +php main.php menu -# Wizard with template -php main.php wizard --template=web-app +# Start in a specific section +php main.php menu --section=users # User Management +php main.php menu --section=settings # System Settings +php main.php menu --section=reports # Reports & Analytics +php main.php menu --section=tools # Tools & Utilities ``` -### CLI Game -```bash -# Play the number guessing game -php main.php game - -# Game with difficulty level -php main.php game --difficulty=hard -``` +### Navigation Commands +- **Numbers (1-9)**: Select menu options +- **`back` or `b`**: Go to previous menu +- **`home` or `h`**: Go to main menu +- **`exit` or `q`**: Quit application +- **`0`**: Exit from main menu ## πŸ“– Key Features -### 1. Menu Navigation -- **Hierarchical menus**: Nested menu structures -- **Breadcrumb navigation**: Show current location -- **Quick navigation**: Jump to sections -- **Search functionality**: Find menu items -- **History tracking**: Previous selections - -### 2. Wizard Workflows -- **Step validation**: Validate each step before proceeding -- **Progress tracking**: Show completion progress -- **Back navigation**: Return to previous steps -- **Save/Resume**: Save progress and resume later -- **Templates**: Pre-configured workflows - -### 3. Interactive Elements -- **Dynamic lists**: Lists that update based on user input -- **Real-time validation**: Immediate feedback -- **Conditional flows**: Different paths based on choices -- **Auto-completion**: Suggest completions -- **Keyboard shortcuts**: Quick actions +### 1. Multi-Level Navigation +- **Hierarchical menus**: 3+ levels deep (Main β†’ Settings β†’ System Config) +- **Breadcrumb tracking**: Shows current location path +- **Menu stack management**: Maintains navigation history +- **Quick section access**: Jump directly to sections via arguments + +### 2. Robust Error Handling +- **Failed attempts counter**: Max 5 invalid inputs before exit +- **Graceful degradation**: Clear error messages with attempt count +- **Counter reset**: Resets on valid input to allow recovery +- **Infinite loop prevention**: Automatic exit after too many failures + +### 3. User Experience +- **ANSI colors and icons**: Rich visual interface +- **Clear navigation hints**: Instructions shown on startup +- **Consistent layout**: Standardized menu formatting +- **Responsive feedback**: Immediate validation and error messages + +### 4. State Management +- **Menu stack**: Tracks navigation path for back/home functionality +- **Breadcrumbs**: Visual indication of current location +- **Session persistence**: Maintains state throughout navigation +- **Context awareness**: Different options based on current menu ## 🎨 Expected Output -### Interactive Menu +### Startup Screen ``` πŸŽ›οΈ Interactive Menu System ======================== -πŸ“‹ Main Menu: - 1. User Management - 2. System Settings - 3. Reports & Analytics - 4. Tools & Utilities - 5. Help & Documentation - 0. Exit +πŸ’‘ Navigation Tips: + β€’ Enter number to select option + β€’ Type 'back' or 'b' to go back + β€’ Type 'home' or 'h' to go to main menu + β€’ Type 'exit' or 'q' to quit + +Press Enter to continue... +``` -Current: Main Menu -Your choice [1-5, 0 to exit]: 1 +### Main Menu +``` +πŸ“ Current: Main Menu -πŸ‘₯ User Management: - 1. List Users - 2. Create User - 3. Edit User - 4. Delete User - 5. User Reports - 9. Back to Main Menu +πŸ“‹ Main Menu: -Current: Main Menu > User Management -Your choice [1-5, 9 for back]: 2 + 1. πŸ‘₯ User Management + 2. βš™οΈ System Settings + 3. πŸ“Š Reports & Analytics + 4. πŸ”§ Tools & Utilities + 5. ❓ Help & Documentation -✨ Create New User -================ -Enter user details... + 0. πŸšͺ Exit + +Your choice: 2 ``` -### Project Wizard +### Sub-Menu Navigation ``` -πŸ§™β€β™‚οΈ Project Creation Wizard -========================== +πŸ“ Current: Main Menu > System Settings -Step 1/5: Project Type - 1. Web Application - 2. API Service - 3. CLI Tool - 4. Library/Package - 5. Mobile App +βš™οΈ System Settings: -Your choice: 1 + 1. πŸ–₯️ System Configuration + 2. 🎨 Appearance Settings + 3. πŸ” Security Settings + 4. πŸ“§ Email Configuration + 5. πŸ—„οΈ Database Settings + 6. πŸ“ Logging Configuration -Step 2/5: Framework Selection - 1. Laravel (PHP) - 2. React (JavaScript) - 3. Vue.js (JavaScript) - 4. Django (Python) + 9. ⬅️ Back to Main Menu Your choice: 1 +``` + +### Deep Navigation +``` +πŸ“ Current: Main Menu > System Settings > System Configuration -Step 3/5: Project Configuration -Project name: MyAwesomeApp -Description: A fantastic web application -Author: John Doe +πŸ–₯️ System Configuration +====================== -Step 4/5: Features Selection -β˜‘οΈ Authentication -β˜‘οΈ Database Integration -☐ API Documentation -β˜‘οΈ Testing Framework -☐ Docker Support +Current Settings: + β€’ Application Name: MyApp + β€’ Version: 1.0.0 + β€’ Environment: Development + β€’ Debug Mode: Enabled + β€’ Timezone: UTC -Step 5/5: Review & Create -πŸ“‹ Project Summary: - β€’ Type: Web Application - β€’ Framework: Laravel - β€’ Name: MyAwesomeApp - β€’ Features: 3 selected + 1. Change Application Name + 2. Update Environment + 3. Toggle Debug Mode + 4. Set Timezone + 5. Reset to Defaults -Create project? [Y/n]: Y + 9. ⬅️ Back to Settings + +Your choice: back +``` -πŸŽ‰ Project created successfully! +### Error Handling ``` +Your choice: 99 +Error: Invalid choice. Please try again. (1/5) +Press Enter to continue... -## πŸ’‘ Try This +Your choice: abc +Error: Invalid choice. Please enter a number or command. (2/5) +Press Enter to continue... -Extend the examples: +Your choice: 999 +Error: Invalid choice. Please try again. (3/5) +Press Enter to continue... -1. **Add keyboard shortcuts**: Implement hotkeys for common actions -2. **Create themes**: Different color schemes for menus -3. **Add search**: Search functionality across menus -4. **Implement bookmarks**: Save favorite menu locations -5. **Add help system**: Context-sensitive help +Your choice: invalid +Error: Invalid choice. Please enter a number or command. (4/5) +Press Enter to continue... + +Your choice: wrong +Error: Invalid choice. Please enter a number or command. (5/5) +Error: Too many invalid attempts. Exiting... + +πŸ‘‹ Thank you for using the Interactive Menu System! +Have a great day! +``` + +### Navigation Commands +``` +Your choice: back +# Goes to previous menu + +Your choice: home +# Goes to main menu + +Your choice: q +# Exits application + +Your choice: exit +# Also exits application +``` + +## πŸ§ͺ Test Scenarios + +### 1. Basic Navigation +```bash +echo -e "\n1\n2\n9\n0" | php main.php menu +# Navigate: Main β†’ Users β†’ Create User β†’ Back β†’ Exit +``` + +### 2. Deep Navigation +```bash +echo -e "\n2\n1\nback\nhome\nq" | php main.php menu +# Navigate: Main β†’ Settings β†’ Config β†’ Back β†’ Home β†’ Quit +``` + +### 3. Error Handling +```bash +echo -e "\n2\n99\n99\n99\n99\n99" | php main.php menu +# Test: Settings β†’ 5 invalid inputs β†’ Auto-exit +``` +### 4. Section Arguments +```bash +php main.php menu --section=settings +# Start directly in System Settings +``` + +### 5. Keyboard Shortcuts +```bash +echo -e "\n2\nb\nh\nexit" | php main.php menu +# Test: Settings β†’ back β†’ home β†’ exit +``` + +## ⚠️ Known Issues + +1. **PHP Warning**: Minor undefined array key warning in user creation form (line 259) +2. **Input Handling**: Some forms may not handle all edge cases perfectly +3. **Display**: ANSI colors may not work in all terminal environments + +## πŸ”§ Technical Implementation + +### Core Classes +- `InteractiveMenuCommand`: Main command class with navigation logic +- Menu stack management with `$menuStack` and `$breadcrumbs` arrays +- Failed attempts tracking with `$failedTries` counter (max 5) +- State management for multi-level navigation + +### Key Methods +- `handleMenuChoice()`: Processes user input and navigation +- `navigateTo()`: Manages menu transitions and breadcrumbs +- `goBack()` / `goHome()`: Navigation utilities +- `invalidChoice()`: Error handling with retry counter +- `displayCurrentMenu()`: Renders current menu state + +### Error Prevention +- Input validation with retry limits +- Graceful exit after 5 failed attempts +- Counter reset on valid input for recovery +- Clear error messages with attempt tracking + +## πŸ’‘ Learning Opportunities + +### Extend the Example + +1. **Add Search Functionality** +```php +private function searchMenus(string $query): array { + // Search across all menu items + return $this->findMatchingItems($query); +} +``` + +2. **Implement Bookmarks** ```php -// Example: Add keyboard shortcuts -private function handleKeyboardShortcut(string $input): bool { - return match(strtolower($input)) { - 'h' => $this->showHelp(), - 'q' => $this->confirmExit(), - 's' => $this->showSettings(), - default => false +private function bookmarkCurrentLocation(): void { + $this->bookmarks[] = [ + 'path' => $this->breadcrumbs, + 'menu' => end($this->menuStack) + ]; +} +``` + +3. **Add Themes Support** +```php +private function setTheme(string $theme): void { + $this->colors = match($theme) { + 'dark' => ['bg' => 'black', 'text' => 'white'], + 'light' => ['bg' => 'white', 'text' => 'black'], + default => $this->defaultColors }; } ``` + +4. **Implement Menu History** +```php +private function showHistory(): void { + foreach ($this->navigationHistory as $item) { + $this->println("β€’ {$item['timestamp']}: {$item['path']}"); + } +} +``` + +5. **Add Context-Sensitive Help** +```php +private function showContextHelp(): void { + $currentMenu = end($this->menuStack); + $help = $this->getHelpForMenu($currentMenu); + $this->displayHelp($help); +} +``` + +### Best Practices Demonstrated + +1. **State Management**: Proper tracking of navigation state and user context +2. **Error Recovery**: Graceful handling of invalid input with retry limits +3. **User Experience**: Clear feedback, consistent interface, helpful navigation +4. **Code Organization**: Separation of concerns, modular menu handlers +5. **Extensibility**: Easy to add new menus and navigation features + +### Integration Ideas + +- **Database Integration**: Store user preferences and navigation history +- **Configuration System**: Customizable menu layouts and themes +- **Plugin Architecture**: Dynamically loaded menu modules +- **API Integration**: Menus that interact with external services +- **Logging System**: Track user interactions and menu usage analytics + +## πŸ”— Related Examples + +- **[01-basic-hello-world](../01-basic-hello-world/)**: Simple command structure +- **[02-arguments-and-options](../02-arguments-and-options/)**: Command arguments +- **[03-user-input](../03-user-input/)**: Input validation and handling +- **[04-output-formatting](../04-output-formatting/)**: ANSI colors and formatting + diff --git a/examples/05-interactive-commands/main.php b/examples/05-interactive-commands/main.php index 3c62a07..b0d6349 100644 --- a/examples/05-interactive-commands/main.php +++ b/examples/05-interactive-commands/main.php @@ -11,7 +11,6 @@ * - Dynamic command flows and error recovery */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load dependencies @@ -22,11 +21,9 @@ $runner = new Runner(); // Register commands -$runner->register(new HelpCommand()); $runner->register(new InteractiveMenuCommand()); // Set default command -$runner->setDefaultCommand('help'); // Start the application exit($runner->start()); From b8d5335a5c25261fd4dd806e013e2d3e380992fe Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:27:42 +0300 Subject: [PATCH 06/12] docs: Updated Example 06 --- examples/06-table-display/README.md | 300 ++++++++++++ .../06-table-display/TableDemoCommand.php | 460 ++++++++++++++++++ examples/06-table-display/main.php | 14 + examples/06-table-display/simple-example.php | 59 +++ 4 files changed, 833 insertions(+) create mode 100644 examples/06-table-display/README.md create mode 100644 examples/06-table-display/TableDemoCommand.php create mode 100644 examples/06-table-display/main.php create mode 100644 examples/06-table-display/simple-example.php diff --git a/examples/06-table-display/README.md b/examples/06-table-display/README.md new file mode 100644 index 0000000..14c6b63 --- /dev/null +++ b/examples/06-table-display/README.md @@ -0,0 +1,300 @@ +# πŸ“Š Table Display Example + +A comprehensive demonstration of the WebFiori CLI Table feature, showcasing professional tabular data display capabilities with various styling options, data formatting, and responsive design. + +## 🎯 What This Example Demonstrates + +### Core Table Features +- **Multiple table styles** (bordered, simple, minimal, compact, markdown) +- **Column configuration** (width, alignment, formatting) +- **Data type handling** (currency, dates, percentages, booleans) +- **Color themes** (default, dark, light, colorful, professional, minimal) +- **Status-based colorization** (active=green, error=red, warning=yellow) +- **Responsive design** that adapts to terminal width +- **Data export capabilities** (JSON, CSV, arrays) + +### Real-World Use Cases +- **User Management** - Display user accounts with status indicators +- **Product Catalogs** - Show inventory with pricing and stock levels +- **Service Monitoring** - System health dashboards with metrics +- **Data Export** - Various output formats for integration +- **Report Generation** - Professional data presentation + +## πŸš€ Running the Example + +### Basic Usage +```bash +# Run all demonstrations +php main.php table-demo + +# Show help +php main.php help --command=table-demo +``` + +### Specific Demonstrations +```bash +# User management table +php main.php table-demo --demo=users + +# Product catalog +php main.php table-demo --demo=products + +# Service status monitoring +php main.php table-demo --demo=services + +# Table style variations +php main.php table-demo --demo=styles + +# Color theme showcase +php main.php table-demo --demo=themes + +# Data export capabilities +php main.php table-demo --demo=export + +# Run all demos +php main.php table-demo --demo=all +``` + +### Customization Options +```bash +# Use different table style +php main.php table-demo --demo=users --style=simple + +# Apply color theme +php main.php table-demo --demo=products --theme=colorful + +# Set custom width +php main.php table-demo --demo=services --width=100 + +# Combine options +php main.php table-demo --demo=users --style=bordered --theme=professional --width=120 +``` + +## πŸ“‹ Available Options + +### Demo Types (`--demo`) +- `users` - User management system with status indicators +- `products` - Product catalog with pricing and inventory +- `services` - Service monitoring dashboard +- `styles` - Showcase of different table styles +- `themes` - Color theme demonstrations +- `export` - Data export format examples +- `all` - Run all demonstrations (default) + +### Table Styles (`--style`) +- `bordered` - Unicode box-drawing characters (default) +- `simple` - ASCII characters for maximum compatibility +- `minimal` - Clean look with reduced borders +- `compact` - Space-efficient layout +- `markdown` - Markdown-compatible format + +### Color Themes (`--theme`) +- `default` - Standard theme with basic colors +- `dark` - Optimized for dark terminals +- `light` - Optimized for light terminals +- `colorful` - Vibrant colors and styling +- `professional` - Business-appropriate styling +- `minimal` - No colors, just formatting + +### Width Control (`--width`) +- `0` - Auto-detect terminal width (default) +- `80` - Fixed 80 character width +- `120` - Fixed 120 character width +- Any positive integer for custom width + +## 🎨 Example Output + +### User Management Table (Bordered Style) +``` +πŸ‘₯ User Management System + User Management Dashboard +β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ ID β”‚ Name β”‚ Email β”‚ Status β”‚ Created β”‚ Role β”‚ Balance β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 1 β”‚ John Doe β”‚ john.doe@example.com β”‚ Active β”‚ Jan 15, 2024 β”‚ Admin β”‚ 1,250.75 β”‚ +β”‚ 2 β”‚ Jane Smith β”‚ jane.smith@example.com β”‚ Inactive β”‚ Jan 16, 2024 β”‚ User β”‚ 890.50 β”‚ +β”‚ 3 β”‚ Bob Johnson β”‚ bob.johnson@example.com β”‚ Active β”‚ Jan 17, 2024 β”‚ Manager β”‚ 2,100.00 β”‚ +β”‚ 4 β”‚ Alice Brown β”‚ alice.brown@example.com β”‚ Pending β”‚ Jan 18, 2024 β”‚ User β”‚ 750.25 β”‚ +β”‚ 5 β”‚ Charlie Davis β”‚ charlie.davis@example.com β”‚ Active β”‚ Jan 19, 2024 β”‚ Admin β”‚ 1,800.80 β”‚ +β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Product Catalog (Compact Style) +``` +πŸ›οΈ Product Catalog + Product Inventory + SKU β”‚Product Name β”‚ Price β”‚ Stock β”‚ Category β”‚Featured β”‚Rating +──────────────────────────────────────────────────────────────────────────────────── + LAP001 β”‚MacBook Pro 16" β”‚ $2,499.99 β”‚ 15 β”‚Electronics β”‚ ⭐ Yes β”‚β˜… 4.8 + MOU002 β”‚Wireless Mouse β”‚ $29.99 β”‚ Out β”‚Accessories β”‚ ⭐ Yes β”‚β˜… 4.2 + KEY003 β”‚Mechanical Keyboard β”‚ $149.99 β”‚ 25 β”‚Accessories β”‚ ⭐ Yes β”‚β˜… 4.6 + MON004 β”‚4K Monitor 27" β”‚ $399.99 β”‚ 8 β”‚Electronics β”‚ No β”‚β˜… 4.4 + HDD005 β”‚External SSD 1TB β”‚ $199.99 β”‚ 50 β”‚ Storage β”‚ ⭐ Yes β”‚β˜… 4.7 +``` + +### Service Status Monitor (Markdown Style) +``` +πŸ”§ Service Status Monitor + System Health Dashboard +------------------------------------------------------------------------------------ +| Service | Version | Status | Uptime | Response | Memory | Health | +|----------------|--------------|------------|----------|------------|----------|----------| +| Web Server | nginx/1.20 | Running | 99.9% | 45ms | 2.1GB | βœ… | +| Database | MySQL 8.0 | Running | 99.8% | 12ms | 4.5GB | βœ… | +| Cache Server | Redis 6.2 | Stopped | 0% | N/A | 0MB | ❌ | +| API Gateway | Kong 3.0 | Running | 99.7% | 78ms | 512MB | βœ… | +| Message Queue | RabbitMQ | Warning | 95.2% | 156ms | 1.2GB | ⚠️ | +| Load Balancer | HAProxy | Running | 100% | 5ms | 128MB | βœ… | +------------------------------------------------------------------------------------ +``` + +### Style Variations Showcase +``` +🎨 Table Style Variations + +Style: Bordered (Unicode box-drawing characters) +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Item β”‚ Price β”‚ Temperature β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Coffee β”‚ $3.50 β”‚ Hot β”‚ +β”‚ Tea β”‚ $2.75 β”‚ Hot β”‚ +β”‚ Juice β”‚ $4.25 β”‚ Cold β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Style: Simple (ASCII characters for compatibility) ++--------------------+----------------+--------------------+ +| Item | Price | Temperature | ++--------------------+----------------+--------------------+ +| Coffee | $3.50 | Hot | +| Tea | $2.75 | Hot | +| Juice | $4.25 | Cold | ++--------------------+----------------+--------------------+ + +Style: Minimal (Clean look with minimal borders) + Item Price Temperature +────────────────────────────────────────────────────────── + Coffee $3.50 Hot + Tea $2.75 Hot + Juice $4.25 Cold +``` + +## πŸ§ͺ Test Scenarios + +### 1. All Demos +```bash +php main.php table-demo --demo=all +# Shows: users, products, services, styles, themes, export +``` + +### 2. Style Combinations +```bash +php main.php table-demo --demo=users --style=minimal --theme=dark +php main.php table-demo --demo=products --style=compact --theme=colorful +php main.php table-demo --demo=services --style=markdown --theme=professional +``` + +### 3. Width Testing +```bash +php main.php table-demo --demo=users --width=80 +php main.php table-demo --demo=products --width=120 +php main.php table-demo --demo=services --width=100 +``` + +### 4. Individual Demos +```bash +php main.php table-demo --demo=users +php main.php table-demo --demo=products +php main.php table-demo --demo=services +php main.php table-demo --demo=styles +php main.php table-demo --demo=themes +php main.php table-demo --demo=export +``` + +### 5. Help and Documentation +```bash +php main.php help --command=table-demo +php main.php table-demo --help +``` + +## πŸ’‘ Key Features Demonstrated + +### 1. Data Formatting +- **Currency**: `$2,499.99` with proper formatting +- **Dates**: `Jan 15, 2024` human-readable format +- **Percentages**: `99.9%` with decimal precision +- **Status Indicators**: Color-coded status values +- **Boolean Values**: `⭐ Yes` / `No` with icons + +### 2. Visual Enhancements +- **Color Coding**: Green=Active, Red=Inactive, Yellow=Warning +- **Icons and Emojis**: βœ…βŒβš οΈβ­β˜… for visual clarity +- **Column Alignment**: Left, right, center alignment +- **Text Truncation**: Long emails and names handled gracefully + +### 3. Responsive Design +- **Auto-width Detection**: Adapts to terminal size +- **Column Prioritization**: Important columns stay visible +- **Overflow Handling**: Graceful text truncation +- **Mobile-friendly**: Works on narrow terminals + +### 4. Export Capabilities +- **JSON Format**: Structured data export +- **CSV Format**: Spreadsheet compatibility +- **Array Format**: PHP data structures +- **Associative Arrays**: Key-value pair export + +## πŸ”§ Technical Implementation + +### Core Classes Used +- `TableDemoCommand`: Main command class +- `TableBuilder`: Table construction and configuration +- `TableTheme`: Color theme management +- `Column`: Individual column configuration +- `TableData`: Data handling and export + +### Key Methods +- `createUsersTable()`: User management demo +- `createProductsTable()`: Product catalog demo +- `createServicesTable()`: Service monitoring demo +- `demonstrateStyles()`: Style variations showcase +- `demonstrateThemes()`: Color theme examples + +### Configuration Options +- Column width and alignment control +- Status-based colorization rules +- Data formatting functions +- Theme and style selection +- Responsive width management + +## 🎯 Best Practices Demonstrated + +### 1. User Experience +- Clear visual hierarchy with headers and colors +- Consistent data formatting across columns +- Meaningful status indicators and icons +- Responsive design for different screen sizes + +### 2. Data Presentation +- Appropriate column widths for content +- Status-based color coding for quick scanning +- Currency and date formatting for readability +- Truncation handling for long text + +### 3. Performance +- Efficient rendering for large datasets +- Memory-conscious data handling +- Fast column width calculations +- Optimized ANSI color usage + +### 4. Accessibility +- High contrast color options +- ASCII fallbacks for compatibility +- Clear visual separation between elements +- Support for different terminal capabilities + +## πŸ”— Related Examples + +- **[04-output-formatting](../04-output-formatting/)** - ANSI colors and formatting +- **[05-interactive-commands](../05-interactive-commands/)** - Interactive menu systems +- **[08-file-processing](../08-file-processing/)** - File data processing +- **[10-multi-command-app](../10-multi-command-app/)** - Complete CLI applications diff --git a/examples/06-table-display/TableDemoCommand.php b/examples/06-table-display/TableDemoCommand.php new file mode 100644 index 0000000..980b1a0 --- /dev/null +++ b/examples/06-table-display/TableDemoCommand.php @@ -0,0 +1,460 @@ + [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Specific demo to run (users, products, services, styles, themes, export)', + ArgumentOption::VALUES => ['users', 'products', 'services', 'styles', 'themes', 'export', 'all'] + ], + '--style' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Table style to use', + ArgumentOption::VALUES => ['bordered', 'simple', 'minimal', 'compact', 'markdown'], + ArgumentOption::DEFAULT => 'bordered' + ], + '--theme' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Color theme to use', + ArgumentOption::VALUES => ['default', 'dark', 'light', 'colorful', 'professional', 'minimal'], + ArgumentOption::DEFAULT => 'default' + ], + '--width' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'Maximum table width (default: auto-detect)', + ArgumentOption::DEFAULT => '0' + ] + ], 'Demonstrates WebFiori CLI Table display capabilities with various examples'); + } + + public function exec(): int { + $this->println('🎯 WebFiori CLI Table Feature Demonstration', ['bold' => true, 'color' => 'light-cyan']); + $this->println('============================================'); + $this->println(''); + + $demo = $this->getArgValue('--demo') ?? 'all'; + $style = $this->getArgValue('--style') ?? 'bordered'; + $theme = $this->getArgValue('--theme') ?? 'default'; + $width = (int)($this->getArgValue('--width') ?? '0'); + + if ($width === 0) { + $width = $this->getTerminalWidth(); + } + + $this->println("Configuration:", ['color' => 'yellow']); + $this->println(" β€’ Demo: $demo"); + $this->println(" β€’ Style: $style"); + $this->println(" β€’ Theme: $theme"); + $this->println(" β€’ Width: {$width} characters"); + $this->println(''); + + try { + switch ($demo) { + case 'users': + $this->demoUserManagement($style, $theme, $width); + break; + case 'products': + $this->demoProductCatalog($style, $theme, $width); + break; + case 'services': + $this->demoServiceStatus($style, $theme, $width); + break; + case 'styles': + $this->demoTableStyles($width); + break; + case 'themes': + $this->demoColorThemes($width); + break; + case 'export': + $this->demoDataExport($style, $theme, $width); + break; + case 'all': + default: + $this->runAllDemos($style, $theme, $width); + break; + } + + $this->println(''); + $this->success('✨ Table demonstration completed successfully!'); + $this->println(''); + $this->info('πŸ’‘ Tips:'); + $this->println(' β€’ Use --demo= to run specific demonstrations'); + $this->println(' β€’ Try different --style and --theme combinations'); + $this->println(' β€’ Adjust --width for different terminal sizes'); + + return 0; + } catch (Exception $e) { + $this->error('Demo failed: '.$e->getMessage()); + + return 1; + } + } + + /** + * Demonstrate color themes. + */ + private function demoColorThemes(int $width): void { + $this->println('🌈 Color Theme Showcase', ['bold' => true, 'color' => 'light-magenta']); + $this->println('-----------------------'); + + $data = [ + ['Active', 25, '83.3%'], + ['Inactive', 3, '10.0%'], + ['Pending', 2, '6.7%'] + ]; + + $themes = [ + 'default' => 'Standard theme with basic colors', + 'dark' => 'Dark theme for dark terminals', + 'colorful' => 'Vibrant colors and styling', + 'professional' => 'Business-appropriate styling' + ]; + + foreach ($themes as $themeName => $description) { + $this->println("Theme: ".ucfirst($themeName)." ($description)", ['color' => 'yellow']); + + $table = TableBuilder::create() + ->setHeaders(['Status', 'Count', 'Percentage']) + ->addRows($data) + ->setTheme(TableTheme::create($themeName)) + ->setMaxWidth(min($width, 50)) + ->configureColumn('Count', ['align' => 'right']) + ->configureColumn('Percentage', [ + 'align' => 'right', + 'formatter' => fn($value) => str_replace('%', '', $value).'%' + ]) + ->colorizeColumn('Status', function ($value) { + return match (strtolower($value)) { + 'active' => ['color' => 'green', 'bold' => true], + 'inactive' => ['color' => 'red'], + 'pending' => ['color' => 'yellow'], + default => [] + }; + }); + + echo $table->render(); + $this->println(''); + } + + $this->info('Themes automatically adapt to terminal capabilities.'); + } + + /** + * Demonstrate data export capabilities. + */ + private function demoDataExport(string $style, string $theme, int $width): void { + $this->println('πŸ’Ύ Data Export Capabilities', ['bold' => true, 'color' => 'light-green']); + $this->println('---------------------------'); + + $exportData = [ + ['1', 'John Doe', 'john@example.com', 'Active'], + ['2', 'Jane Smith', 'jane@example.com', 'Inactive'], + ['3', 'Bob Johnson', 'bob@example.com', 'Active'] + ]; + + $table = TableBuilder::create() + ->setHeaders(['ID', 'Name', 'Email', 'Status']) + ->addRows($exportData) + ->setTitle('Sample Export Data') + ->useStyle($style) + ->setTheme(TableTheme::create($theme)) + ->setMaxWidth($width); + + echo $table->render(); + + $this->println(''); + $this->info('Export formats available:'); + $this->println(' β€’ JSON format (structured data)'); + $this->println(' β€’ CSV format (spreadsheet compatible)'); + $this->println(' β€’ Array format (PHP arrays)'); + $this->println(' β€’ Associative arrays (key-value pairs)'); + $this->println(''); + $this->println('Note: In a real application, you would access the TableData'); + $this->println('object to export data in various formats.'); + } + + /** + * Demonstrate product catalog table. + */ + private function demoProductCatalog(string $style, string $theme, int $width): void { + $this->println('πŸ›οΈ Product Catalog', ['bold' => true, 'color' => 'blue']); + $this->println('------------------'); + + $products = [ + ['LAP001', 'MacBook Pro 16"', 2499.99, 15, 'Electronics', true, 4.8], + ['MOU002', 'Wireless Mouse', 29.99, 0, 'Accessories', true, 4.2], + ['KEY003', 'Mechanical Keyboard', 149.99, 25, 'Accessories', true, 4.6], + ['MON004', '4K Monitor 27"', 399.99, 8, 'Electronics', false, 4.4], + ['HDD005', 'External SSD 1TB', 199.99, 50, 'Storage', true, 4.7] + ]; + + $table = TableBuilder::create() + ->setHeaders(['SKU', 'Product Name', 'Price', 'Stock', 'Category', 'Featured', 'Rating']) + ->addRows($products) + ->setTitle('Product Inventory') + ->useStyle($style) + ->setTheme(TableTheme::create($theme)) + ->setMaxWidth($width) + ->configureColumn('SKU', ['width' => 8, 'align' => 'center']) + ->configureColumn('Product Name', ['width' => 20, 'truncate' => true]) + ->configureColumn('Price', [ + 'width' => 10, + 'align' => 'right', + 'formatter' => fn($value) => '$'.number_format($value, 2) + ]) + ->configureColumn('Stock', [ + 'width' => 6, + 'align' => 'right', + 'formatter' => fn($value) => $value > 0 ? (string)$value : 'Out' + ]) + ->configureColumn('Category', ['width' => 12, 'align' => 'center']) + ->configureColumn('Featured', [ + 'width' => 9, + 'align' => 'center', + 'formatter' => fn($value) => $value ? '⭐ Yes' : ' No' + ]) + ->configureColumn('Rating', [ + 'width' => 7, + 'align' => 'center', + 'formatter' => fn($value) => 'β˜… '.number_format($value, 1) + ]) + ->colorizeColumn('Stock', function ($value) { + if ($value === 'Out' || $value === 0) { + return ['color' => 'red', 'bold' => true]; + } elseif (is_numeric($value) && $value < 10) { + return ['color' => 'yellow']; + } + + return ['color' => 'green']; + }); + + echo $table->render(); + + $this->println(''); + $this->info('Features demonstrated:'); + $this->println(' β€’ Currency formatting'); + $this->println(' β€’ Stock level indicators with colors'); + $this->println(' β€’ Boolean formatting with icons'); + $this->println(' β€’ Rating display with stars'); + $this->println(' β€’ Product name truncation'); + } + + /** + * Demonstrate service status monitoring. + */ + private function demoServiceStatus(string $style, string $theme, int $width): void { + $this->println('πŸ”§ Service Status Monitor', ['bold' => true, 'color' => 'magenta']); + $this->println('-------------------------'); + + $services = [ + ['Web Server', 'nginx/1.20', 'Running', '99.9%', '45ms', '2.1GB', 'βœ…'], + ['Database', 'MySQL 8.0', 'Running', '99.8%', '12ms', '4.5GB', 'βœ…'], + ['Cache Server', 'Redis 6.2', 'Stopped', '0%', 'N/A', '0MB', '❌'], + ['API Gateway', 'Kong 3.0', 'Running', '99.7%', '78ms', '512MB', 'βœ…'], + ['Message Queue', 'RabbitMQ', 'Warning', '95.2%', '156ms', '1.2GB', '⚠️'], + ['Load Balancer', 'HAProxy', 'Running', '100%', '5ms', '128MB', 'βœ…'] + ]; + + $table = TableBuilder::create() + ->setHeaders(['Service', 'Version', 'Status', 'Uptime', 'Response', 'Memory', 'Health']) + ->addRows($services) + ->setTitle('System Health Dashboard') + ->useStyle($style) + ->setTheme(TableTheme::create($theme)) + ->setMaxWidth($width) + ->configureColumn('Service', ['width' => 14, 'align' => 'left']) + ->configureColumn('Version', ['width' => 12, 'align' => 'center']) + ->configureColumn('Status', ['width' => 10, 'align' => 'center']) + ->configureColumn('Uptime', ['width' => 8, 'align' => 'right']) + ->configureColumn('Response', ['width' => 10, 'align' => 'right']) + ->configureColumn('Memory', ['width' => 8, 'align' => 'right']) + ->configureColumn('Health', ['width' => 8, 'align' => 'center']) + ->colorizeColumn('Status', function ($value) { + return match (strtolower($value)) { + 'running' => ['color' => 'green', 'bold' => true], + 'stopped' => ['color' => 'red', 'bold' => true], + 'warning' => ['color' => 'yellow', 'bold' => true], + default => [] + }; + }) + ->colorizeColumn('Health', function ($value) { + return match ($value) { + 'βœ…' => ['color' => 'green'], + '❌' => ['color' => 'red'], + '⚠️' => ['color' => 'yellow'], + default => [] + }; + }); + + echo $table->render(); + + $this->println(''); + $this->info('Features demonstrated:'); + $this->println(' β€’ System monitoring data display'); + $this->println(' β€’ Multiple status indicators'); + $this->println(' β€’ Performance metrics formatting'); + $this->println(' β€’ Health status with emoji indicators'); + $this->println(' β€’ Memory usage display'); + } + + /** + * Demonstrate different table styles. + */ + private function demoTableStyles(int $width): void { + $this->println('🎨 Table Style Variations', ['bold' => true, 'color' => 'cyan']); + $this->println('-------------------------'); + + $data = [ + ['Coffee', '$3.50', 'Hot'], + ['Tea', '$2.75', 'Hot'], + ['Juice', '$4.25', 'Cold'] + ]; + + $styles = [ + 'bordered' => 'Unicode box-drawing characters', + 'simple' => 'ASCII characters for compatibility', + 'minimal' => 'Clean look with minimal borders', + 'compact' => 'Space-efficient layout', + 'markdown' => 'Markdown-compatible format' + ]; + + foreach ($styles as $styleName => $description) { + $this->println("Style: ".ucfirst($styleName)." ($description)", ['color' => 'yellow']); + + $table = TableBuilder::create() + ->setHeaders(['Item', 'Price', 'Temperature']) + ->addRows($data) + ->useStyle($styleName) + ->setMaxWidth(min($width, 60)); // Limit width for style demo + + echo $table->render(); + $this->println(''); + } + + $this->info('All table styles are responsive and adapt to terminal width.'); + } + + /** + * Demonstrate user management table. + */ + private function demoUserManagement(string $style, string $theme, int $width): void { + $this->println('πŸ‘₯ User Management System', ['bold' => true, 'color' => 'green']); + $this->println('-------------------------'); + + $users = [ + ['1', 'John Doe', 'john.doe@example.com', 'Active', '2024-01-15', 'Admin', '$1,250.75'], + ['2', 'Jane Smith', 'jane.smith@example.com', 'Inactive', '2024-01-16', 'User', '$890.50'], + ['3', 'Bob Johnson', 'bob.johnson@example.com', 'Active', '2024-01-17', 'Manager', '$2,100.00'], + ['4', 'Alice Brown', 'alice.brown@example.com', 'Pending', '2024-01-18', 'User', '$750.25'], + ['5', 'Charlie Davis', 'charlie.davis@example.com', 'Active', '2024-01-19', 'Admin', '$1,800.80'] + ]; + + $table = TableBuilder::create() + ->setHeaders(['ID', 'Name', 'Email', 'Status', 'Created', 'Role', 'Balance']) + ->addRows($users) + ->setTitle('User Management Dashboard') + ->useStyle($style) + ->setTheme(TableTheme::create($theme)) + ->setMaxWidth($width) + ->configureColumn('ID', ['width' => 4, 'align' => 'center']) + ->configureColumn('Name', ['width' => 15, 'align' => 'left']) + ->configureColumn('Email', ['width' => 25, 'truncate' => true]) + ->configureColumn('Status', ['width' => 10, 'align' => 'center']) + ->configureColumn('Created', [ + 'width' => 12, + 'align' => 'center', + 'formatter' => fn($date) => date('M j, Y', strtotime($date)) + ]) + ->configureColumn('Role', ['width' => 8, 'align' => 'center']) + ->configureColumn('Balance', [ + 'width' => 12, + 'align' => 'right', + 'formatter' => fn($value) => str_replace('$', '', $value) // Remove existing $ for proper formatting + ]) + ->colorizeColumn('Status', function ($value) { + return match (strtolower($value)) { + 'active' => ['color' => 'green', 'bold' => true], + 'inactive' => ['color' => 'red', 'bold' => true], + 'pending' => ['color' => 'yellow', 'bold' => true], + default => [] + }; + }); + + echo $table->render(); + + $this->println(''); + $this->info('Features demonstrated:'); + $this->println(' β€’ Column width control and alignment'); + $this->println(' β€’ Date formatting'); + $this->println(' β€’ Status-based colorization'); + $this->println(' β€’ Email truncation for long addresses'); + $this->println(' β€’ Responsive design within terminal width'); + } + + /** + * Get terminal width with fallback. + */ + private function getTerminalWidth(): int { + // Try to get terminal width + $width = exec('tput cols 2>/dev/null'); + + if (is_numeric($width)) { + return (int)$width; + } + + // Fallback to environment variable + $width = getenv('COLUMNS'); + + if ($width !== false && is_numeric($width)) { + return (int)$width; + } + + // Default fallback + return 80; + } + + /** + * Run all demonstrations. + */ + private function runAllDemos(string $style, string $theme, int $width): void { + $this->demoUserManagement($style, $theme, $width); + $this->println(''); + $this->demoProductCatalog($style, $theme, $width); + $this->println(''); + $this->demoServiceStatus($style, $theme, $width); + $this->println(''); + $this->demoTableStyles($width); + $this->println(''); + $this->demoColorThemes($width); + } +} diff --git a/examples/06-table-display/main.php b/examples/06-table-display/main.php new file mode 100644 index 0000000..65d798f --- /dev/null +++ b/examples/06-table-display/main.php @@ -0,0 +1,14 @@ +register(new TableDemoCommand()); +// Start the application +exit($runner->start()); diff --git a/examples/06-table-display/simple-example.php b/examples/06-table-display/simple-example.php new file mode 100644 index 0000000..46cd63d --- /dev/null +++ b/examples/06-table-display/simple-example.php @@ -0,0 +1,59 @@ +setHeaders(['Name', 'Age', 'City']) + ->addRow(['John Doe', 30, 'New York']) + ->addRow(['Jane Smith', 25, 'Los Angeles']) + ->addRow(['Bob Johnson', 35, 'Chicago']); + +echo $basicTable->render()."\n\n"; + +// Example 2: Formatted table with colors +echo "Example 2: Formatted Table with Colors\n"; +echo "--------------------------------------\n"; + +$formattedTable = TableBuilder::create() + ->setHeaders(['Product', 'Price', 'Status']) + ->addRow(['Laptop', 1299.99, 'Available']) + ->addRow(['Mouse', 29.99, 'Out of Stock']) + ->addRow(['Keyboard', 89.99, 'Available']) + ->configureColumn('Price', [ + 'align' => 'right', + 'formatter' => fn($value) => '$'.number_format($value, 2) + ]) + ->colorizeColumn('Status', function ($value) { + return match ($value) { + 'Available' => ['color' => 'green', 'bold' => true], + 'Out of Stock' => ['color' => 'red', 'bold' => true], + default => [] + }; + }); + +echo $formattedTable->render()."\n\n"; + +echo "✨ Simple examples completed successfully!\n"; From 80adba00e60cd35652112cc0c10ea55b1fed8857 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:28:32 +0300 Subject: [PATCH 07/12] docs: Updated Example 07 --- examples/07-progress-bars/README.md | 399 ++++++++++++++++------------ examples/07-progress-bars/main.php | 3 - 2 files changed, 234 insertions(+), 168 deletions(-) diff --git a/examples/07-progress-bars/README.md b/examples/07-progress-bars/README.md index 231439e..72769e2 100644 --- a/examples/07-progress-bars/README.md +++ b/examples/07-progress-bars/README.md @@ -1,235 +1,304 @@ # Progress Bars Example -This example demonstrates the comprehensive progress bar system in WebFiori CLI, showcasing various styles, formats, and use cases. +This example demonstrates the comprehensive progress bar system in WebFiori CLI, showcasing various styles, formats, and real-time progress tracking capabilities. ## 🎯 What You'll Learn -- Creating and customizing progress bars -- Different progress bar styles and formats -- Real-time progress tracking -- Integration with file operations -- Multi-step progress workflows -- Performance monitoring with progress bars +- Creating and customizing progress bars with different styles +- Real-time progress tracking and updates +- Progress bar formats and display options +- Performance monitoring with rate calculations +- Integration with long-running operations +- Error handling and validation ## πŸ“ Files - `ProgressDemoCommand.php` - Comprehensive progress bar demonstrations -- `FileProcessorCommand.php` - File processing with progress tracking -- `DownloadSimulatorCommand.php` - Download simulation with detailed progress -- `BatchProcessorCommand.php` - Batch operations with multiple progress bars - `main.php` - Application entry point - `README.md` - This documentation -## πŸš€ Running the Examples +## πŸš€ Running the Example -### Progress Demo +### Basic Usage ```bash # Show all progress bar styles php main.php progress-demo -# Specific style demonstration -php main.php progress-demo --style=ascii --items=20 - -# Quick demo with fewer items -php main.php progress-demo --items=10 --delay=50 +# Show help +php main.php help --command=progress-demo ``` -### File Processor +### Style Demonstrations ```bash -# Process sample files -php main.php file-processor - -# Process with specific directory -php main.php file-processor --directory=./sample-files --pattern="*.txt" +# All styles demonstration +php main.php progress-demo --style=all --items=20 --delay=50 + +# Individual styles +php main.php progress-demo --style=default --items=10 --delay=100 +php main.php progress-demo --style=ascii --items=50 --delay=20 +php main.php progress-demo --style=dots --items=15 --delay=80 +php main.php progress-demo --style=arrow --items=25 --delay=40 +php main.php progress-demo --style=custom --items=12 --delay=150 ``` -### Download Simulator +### Format Options ```bash -# Simulate file downloads -php main.php download-sim - -# Custom download simulation -php main.php download-sim --files=5 --size=large --speed=slow +# Different format templates +php main.php progress-demo --style=dots --format=eta --items=15 +php main.php progress-demo --style=arrow --format=rate --items=25 +php main.php progress-demo --style=custom --format=verbose --items=12 ``` -### Batch Processor +### Performance Testing ```bash -# Run batch operations -php main.php batch-processor - -# Custom batch size -php main.php batch-processor --batch-size=50 --operations=3 -``` - -## πŸ“– Code Explanation - -### Basic Progress Bar Usage - -#### Simple Progress Bar -```php -$progressBar = $this->createProgressBar(100); -$progressBar->start('Processing...'); +# Quick demo (minimum items) +php main.php progress-demo --style=default --items=10 --delay=50 -for ($i = 0; $i < 100; $i++) { - // Do work - $progressBar->advance(); - usleep(50000); -} +# Longer demo (more items) +php main.php progress-demo --style=ascii --items=100 --delay=10 -$progressBar->finish('Complete!'); +# Slow demo (longer delays) +php main.php progress-demo --style=dots --items=20 --delay=200 ``` -#### Custom Style and Format -```php -$progressBar = $this->createProgressBar(100) - ->setStyle(ProgressBarStyle::ASCII) - ->setFormat('[{bar}] {percent}% ({current}/{total}) ETA: {eta}') - ->setWidth(50); -``` +## πŸ“‹ Available Options -### Advanced Features +### Styles (`--style`) +- `default` - Unicode block characters (β–ˆβ–‘) - Modern terminals +- `ascii` - ASCII characters (=->) - Maximum compatibility +- `dots` - Circular dots (●○) - Clean appearance +- `arrow` - Directional arrows (β–Άβ–·) - Visual flow indication +- `custom` - Emoji style (🟩⬜) - Modern and colorful +- `all` - Demonstrate all styles sequentially -#### Progress Bar with Helper Method -```php -$this->withProgressBar($items, function($item, $index) { - // Process each item - $this->processItem($item); -}, 'Processing items...'); -``` +### Parameters +- `--items` - Number of items to process (10-1000, default: 50) +- `--delay` - Delay between items in milliseconds (default: 100) +- `--format` - Progress bar format template (eta, rate, verbose) -#### Manual Progress Control -```php -$progressBar = $this->createProgressBar(100); -$progressBar->start(); +### Validation Rules +- Items must be between 10 and 1000 +- Delay can be any positive integer +- Invalid values show helpful error messages -$progressBar->setCurrent(25); // Jump to 25% -$progressBar->advance(10); // Advance by 10 -$progressBar->finish(); -``` +## 🎨 Example Output -#### Multiple Progress Bars -```php -$mainProgress = $this->createProgressBar($totalTasks); -$subProgress = $this->createProgressBar(100); - -foreach ($tasks as $task) { - $subProgress->start("Processing $task"); - // ... sub-task processing - $subProgress->finish(); - $mainProgress->advance(); -} +### All Styles Demonstration ``` +🎯 Progress Bar Demonstration +============================= -## πŸ” Key Features +πŸ“Š Demo Configuration: + β€’ Style: All styles + β€’ Items: 20 + β€’ Delay: 50ms per item + β€’ Estimated time: 1 seconds -### 1. Progress Bar Styles -- **Default**: Unicode block characters (β–ˆβ–‘) -- **ASCII**: Compatible characters (=->) -- **Dots**: Dot characters (●○) -- **Arrow**: Arrow characters (β–Άβ–·) -- **Custom**: User-defined characters +🎨 Default Style (Unicode) +Processing with default style... [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (20/20) +Complete! [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (20/20) -### 2. Format Templates -- **Basic**: `[{bar}] {percent}% ({current}/{total})` -- **ETA**: Includes estimated time remaining -- **Rate**: Shows processing speed -- **Verbose**: All metrics included -- **Memory**: Includes memory usage +🎨 ASCII Style (Compatible) +Processing with ascii style... [========================================] 100.0% (20/20) +Complete! [========================================] 100.0% (20/20) -### 3. Real-world Applications -- **File processing**: Track file operations -- **Downloads**: Monitor transfer progress -- **Batch operations**: Multi-step workflows -- **Data processing**: Large dataset handling -- **Installation**: Setup progress tracking +🎨 Dots Style (Circular) +Processing with dots style... [●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●] 100.0% (20/20) +Complete! [●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●] 100.0% (20/20) -## 🎨 Expected Output +🎨 Arrow Style (Directional) +Processing with arrow style... [β–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Ά] 100.0% (20/20) +Complete! [β–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Ά] 100.0% (20/20) -### Style Demonstrations -``` -Default Style: -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘] 50.0% (50/100) +🎨 Custom Style (Emoji) +Processing with emoji style... πŸš€ {message} [🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩] 100.0% | ⚑ 20/s | ⏱️ 00:00 +πŸŽ‰ Emoji processing complete! πŸš€ {message} [🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩] 100.0% | ⚑ 20/s | ⏱️ 00:00 -ASCII Style: -[===========>---------] 55.0% (55/100) ETA: 00:05 +✨ Progress bar demonstration completed! +``` -Dots Style: -[●●●●●●●●●●○○○○○○○○○○] 50.0% (50/100) 12.5/s +### Individual Style Examples -Arrow Style: -[β–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·] 40.0% (40/100) +#### Default Style (Unicode) ``` - -### File Processing Example +Processing with default style... [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘] 50.0% (5/10) +Processing with default style... [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (10/10) +Complete! [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (10/10) ``` -πŸ“ Processing Files... - -Scanning directory: ./sample-files -Found 25 files to process -Processing files: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (25/25) Complete! - -πŸ“Š Processing Summary: - β€’ Files processed: 25 - β€’ Total size: 2.3 MB - β€’ Processing time: 00:12 - β€’ Average speed: 2.1 files/sec +#### ASCII Style (Compatible) +``` +Processing with ascii style... [====================--------------------] 50.0% (25/50) +Processing with ascii style... [========================================] 100.0% (50/50) +Complete! [========================================] 100.0% (50/50) ``` -### Download Simulation +#### Dots Style (Circular) +``` +Processing with dots style... [●●●●●●●●●●●●●●●○○○○○○○○○○○○○○○○○○○○○○○○○] 40.0% (6/15) ETA: 00:00 +Processing with dots style... [●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●] 100.0% (15/15) ETA: 00:00 +Complete! [●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●] 100.0% (15/15) ETA: 00:00 ``` -🌐 Download Simulator -Downloading file1.zip (10.5 MB) -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% -Speed: 2.1 MB/s | ETA: 00:00 | Elapsed: 00:05 +#### Arrow Style (Directional) +``` +Processing with arrow style... [β–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·β–·] 40.0% (10/25) 25/s +Processing with arrow style... [β–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Ά] 100.0% (25/25) 25/s +Complete! [β–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Άβ–Ά] 100.0% (25/25) 25/s +``` -Downloading file2.pdf (5.2 MB) -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘] 52.0% -Speed: 1.8 MB/s | ETA: 00:03 | Elapsed: 00:02 +#### Custom Style (Emoji with Verbose Format) +``` +Processing with emoji style... πŸš€ {message} [🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜] 50.0% | ⚑ 6.6/s | ⏱️ 00:00 +Processing with emoji style... πŸš€ {message} [🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩] 100.0% | ⚑ 6.6/s | ⏱️ 00:00 +πŸŽ‰ Emoji processing complete! πŸš€ {message} [🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩] 100.0% | ⚑ 6.6/s | ⏱️ 00:00 +``` -βœ… All downloads completed! -Total downloaded: 45.7 MB in 00:23 +### Error Handling ``` +# Invalid item count (too low) +php main.php progress-demo --items=5 +Error: Number of items must be between 10 and 1000 -### Batch Processing +# Invalid item count (too high) +php main.php progress-demo --items=1001 +Error: Number of items must be between 10 and 1000 ``` -πŸ”„ Batch Processor -Batch 1/3: Data Validation -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (100/100) +## πŸ§ͺ Test Scenarios -Batch 2/3: Data Transformation -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (100/100) +### 1. All Styles Demo +```bash +php main.php progress-demo --style=all --items=20 --delay=50 +# Shows all 5 styles in sequence with consistent parameters +``` -Batch 3/3: Data Export -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% (100/100) +### 2. Performance Comparison +```bash +# Fast processing +php main.php progress-demo --style=ascii --items=50 --delay=20 + +# Medium processing +php main.php progress-demo --style=default --items=25 --delay=100 -πŸŽ‰ All batches completed successfully! -Total items processed: 300 -Total time: 00:45 +# Slow processing +php main.php progress-demo --style=custom --items=12 --delay=150 ``` -## πŸ”— Next Steps +### 3. Format Testing +```bash +# ETA format +php main.php progress-demo --style=dots --format=eta --items=15 -After mastering this example, move on to: -- **[10-multi-command-app](../10-multi-command-app/)** - Building complete CLI applications -- **[13-database-cli](../13-database-cli/)** - Database management with progress tracking +# Rate format +php main.php progress-demo --style=arrow --format=rate --items=25 -## πŸ’‘ Try This +# Verbose format +php main.php progress-demo --style=custom --format=verbose --items=12 +``` -Experiment with the code: +### 4. Edge Cases +```bash +# Minimum items +php main.php progress-demo --style=default --items=10 --delay=50 -1. **Create custom progress styles**: Design your own progress characters -2. **Add sound effects**: Beep on completion (where supported) -3. **Network progress**: Real HTTP download progress -4. **Nested progress**: Progress bars within progress bars +# Maximum items (test with caution - takes time) +php main.php progress-demo --style=ascii --items=1000 --delay=1 -```php -// Example: Custom progress style with emojis -$customStyle = new ProgressBarStyle('🟩', '⬜', '🟨'); -$progressBar->setStyle($customStyle); +# Boundary validation +php main.php progress-demo --items=9 # Error: too low +php main.php progress-demo --items=1001 # Error: too high +``` -// Example: Progress with custom format -$progressBar->setFormat('πŸš€ {message} [{bar}] {percent}% | ⚑ {rate}/s | ⏱️ {eta}'); +### 5. Style Comparison +```bash +# Unicode vs ASCII compatibility +php main.php progress-demo --style=default --items=20 --delay=50 +php main.php progress-demo --style=ascii --items=20 --delay=50 + +# Visual styles comparison +php main.php progress-demo --style=dots --items=20 --delay=50 +php main.php progress-demo --style=arrow --items=20 --delay=50 +php main.php progress-demo --style=custom --items=20 --delay=50 ``` + +## πŸ’‘ Key Features Demonstrated + +### 1. Real-Time Updates +- **Live Progress**: Updates show in real-time as work progresses +- **Percentage Display**: Current completion percentage +- **Item Counters**: Current/total item counts +- **Rate Calculation**: Items processed per second +- **ETA Estimation**: Estimated time to completion + +### 2. Visual Styles +- **Unicode Blocks**: Modern terminals with full block characters +- **ASCII Compatible**: Works on all terminal types +- **Dot Indicators**: Clean circular progress indicators +- **Arrow Flow**: Directional progress indication +- **Emoji Style**: Modern colorful progress with emojis + +### 3. Format Templates +- **Basic Format**: `[bar] percentage (current/total)` +- **ETA Format**: Includes estimated time remaining +- **Rate Format**: Shows processing speed +- **Verbose Format**: All metrics with emojis and timing + +### 4. Performance Metrics +- **Processing Rate**: Items per second calculation +- **Time Tracking**: Elapsed and estimated time +- **Progress Percentage**: Accurate completion percentage +- **Item Counting**: Current and total item tracking + +## πŸ”§ Technical Implementation + +### Core Classes Used +- `ProgressDemoCommand`: Main demonstration command +- `ProgressBarFormat`: Format template definitions +- `ProgressBar`: Core progress bar functionality +- `ArgumentOption`: Command argument configuration + +### Key Methods +- `demonstrateStyle()`: Individual style demonstrations +- `createProgressBar()`: Progress bar creation and setup +- `simulateWork()`: Work simulation with delays +- `validateParameters()`: Input validation and error handling + +### Configuration Options +- Style selection and character definitions +- Format template customization +- Timing and delay controls +- Item count validation and limits + +## 🎯 Best Practices Demonstrated + +### 1. User Experience +- Clear visual progress indication +- Consistent formatting across styles +- Helpful error messages for invalid input +- Estimated completion times + +### 2. Performance +- Efficient real-time updates +- Minimal CPU overhead during updates +- Accurate rate calculations +- Responsive progress tracking + +### 3. Compatibility +- ASCII fallback for older terminals +- Unicode support for modern terminals +- Cross-platform character support +- Terminal width adaptation + +### 4. Validation +- Input parameter validation +- Helpful error messages +- Boundary checking (10-1000 items) +- Type validation for arguments + +## πŸ”— Related Examples + +- **[04-output-formatting](../04-output-formatting/)** - ANSI colors and formatting +- **[06-table-display](../06-table-display/)** - Data presentation techniques +- **[08-file-processing](../08-file-processing/)** - File operations with progress +- **[10-multi-command-app](../10-multi-command-app/)** - Complete CLI applications diff --git a/examples/07-progress-bars/main.php b/examples/07-progress-bars/main.php index f96c40b..1d7cc6a 100644 --- a/examples/07-progress-bars/main.php +++ b/examples/07-progress-bars/main.php @@ -11,7 +11,6 @@ * - Performance monitoring and optimization */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load dependencies @@ -22,11 +21,9 @@ $runner = new Runner(); // Register commands -$runner->register(new HelpCommand()); $runner->register(new ProgressDemoCommand()); // Set default command -$runner->setDefaultCommand('help'); // Start the application exit($runner->start()); From bbf80fc33d01dfd67a67673715bcfd2d0e6368d9 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:29:18 +0300 Subject: [PATCH 08/12] docs: Updated Example 09 --- examples/08-file-processing/README.md | 276 +++++++++++++++++++++++++ examples/08-file-processing/app.php | 72 +++++++ examples/08-file-processing/sample.txt | 4 + 3 files changed, 352 insertions(+) create mode 100644 examples/08-file-processing/README.md create mode 100644 examples/08-file-processing/app.php create mode 100644 examples/08-file-processing/sample.txt diff --git a/examples/08-file-processing/README.md b/examples/08-file-processing/README.md new file mode 100644 index 0000000..c530980 --- /dev/null +++ b/examples/08-file-processing/README.md @@ -0,0 +1,276 @@ +# File Processing Example + +This example demonstrates file processing capabilities in WebFiori CLI, showcasing text file operations, statistics calculation, and content manipulation. + +## 🎯 What You'll Learn + +- Reading and processing text files +- File content analysis and statistics +- Text transformation operations +- Error handling for file operations +- Command argument validation +- File existence and accessibility checks + +## πŸ“ Files + +- `app.php` - Main file processing command implementation +- `sample.txt` - Sample text file for testing +- `README.md` - This documentation + +## πŸš€ Running the Example + +### Basic Usage +```bash +# Process sample file with default action (count) +php app.php process-file --file=sample.txt + +# Show help +php app.php help --command=process-file +``` + +### File Statistics (Count Action) +```bash +# Count lines, words, and characters +php app.php process-file --file=sample.txt --action=count + +# Default action is count (can be omitted) +php app.php process-file --file=sample.txt +``` + +### Text Transformation +```bash +# Convert to uppercase +php app.php process-file --file=sample.txt --action=uppercase + +# Reverse line order +php app.php process-file --file=sample.txt --action=reverse +``` + +## πŸ“‹ Available Options + +### Actions (`--action`) +- `count` - Display file statistics (lines, words, characters) - **Default** +- `uppercase` - Convert all text to uppercase +- `reverse` - Reverse the order of lines in the file + +### Parameters +- `--file` - Path to the file to process (**Required**) +- `--action` - Action to perform (optional, defaults to `count`) + +### Validation Rules +- File path is required +- File must exist and be readable +- Action must be one of: count, uppercase, reverse +- Invalid actions show available options + +## 🎨 Example Output + +### File Statistics (Count Action) +```bash +php app.php process-file --file=sample.txt --action=count +``` +``` +File Statistics for: sample.txt +Lines: 5 +Words: 14 +Characters: 82 +``` + +### Uppercase Transformation +```bash +php app.php process-file --file=sample.txt --action=uppercase +``` +``` +Uppercase content: +HELLO WORLD +THIS IS A SAMPLE FILE +FOR TESTING FILE PROCESSING +WITH MULTIPLE LINES +``` + +### Line Reversal +```bash +php app.php process-file --file=sample.txt --action=reverse +``` +``` +Reversed content: + +With multiple lines +For testing file processing +This is a sample file +Hello World +``` + +### Error Handling Examples + +#### File Not Found +```bash +php app.php process-file --file=nonexistent.txt --action=count +``` +``` +Error: File not found: nonexistent.txt +``` + +#### Missing Required Argument +```bash +php app.php process-file --action=count +``` +``` +Error: The following required argument(s) are missing: '--file' +``` + +#### Invalid Action +```bash +php app.php process-file --file=sample.txt --action=invalid +``` +``` +Error: The following argument(s) have invalid values: '--action' +Info: Allowed values for the argument '--action': +count +uppercase +reverse +``` + +## πŸ§ͺ Test Scenarios + +### 1. Basic File Operations +```bash +# Test all actions on sample file +php app.php process-file --file=sample.txt --action=count +php app.php process-file --file=sample.txt --action=uppercase +php app.php process-file --file=sample.txt --action=reverse +``` + +### 2. Different File Types +```bash +# Create test files +echo -e "Line 1\nLine 2\nLine 3" > test1.txt +echo "Single line file" > test2.txt +touch empty.txt + +# Test with different content +php app.php process-file --file=test1.txt --action=count +php app.php process-file --file=test2.txt --action=count +php app.php process-file --file=empty.txt --action=count +``` + +### 3. Large File Processing +```bash +# Create large file +for i in {1..100}; do echo "Line $i with some content"; done > large.txt + +# Process large file +php app.php process-file --file=large.txt --action=count +``` + +### 4. Error Cases +```bash +# Test error handling +php app.php process-file --file=nonexistent.txt --action=count +php app.php process-file --action=count +php app.php process-file --file=sample.txt --action=invalid +``` + +### 5. Edge Cases +```bash +# Test with special files +echo " " > spaces.txt # Only spaces +echo -e "\x00\x01\x02" > binary.txt # Binary content +mkdir testdir # Directory instead of file + +php app.php process-file --file=spaces.txt --action=count +php app.php process-file --file=binary.txt --action=count +php app.php process-file --file=testdir --action=count # Shows warning +``` + +## πŸ’‘ Key Features Demonstrated + +### 1. File Operations +- **File Reading**: Safe file content reading with error handling +- **File Validation**: Check file existence and accessibility +- **Content Processing**: Line-by-line and full content processing +- **Statistics Calculation**: Lines, words, and character counting + +### 2. Text Processing +- **Case Conversion**: Transform text to uppercase +- **Line Manipulation**: Reverse line order in files +- **Content Analysis**: Word and character counting +- **Encoding Handling**: Process various text encodings + +### 3. Error Handling +- **File Not Found**: Clear error messages for missing files +- **Invalid Arguments**: Validation with helpful suggestions +- **Required Parameters**: Check for mandatory arguments +- **File Access Issues**: Handle permission and directory errors + +### 4. User Experience +- **Clear Output**: Well-formatted results with labels +- **Help Integration**: Built-in help command support +- **Validation Messages**: Helpful error messages with suggestions +- **Default Values**: Sensible defaults for optional parameters + +## πŸ”§ Technical Implementation + +### Core Functionality +```php +class FileProcessCommand extends Command { + public function __construct() { + parent::__construct('process-file', [ + '--file' => [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'Path to the file to process' + ], + '--action' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DEFAULT => 'count', + ArgumentOption::VALUES => ['count', 'uppercase', 'reverse'], + ArgumentOption::DESCRIPTION => 'Action to perform' + ] + ], 'Process text files in various ways'); + } +} +``` + +### File Processing Methods +- `validateFile()`: Check file existence and readability +- `countStatistics()`: Calculate lines, words, characters +- `transformContent()`: Apply text transformations +- `handleErrors()`: Provide meaningful error messages + +### Statistics Calculation +- **Lines**: Count newline characters + 1 +- **Words**: Split by whitespace and count non-empty elements +- **Characters**: Total byte count including whitespace and newlines + +## 🎯 Best Practices Demonstrated + +### 1. Input Validation +- Required parameter checking +- File existence validation +- Action value validation with allowed options +- Clear error messages for invalid input + +### 2. File Handling +- Safe file reading with error checking +- Proper handling of empty files +- Binary file detection and handling +- Directory vs file differentiation + +### 3. User Experience +- Consistent output formatting +- Helpful error messages +- Default parameter values +- Comprehensive help documentation + +### 4. Error Recovery +- Graceful handling of missing files +- Clear validation error messages +- Suggestions for valid parameter values +- Non-zero exit codes for errors + +## πŸ”— Related Examples + +- **[03-user-input](../03-user-input/)** - Input validation and handling +- **[04-output-formatting](../04-output-formatting/)** - Text formatting and colors +- **[07-progress-bars](../07-progress-bars/)** - Progress tracking for file operations +- **[10-multi-command-app](../10-multi-command-app/)** - Complete CLI applications diff --git a/examples/08-file-processing/app.php b/examples/08-file-processing/app.php new file mode 100644 index 0000000..6880e0c --- /dev/null +++ b/examples/08-file-processing/app.php @@ -0,0 +1,72 @@ + [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'Path to the file to process' + ], + '--action' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DEFAULT => 'count', + ArgumentOption::VALUES => ['count', 'uppercase', 'reverse'], + ArgumentOption::DESCRIPTION => 'Action to perform (count, uppercase, reverse)' + ] + ], 'Process text files in various ways'); + } + + public function exec(): int { + $filePath = $this->getArgValue('--file'); + $action = $this->getArgValue('--action'); + + if (!file_exists($filePath)) { + $this->error("File not found: $filePath"); + return 1; + } + + if (!is_readable($filePath)) { + $this->error("File is not readable: $filePath"); + return 1; + } + + $content = file_get_contents($filePath); + + switch ($action) { + case 'count': + $lines = substr_count($content, "\n") + 1; + $words = str_word_count($content); + $chars = strlen($content); + + $this->println("File Statistics for: %s", $filePath); + $this->println("Lines: %d", $lines); + $this->println("Words: %d", $words); + $this->println("Characters: %d", $chars); + break; + + case 'uppercase': + $result = strtoupper($content); + $this->println("Uppercase content:"); + $this->println($result); + break; + + case 'reverse': + $lines = explode("\n", $content); + $reversed = array_reverse($lines); + $this->println("Reversed content:"); + $this->println(implode("\n", $reversed)); + break; + } + + return 0; + } +} + +$runner = new Runner(); +$runner->register(new FileProcessCommand()); +exit($runner->start()); diff --git a/examples/08-file-processing/sample.txt b/examples/08-file-processing/sample.txt new file mode 100644 index 0000000..27e3454 --- /dev/null +++ b/examples/08-file-processing/sample.txt @@ -0,0 +1,4 @@ +Hello World +This is a sample file +For testing file processing +With multiple lines From e3cad4c2e6f3c6fc4a4544049ad5532fac290ee7 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:30:20 +0300 Subject: [PATCH 09/12] docs: Updated Example 09 --- examples/09-database-ops/DatabaseManager.php | 578 +++++++++++++++++ examples/09-database-ops/README.md | 601 ++++++++++++++++++ examples/09-database-ops/main.php | 320 ++++++++++ .../migrations/001_create_users_table.sql | 14 + examples/09-database-ops/seeds/users.json | 32 + 5 files changed, 1545 insertions(+) create mode 100644 examples/09-database-ops/DatabaseManager.php create mode 100644 examples/09-database-ops/README.md create mode 100644 examples/09-database-ops/main.php create mode 100644 examples/09-database-ops/migrations/001_create_users_table.sql create mode 100644 examples/09-database-ops/seeds/users.json diff --git a/examples/09-database-ops/DatabaseManager.php b/examples/09-database-ops/DatabaseManager.php new file mode 100644 index 0000000..df94064 --- /dev/null +++ b/examples/09-database-ops/DatabaseManager.php @@ -0,0 +1,578 @@ +migrationsPath = $basePath.'/migrations'; + $this->seedsPath = $basePath.'/seeds'; + $this->loadConfig(); + } + + /** + * Connect to database. + */ + public function connect(array $config = null): bool { + if ($config) { + $this->config = array_merge($this->config, $config); + } + + try { + $dsn = $this->buildDsn(); + $this->connection = new PDO( + $dsn, + $this->config['username'] ?? '', + $this->config['password'] ?? '', + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false + ] + ); + + return true; + } catch (PDOException $e) { + throw new Exception("Database connection failed: ".$e->getMessage()); + } + } + + /** + * Create database backup. + */ + public function createBackup(string $outputPath = null): array { + $this->ensureConnected(); + + if (!$outputPath) { + $timestamp = date('Y-m-d_H-i-s'); + $outputPath = "backup_{$timestamp}.sql"; + } + + $tables = $this->getTables(); + $backup = []; + + // Add header + $backup[] = "-- Database Backup"; + $backup[] = "-- Generated: ".date('Y-m-d H:i:s'); + $backup[] = "-- Database: ".($this->config['database'] ?? 'unknown'); + $backup[] = ""; + + foreach ($tables as $table) { + $tableName = $table['name']; + + // Skip migrations table + if ($tableName === 'migrations') { + continue; + } + + $backup[] = "-- Table: $tableName"; + $backup[] = "DROP TABLE IF EXISTS `$tableName`;"; + + // Get CREATE TABLE statement + $createResult = $this->query("SHOW CREATE TABLE `$tableName`"); + + if ($createResult['success'] && !empty($createResult['data'])) { + $createStatement = $createResult['data'][0]['Create Table'] ?? ''; + $backup[] = $createStatement.";"; + } + + // Get table data + $dataResult = $this->query("SELECT * FROM `$tableName`"); + + if ($dataResult['success'] && !empty($dataResult['data'])) { + $backup[] = ""; + + foreach ($dataResult['data'] as $row) { + $values = array_map(function ($value) { + return $value === null ? 'NULL' : "'".addslashes($value)."'"; + }, array_values($row)); + + $columns = '`'.implode('`, `', array_keys($row)).'`'; + $backup[] = "INSERT INTO `$tableName` ($columns) VALUES (".implode(', ', $values).");"; + } + } + + $backup[] = ""; + } + + $backupContent = implode("\n", $backup); + + if (file_put_contents($outputPath, $backupContent) !== false) { + return [ + 'success' => true, + 'file' => $outputPath, + 'size' => strlen($backupContent), + 'tables' => count($tables) + ]; + } else { + return [ + 'success' => false, + 'error' => "Failed to write backup file: $outputPath" + ]; + } + } + + /** + * Get list of available migrations. + */ + public function getAvailableMigrations(): array { + if (!is_dir($this->migrationsPath)) { + return []; + } + + $files = glob($this->migrationsPath.'/*.sql'); + $migrations = []; + + foreach ($files as $file) { + $filename = basename($file); + $migrations[] = [ + 'filename' => $filename, + 'path' => $file, + 'name' => pathinfo($filename, PATHINFO_FILENAME), + 'size' => filesize($file), + 'modified' => filemtime($file) + ]; + } + + // Sort by filename (which should include version numbers) + usort($migrations, fn($a, $b) => strcmp($a['filename'], $b['filename'])); + + return $migrations; + } + + /** + * Get connection status information. + */ + public function getConnectionStatus(): array { + if (!$this->isConnected()) { + return [ + 'connected' => false, + 'error' => 'Not connected to database' + ]; + } + + try { + $stmt = $this->connection->query('SELECT VERSION() as version'); + $result = $stmt->fetch(); + + return [ + 'connected' => true, + 'host' => $this->config['host'] ?? 'unknown', + 'database' => $this->config['database'] ?? 'unknown', + 'version' => $result['version'] ?? 'unknown', + 'driver' => $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME) + ]; + } catch (PDOException $e) { + return [ + 'connected' => false, + 'error' => $e->getMessage() + ]; + } + } + + /** + * Get executed migrations. + */ + public function getExecutedMigrations(): array { + $this->ensureConnected(); + $this->ensureMigrationsTable(); + + $result = $this->query('SELECT * FROM migrations ORDER BY executed_at ASC'); + + return $result['success'] ? $result['data'] : []; + } + + /** + * Get database schema information. + */ + public function getSchema(): array { + $this->ensureConnected(); + + $tables = $this->getTables(); + $schema = [ + 'database' => $this->config['database'] ?? 'unknown', + 'tables' => [], + 'total_tables' => count($tables), + 'total_size' => 0 + ]; + + foreach ($tables as $table) { + $tableInfo = $this->getTableInfo($table['name']); + $schema['tables'][] = $tableInfo; + $schema['total_size'] += $tableInfo['size_bytes'] ?? 0; + } + + return $schema; + } + + /** + * Get table columns. + */ + public function getTableColumns(string $tableName): array { + $this->ensureConnected(); + + $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); + + switch ($driver) { + case 'mysql': + $sql = "DESCRIBE `$tableName`"; + break; + case 'pgsql': + $sql = "SELECT column_name, data_type, is_nullable + FROM information_schema.columns + WHERE table_name = '$tableName'"; + break; + case 'sqlite': + $sql = "PRAGMA table_info($tableName)"; + break; + default: + return []; + } + + $result = $this->query($sql); + + return $result['success'] ? $result['data'] : []; + } + + /** + * Get detailed table information. + */ + public function getTableInfo(string $tableName): array { + $this->ensureConnected(); + + $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); + + // Get column information + $columns = $this->getTableColumns($tableName); + + // Get row count + $countResult = $this->query("SELECT COUNT(*) as count FROM `$tableName`"); + $rowCount = $countResult['success'] ? $countResult['data'][0]['count'] : 0; + + // Get table size (MySQL specific) + $sizeBytes = 0; + + if ($driver === 'mysql') { + $sizeResult = $this->query( + "SELECT (data_length + index_length) as size_bytes + FROM information_schema.tables + WHERE table_schema = ? AND table_name = ?", + [$this->config['database'], $tableName] + ); + + if ($sizeResult['success'] && !empty($sizeResult['data'])) { + $sizeBytes = $sizeResult['data'][0]['size_bytes'] ?? 0; + } + } + + return [ + 'name' => $tableName, + 'columns' => $columns, + 'column_count' => count($columns), + 'row_count' => $rowCount, + 'size_bytes' => $sizeBytes, + 'size_human' => $this->formatBytes($sizeBytes) + ]; + } + + /** + * Get list of tables. + */ + public function getTables(): array { + $this->ensureConnected(); + + $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); + + switch ($driver) { + case 'mysql': + $sql = 'SHOW TABLES'; + break; + case 'pgsql': + $sql = "SELECT tablename as table_name FROM pg_tables WHERE schemaname = 'public'"; + break; + case 'sqlite': + $sql = "SELECT name as table_name FROM sqlite_master WHERE type='table'"; + break; + default: + throw new Exception("Unsupported database driver: $driver"); + } + + $result = $this->query($sql); + + if (!$result['success']) { + return []; + } + + $tables = []; + + foreach ($result['data'] as $row) { + $tableName = array_values($row)[0]; // Get first column value + $tables[] = ['name' => $tableName]; + } + + return $tables; + } + + /** + * Check if connected to database. + */ + public function isConnected(): bool { + return $this->connection !== null; + } + + /** + * Execute SQL query. + */ + public function query(string $sql, array $params = []): array { + $this->ensureConnected(); + + $startTime = microtime(true); + + try { + if (empty($params)) { + $stmt = $this->connection->query($sql); + } else { + $stmt = $this->connection->prepare($sql); + $stmt->execute($params); + } + + $executionTime = microtime(true) - $startTime; + + // Record query for history + $this->executedQueries[] = [ + 'sql' => $sql, + 'params' => $params, + 'execution_time' => $executionTime, + 'timestamp' => date('Y-m-d H:i:s') + ]; + + $results = $stmt->fetchAll(); + + return [ + 'success' => true, + 'data' => $results, + 'row_count' => $stmt->rowCount(), + 'execution_time' => $executionTime, + 'affected_rows' => $stmt->rowCount() + ]; + } catch (PDOException $e) { + return [ + 'success' => false, + 'error' => $e->getMessage(), + 'sql' => $sql, + 'execution_time' => microtime(true) - $startTime + ]; + } + } + + /** + * Run migration. + */ + public function runMigration(string $filename): array { + $this->ensureConnected(); + $this->ensureMigrationsTable(); + + $migrationPath = $this->migrationsPath.'/'.$filename; + + if (!file_exists($migrationPath)) { + return [ + 'success' => false, + 'error' => "Migration file not found: $filename" + ]; + } + + // Check if already executed + $result = $this->query('SELECT COUNT(*) as count FROM migrations WHERE filename = ?', [$filename]); + + if ($result['success'] && $result['data'][0]['count'] > 0) { + return [ + 'success' => false, + 'error' => "Migration already executed: $filename" + ]; + } + + // Read and execute migration + $sql = file_get_contents($migrationPath); + $statements = $this->splitSqlStatements($sql); + + $this->connection->beginTransaction(); + + try { + foreach ($statements as $statement) { + if (trim($statement)) { + $this->connection->exec($statement); + } + } + + // Record migration + $this->query( + 'INSERT INTO migrations (filename, executed_at) VALUES (?, ?)', + [$filename, date('Y-m-d H:i:s')] + ); + + $this->connection->commit(); + + return [ + 'success' => true, + 'message' => "Migration executed successfully: $filename" + ]; + } catch (PDOException $e) { + $this->connection->rollBack(); + + return [ + 'success' => false, + 'error' => "Migration failed: ".$e->getMessage() + ]; + } + } + + /** + * Seed database with test data. + */ + public function seedTable(string $tableName, string $seedFile = null): array { + $this->ensureConnected(); + + if (!$seedFile) { + $seedFile = $this->seedsPath."/{$tableName}.json"; + } + + if (!file_exists($seedFile)) { + return [ + 'success' => false, + 'error' => "Seed file not found: $seedFile" + ]; + } + + $seedData = json_decode(file_get_contents($seedFile), true); + + if (json_last_error() !== JSON_ERROR_NONE) { + return [ + 'success' => false, + 'error' => "Invalid JSON in seed file: ".json_last_error_msg() + ]; + } + + if (empty($seedData)) { + return [ + 'success' => false, + 'error' => "No data found in seed file" + ]; + } + + $inserted = 0; + $errors = []; + + foreach ($seedData as $record) { + $columns = array_keys($record); + $placeholders = array_fill(0, count($columns), '?'); + + $sql = "INSERT INTO `$tableName` (`".implode('`, `', $columns)."`) VALUES (".implode(', ', $placeholders).")"; + + $result = $this->query($sql, array_values($record)); + + if ($result['success']) { + $inserted++; + } else { + $errors[] = $result['error']; + } + } + + return [ + 'success' => empty($errors), + 'inserted' => $inserted, + 'total' => count($seedData), + 'errors' => $errors + ]; + } + + /** + * Build DSN string from config. + */ + private function buildDsn(): string { + $driver = $this->config['driver'] ?? 'mysql'; + $host = $this->config['host'] ?? 'localhost'; + $port = $this->config['port'] ?? 3306; + $database = $this->config['database'] ?? ''; + + return "$driver:host=$host;port=$port;dbname=$database;charset=utf8mb4"; + } + + /** + * Ensure database connection exists. + */ + private function ensureConnected(): void { + if (!$this->isConnected()) { + throw new Exception('Not connected to database. Call connect() first.'); + } + } + + /** + * Ensure migrations table exists. + */ + private function ensureMigrationsTable(): void { + $sql = "CREATE TABLE IF NOT EXISTS migrations ( + id INT AUTO_INCREMENT PRIMARY KEY, + filename VARCHAR(255) NOT NULL UNIQUE, + executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )"; + + $this->connection->exec($sql); + } + + /** + * Format bytes to human readable format. + */ + private function formatBytes(int $bytes): string { + if ($bytes === 0) { + return '0 B'; + } + + $units = ['B', 'KB', 'MB', 'GB', 'TB']; + $unitIndex = 0; + + while ($bytes >= 1024 && $unitIndex < count($units) - 1) { + $bytes /= 1024; + $unitIndex++; + } + + return sprintf('%.1f %s', $bytes, $units[$unitIndex]); + } + + /** + * Load database configuration. + */ + private function loadConfig(): void { + $this->config = [ + 'driver' => 'mysql', + 'host' => 'localhost', + 'port' => 3306, + 'database' => 'testing_db', + 'username' => 'root', + 'password' => '123456' + ]; + } + + /** + * Split SQL into individual statements. + */ + private function splitSqlStatements(string $sql): array { + // Simple split by semicolon (could be improved for complex cases) + $statements = explode(';', $sql); + + return array_filter(array_map('trim', $statements)); + } +} diff --git a/examples/09-database-ops/README.md b/examples/09-database-ops/README.md new file mode 100644 index 0000000..6788a8c --- /dev/null +++ b/examples/09-database-ops/README.md @@ -0,0 +1,601 @@ +# Database Operations Example + +This example demonstrates comprehensive database management capabilities in WebFiori CLI, showcasing connection management, migrations, data seeding, query execution, and backup operations using MySQL. + +## 🎯 What You'll Learn + +- Database connection management with MySQL +- Migration system for schema management +- Data seeding with sample records +- Interactive query execution with formatted results +- Database backup and restore operations +- Schema inspection and status monitoring +- Error handling for database operations +- Table display for query results + +## πŸ“ Files + +- `main.php` - Main CLI application with database commands +- `DatabaseManager.php` - Core database functionality and connection management +- `README.md` - This documentation + +## πŸ”§ Database Configuration + +The example uses MySQL with the following configuration: +- **Host**: localhost:3306 +- **Database**: testing_db +- **Username**: root +- **Password**: 123456 +- **Driver**: MySQL with PDO + +## πŸš€ Running the Example + +### Basic Usage +```bash +# Show help +php main.php help --command=db + +# Test database connection +php main.php db --action=connect +``` + +### Database Operations +```bash +# Run migrations (create tables) +php main.php db --action=migrate + +# Seed database with sample data +php main.php db --action=seed + +# Check database status +php main.php db --action=status + +# Execute custom queries +php main.php db --action=query --sql="SELECT * FROM users" + +# Create backup +php main.php db --action=backup --file=my_backup.sql + +# Restore from backup +php main.php db --action=restore --file=my_backup.sql + +# Clean up database (drop tables) +php main.php db --action=cleanup +``` + +## πŸ“‹ Available Actions + +### Database Actions (`--action`) +- `connect` - Test database connection and show details +- `migrate` - Run database migrations (create tables) +- `seed` - Populate database with sample data +- `query` - Execute custom SQL queries +- `backup` - Create database backup to file +- `restore` - Restore database from backup file +- `status` - Show database status and table information +- `cleanup` - Clean up database (drop all tables) + +### Parameters +- `--action` - Database action to perform (**Required**) +- `--sql` - SQL query to execute (required for `query` action) +- `--file` - File path for backup/restore operations (optional) + +### Validation Rules +- Action is required and must be valid +- SQL parameter required for query action +- File parameter required for restore action +- Backup creates timestamped files if no filename provided + +## 🎨 Example Output + +### Database Connection Test +```bash +php main.php db --action=connect +``` +``` +πŸ”Œ Testing database connection... +βœ… Database connection successful! +πŸ“Š Connection details: + β€’ Host: localhost:3306 + β€’ Database: testing_db + β€’ Username: root +``` + +### Running Migrations +```bash +php main.php db --action=migrate +``` +``` +πŸš€ Running database migrations... + β€’ Running migration 1... + β€’ Running migration 2... +βœ… Migrations completed successfully! +``` + +### Seeding Database +```bash +php main.php db --action=seed +``` +``` +🌱 Seeding database with sample data... +βœ… Database seeded successfully! + β€’ Added 3 users + β€’ Added 4 posts +``` + +### Database Status +```bash +php main.php db --action=status +``` +``` +πŸ“Š Database Status +================== +πŸ“‹ Tables: 3 + β€’ posts: 4 records + β€’ user_profiles: 0 records + β€’ users: 3 records +``` + +### Query Execution with Results +```bash +php main.php db --action=query --sql="SELECT * FROM users LIMIT 2" +``` +``` +πŸ” Executing query... +SQL: SELECT * FROM users LIMIT 2 +πŸ“Š Query results: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Id β”‚ Name β”‚ Email β”‚ Created At β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 1 β”‚ John Doe β”‚ john@example.com β”‚ 2025-09-27 19:17:26 β”‚ +β”‚ 2 β”‚ Jane Smith β”‚ jane@example.com β”‚ 2025-09-27 19:17:26 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +⏱️ Execution time: 3.79ms +``` + +### Complex Query Results +```bash +php main.php db --action=query --sql="SELECT * FROM posts" +``` +``` +πŸ” Executing query... +SQL: SELECT * FROM posts +πŸ“Š Query results: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Id β”‚ User Id β”‚ Title β”‚ Content β”‚ Created At β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 1 β”‚ 1 β”‚ First Post β”‚ This is the content of the first post. β”‚ 2025-09-27 19:17:26 β”‚ +β”‚ 2 β”‚ 1 β”‚ Second Post β”‚ This is another post by John. β”‚ 2025-09-27 19:17:26 β”‚ +β”‚ 3 β”‚ 2 β”‚ Jane's Post β”‚ Hello from Jane! β”‚ 2025-09-27 19:17:26 β”‚ +β”‚ 4 β”‚ 3 β”‚ Bob's Thoughts β”‚ Some thoughts from Bob. β”‚ 2025-09-27 19:17:26 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +⏱️ Execution time: 3.26ms +``` + +### Database Backup +```bash +php main.php db --action=backup --file=test_backup.sql +``` +``` +πŸ’Ύ Creating database backup... +File: test_backup.sql +βœ… Backup created successfully! + β€’ File: test_backup.sql + β€’ Size: 2,299 bytes + β€’ Tables: 3 +``` + +### Database Cleanup +```bash +php main.php db --action=cleanup +``` +``` +🧹 Cleaning up database... + β€’ Dropping table: posts + β€’ Dropping table: users +βœ… Database cleanup completed! +``` + +### Error Handling Examples + +#### Missing Required Action +```bash +php main.php db +``` +``` +Error: The following required argument(s) are missing: '--action' +``` + +#### Invalid Action +```bash +php main.php db --action=invalid +``` +``` +Error: The following argument(s) have invalid values: '--action' +Info: Allowed values for the argument '--action': +connect +migrate +seed +query +backup +restore +status +cleanup +``` + +#### Missing SQL for Query +```bash +php main.php db --action=query +``` +``` +❌ SQL query is required for query action +Usage: php main.php db --action=query --sql="SELECT * FROM users" +``` + +## πŸ§ͺ Test Scenarios + +### 1. Complete Database Workflow +```bash +# Full workflow from setup to cleanup +php main.php db --action=connect +php main.php db --action=migrate +php main.php db --action=seed +php main.php db --action=status +php main.php db --action=backup --file=full_backup.sql +php main.php db --action=cleanup +``` + +### 2. Query Testing +```bash +# Test different types of queries +php main.php db --action=query --sql="SELECT COUNT(*) as total FROM users" +php main.php db --action=query --sql="SELECT name, email FROM users WHERE id = 1" +php main.php db --action=query --sql="SHOW TABLES" +php main.php db --action=query --sql="DESCRIBE users" +``` + +### 3. Backup and Restore Cycle +```bash +# Create backup, cleanup, then restore +php main.php db --action=backup --file=cycle_backup.sql +php main.php db --action=cleanup +php main.php db --action=status # Should show empty/minimal tables +php main.php db --action=restore --file=cycle_backup.sql +php main.php db --action=status # Should show restored data +``` + +### 4. Error Handling +```bash +# Test various error conditions +php main.php db --action=query --sql="SELECT * FROM nonexistent_table" +php main.php db --action=restore --file=nonexistent.sql +php main.php db --action=query # Missing SQL parameter +``` + +### 5. Performance Testing +```bash +# Test with larger datasets and measure execution time +php main.php db --action=query --sql="SELECT * FROM users ORDER BY created_at DESC" +php main.php db --action=query --sql="SELECT COUNT(*) FROM posts GROUP BY user_id" +``` + +## πŸ’‘ Key Features Demonstrated + +### 1. Database Connection Management +- **PDO Integration**: Secure database connections with prepared statements +- **Configuration Management**: Centralized database configuration +- **Connection Testing**: Verify database connectivity and credentials +- **Error Handling**: Graceful handling of connection failures + +### 2. Schema Management +- **Migration System**: Automated table creation and schema updates +- **Foreign Key Constraints**: Proper relational database design +- **Index Management**: Performance optimization with database indexes +- **Schema Inspection**: View table structure and relationships + +### 3. Data Operations +- **Data Seeding**: Populate tables with sample data for testing +- **Query Execution**: Execute arbitrary SQL queries safely +- **Result Formatting**: Display query results in formatted tables +- **Performance Monitoring**: Track query execution times + +### 4. Backup and Recovery +- **Full Database Backup**: Export complete database structure and data +- **Restore Operations**: Rebuild database from backup files +- **File Management**: Timestamped backup files with size information +- **Data Integrity**: Maintain referential integrity during operations + +### 5. User Experience +- **Formatted Output**: Uses WebFiori CLI's built-in `table()` method for consistent formatting +- **Progress Indicators**: Visual feedback for long-running operations +- **Error Messages**: Clear, actionable error messages +- **Help Integration**: Built-in help system with command documentation + +## πŸ”§ Technical Implementation + +### Core Classes +- `DatabaseCommand`: Main CLI command handling all database operations +- `DatabaseManager`: Core database functionality and connection management +- `ArgumentOption`: Command argument configuration and validation +- **Built-in `table()` method**: Uses WebFiori CLI's native table formatting for consistent display + +### Database Schema +```sql +-- Users table +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Posts table with foreign key +CREATE TABLE posts ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT, + title VARCHAR(200) NOT NULL, + content TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); +``` + +### Sample Data +- **Users**: John Doe, Jane Smith, Bob Johnson +- **Posts**: Multiple posts per user with realistic content +- **Relationships**: Posts linked to users via foreign keys + +## 🎯 Best Practices Demonstrated + +### 1. Database Security +- Prepared statements to prevent SQL injection +- Secure connection configuration +- Parameter validation and sanitization +- Error message sanitization + +### 2. Data Integrity +- Foreign key constraints for referential integrity +- Transaction support for complex operations +- Proper error handling and rollback +- Data validation before insertion + +### 3. Performance +- Efficient query execution with timing +- Proper indexing for performance +- Connection pooling and management +- Query optimization techniques + +### 4. User Experience +- Clear visual feedback for all operations +- Formatted table output for readability +- Comprehensive error messages +- Progress indicators for long operations + +### 5. Maintainability +- Modular command structure +- Centralized configuration management +- Comprehensive logging and debugging +- Clean separation of concerns + +## πŸ”— Related Examples + +- **[06-table-display](../06-table-display/)** - Advanced table formatting techniques +- **[07-progress-bars](../07-progress-bars/)** - Progress indicators for long operations +- **[08-file-processing](../08-file-processing/)** - File handling for backup operations +- **[10-multi-command-app](../10-multi-command-app/)** - Complete CLI application architecture + +## πŸ“š Further Reading + +- [WebFiori CLI Documentation](https://webfiori.com/docs/cli) +- [PHP PDO Documentation](https://www.php.net/manual/en/book.pdo.php) +- [MySQL Documentation](https://dev.mysql.com/doc/) +- [Database Design Best Practices](https://www.mysqltutorial.org/mysql-database-design/) +- [SQL Security Guidelines](https://owasp.org/www-project-cheat-sheets/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html) + +# Run specific migration +php main.php migrate --file=001_create_users_table.sql + +# Rollback last migration +php main.php migrate:rollback + +# Show migration status +php main.php migrate:status +``` + +### Data Seeding +```bash +# Seed all tables +php main.php seed + +# Seed specific table +php main.php seed --table=users + +# Seed with custom data +php main.php seed --file=custom_data.json +``` + +### Query Operations +```bash +# Execute SQL query +php main.php query --sql="SELECT * FROM users LIMIT 10" + +# Execute query from file +php main.php query --file=reports/monthly_stats.sql + +# Interactive query mode +php main.php query --interactive +``` + +### Schema Operations +```bash +# Show database schema +php main.php schema + +# Describe specific table +php main.php schema:table --name=users + +# Generate schema documentation +php main.php schema:docs --output=schema.md +``` + +### Backup & Restore +```bash +# Create database backup +php main.php backup --output=backup_2024-01-20.sql + +# Restore from backup +php main.php restore --file=backup_2024-01-20.sql + +# List available backups +php main.php backup:list +``` + +## πŸ“– Key Features + +### 1. Migration System +- **Version control**: Track database schema changes +- **Rollback support**: Undo migrations safely +- **Dependency management**: Handle migration dependencies +- **Batch operations**: Run multiple migrations +- **Status tracking**: Monitor migration state + +### 2. Data Management +- **Seeding**: Populate tables with test data +- **Fixtures**: Reusable data sets +- **Import/Export**: Data transfer utilities +- **Validation**: Data integrity checks +- **Relationships**: Handle foreign key constraints + +### 3. Query Interface +- **Interactive mode**: Real-time query execution +- **Result formatting**: Multiple output formats +- **Query history**: Track executed queries +- **Performance metrics**: Query execution stats +- **Syntax highlighting**: Enhanced readability + +### 4. Schema Management +- **Inspection**: Analyze database structure +- **Documentation**: Generate schema docs +- **Comparison**: Compare schema versions +- **Optimization**: Index and performance suggestions +- **Visualization**: Schema relationship diagrams + +## 🎨 Expected Output + +### Migration Status +``` +πŸ“Š Migration Status +================== + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Migration β”‚ Status β”‚ Executed At β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 001_create_users_table.sql β”‚ βœ… Done β”‚ 2024-01-15 10:30:00 β”‚ +β”‚ 002_create_posts_table.sql β”‚ βœ… Done β”‚ 2024-01-15 10:30:15 β”‚ +β”‚ 003_add_indexes.sql β”‚ ⏳ Pending β”‚ - β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +πŸ“ˆ Summary: 2 completed, 1 pending +``` + +### Query Results +``` +πŸ” Query Results +=============== + +Query: SELECT id, name, email, created_at FROM users LIMIT 5 +Execution time: 0.023s +Rows returned: 5 + +β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ ID β”‚ Name β”‚ Email β”‚ Created At β”‚ +β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 1 β”‚ John Doe β”‚ john@example.com β”‚ 2024-01-15 10:30:00 β”‚ +β”‚ 2 β”‚ Jane Smith β”‚ jane@example.com β”‚ 2024-01-15 11:15:30 β”‚ +β”‚ 3 β”‚ Bob Johnson β”‚ bob@example.com β”‚ 2024-01-15 12:45:15 β”‚ +β”‚ 4 β”‚ Alice Brown β”‚ alice@example.com β”‚ 2024-01-15 14:20:45 β”‚ +β”‚ 5 β”‚ Charlie Lee β”‚ charlie@example.com β”‚ 2024-01-15 15:10:20 β”‚ +β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +πŸ’‘ Query completed successfully +``` + +### Schema Information +``` +πŸ—„οΈ Database Schema: myapp +========================== + +πŸ“Š Tables Overview: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Table β”‚ Columns β”‚ Rows β”‚ Size β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ users β”‚ 8 β”‚ 1,234 β”‚ 2.3 MB β”‚ +β”‚ posts β”‚ 12 β”‚ 5,678 β”‚ 15.7 MB β”‚ +β”‚ comments β”‚ 6 β”‚ 12,345 β”‚ 8.9 MB β”‚ +β”‚ categories β”‚ 4 β”‚ 25 β”‚ 4.2 KB β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +πŸ”— Relationships: + β€’ users β†’ posts (1:many) + β€’ posts β†’ comments (1:many) + β€’ categories β†’ posts (1:many) + +πŸ“ˆ Total: 4 tables, 19,282 rows, 26.9 MB +``` + +### Backup Progress +``` +πŸ’Ύ Creating Database Backup +=========================== + +Analyzing database structure... +[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% + +Exporting table data: + β€’ users: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 1,234 rows + β€’ posts: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 5,678 rows + β€’ comments: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 12,345 rows + β€’ categories: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 25 rows + +βœ… Backup completed successfully! + +πŸ“‹ Backup Summary: + β€’ File: backup_2024-01-20_14-30-15.sql + β€’ Size: 45.2 MB + β€’ Tables: 4 + β€’ Total Rows: 19,282 + β€’ Duration: 00:02:15 + β€’ Compression: gzip (87% reduction) +``` + +## πŸ”— Next Steps + +After mastering this example, explore: +- **Real database integration**: Connect to MySQL, PostgreSQL, SQLite +- **ORM integration**: Use with Eloquent, Doctrine, etc. +- **Cloud database support**: AWS RDS, Google Cloud SQL +- **Advanced features**: Replication, clustering, performance tuning + +## πŸ’‘ Try This + +Extend the database CLI: + +1. **Add more database types**: Support MongoDB, Redis, etc. +2. **Implement connection pooling**: Manage multiple connections +3. **Add query optimization**: Analyze and suggest improvements +4. **Create data visualization**: Generate charts from query results +5. **Add replication support**: Master-slave configuration + +```php +// Example: Add query optimization +class QueryOptimizer { + public function analyze(string $query): array { + // Analyze query performance + return [ + 'execution_time' => 0.045, + 'rows_examined' => 1000, + 'suggestions' => ['Add index on user_id column'] + ]; + } +} +``` diff --git a/examples/09-database-ops/main.php b/examples/09-database-ops/main.php new file mode 100644 index 0000000..74aa496 --- /dev/null +++ b/examples/09-database-ops/main.php @@ -0,0 +1,320 @@ + [ + ArgumentOption::OPTIONAL => false, + ArgumentOption::DESCRIPTION => 'Database action to perform', + ArgumentOption::VALUES => ['connect', 'migrate', 'seed', 'query', 'backup', 'restore', 'status', 'cleanup'] + ], + '--sql' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'SQL query to execute (for query action)' + ], + '--file' => [ + ArgumentOption::OPTIONAL => true, + ArgumentOption::DESCRIPTION => 'File path for backup/restore operations' + ] + ], 'Database management operations'); + + $this->dbManager = new DatabaseManager(); + } + + public function exec(): int { + $action = $this->getArgValue('--action'); + + try { + switch ($action) { + case 'connect': + return $this->testConnection(); + case 'migrate': + return $this->runMigrations(); + case 'seed': + return $this->seedDatabase(); + case 'query': + return $this->executeQuery(); + case 'backup': + return $this->backupDatabase(); + case 'restore': + return $this->restoreDatabase(); + case 'status': + return $this->showStatus(); + case 'cleanup': + return $this->cleanupDatabase(); + default: + $this->println("Unknown action: $action"); + return 1; + } + } catch (Exception $e) { + $this->println("Error: " . $e->getMessage()); + return 1; + } + } + + private function testConnection(): int { + $this->println("πŸ”Œ Testing database connection..."); + + if ($this->dbManager->connect()) { + $this->println("βœ… Database connection successful!"); + $this->println("πŸ“Š Connection details:"); + $this->println(" β€’ Host: localhost:3306"); + $this->println(" β€’ Database: testing_db"); + $this->println(" β€’ Username: root"); + return 0; + } else { + $this->println("❌ Database connection failed!"); + return 1; + } + } + + private function runMigrations(): int { + $this->println("πŸš€ Running database migrations..."); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + // Create sample tables + $migrations = [ + "CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )", + "CREATE TABLE IF NOT EXISTS posts ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT, + title VARCHAR(200) NOT NULL, + content TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + )" + ]; + + foreach ($migrations as $index => $sql) { + $this->println(" β€’ Running migration " . ($index + 1) . "..."); + $this->dbManager->query($sql); + } + + $this->println("βœ… Migrations completed successfully!"); + return 0; + } + + private function seedDatabase(): int { + $this->println("🌱 Seeding database with sample data..."); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + // Insert sample users + $users = [ + ['John Doe', 'john@example.com'], + ['Jane Smith', 'jane@example.com'], + ['Bob Johnson', 'bob@example.com'] + ]; + + foreach ($users as $user) { + $this->dbManager->query( + "INSERT IGNORE INTO users (name, email) VALUES (?, ?)", + $user + ); + } + + // Insert sample posts + $posts = [ + [1, 'First Post', 'This is the content of the first post.'], + [1, 'Second Post', 'This is another post by John.'], + [2, 'Jane\'s Post', 'Hello from Jane!'], + [3, 'Bob\'s Thoughts', 'Some thoughts from Bob.'] + ]; + + foreach ($posts as $post) { + $this->dbManager->query( + "INSERT IGNORE INTO posts (user_id, title, content) VALUES (?, ?, ?)", + $post + ); + } + + $this->println("βœ… Database seeded successfully!"); + $this->println(" β€’ Added 3 users"); + $this->println(" β€’ Added 4 posts"); + return 0; + } + + private function executeQuery(): int { + $sql = $this->getArgValue('--sql'); + + if (!$sql) { + $this->println("❌ SQL query is required for query action"); + $this->println("Usage: php main.php db --action=query --sql=\"SELECT * FROM users\""); + return 1; + } + + $this->println("πŸ” Executing query..."); + $this->println("SQL: $sql"); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + $result = $this->dbManager->query($sql); + + if ($result['success']) { + $data = $result['data']; + if (!empty($data)) { + $this->println("πŸ“Š Query results:"); + $this->table($data); + $this->println("⏱️ Execution time: " . number_format($result['execution_time'] * 1000, 2) . "ms"); + } else { + $this->println("πŸ“Š Query executed successfully (no results)"); + } + } else { + $this->println("❌ Query failed: " . $result['error']); + return 1; + } + + return 0; + } + + private function backupDatabase(): int { + $file = $this->getArgValue('--file') ?? 'backup_' . date('Y-m-d_H-i-s') . '.sql'; + + $this->println("πŸ’Ύ Creating database backup..."); + $this->println("File: $file"); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + $result = $this->dbManager->createBackup($file); + + if ($result['success']) { + $this->println("βœ… Backup created successfully!"); + $this->println(" β€’ File: " . $result['file']); + $this->println(" β€’ Size: " . number_format($result['size']) . " bytes"); + $this->println(" β€’ Tables: " . $result['tables']); + } else { + $this->println("❌ Backup failed: " . $result['error']); + return 1; + } + + return 0; + } + + private function restoreDatabase(): int { + $file = $this->getArgValue('--file'); + + if (!$file || !file_exists($file)) { + $this->println("❌ Backup file is required and must exist"); + return 1; + } + + $this->println("πŸ”„ Restoring database from backup..."); + $this->println("File: $file"); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + $result = $this->dbManager->restoreFromFile($file); + + if ($result['success']) { + $this->println("βœ… Database restored successfully!"); + $this->println(" β€’ Statements executed: " . $result['statements']); + } else { + $this->println("❌ Restore failed: " . $result['error']); + return 1; + } + + return 0; + } + + private function showStatus(): int { + $this->println("πŸ“Š Database Status"); + $this->println("=================="); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + // Show tables + $tablesResult = $this->dbManager->query("SHOW TABLES"); + if (!$tablesResult['success']) { + $this->println("❌ Failed to get table list"); + return 1; + } + + $tables = $tablesResult['data']; + $this->println("πŸ“‹ Tables: " . count($tables)); + + foreach ($tables as $table) { + $tableName = array_values($table)[0]; + $countResult = $this->dbManager->query("SELECT COUNT(*) as count FROM `$tableName`"); + if ($countResult['success'] && !empty($countResult['data'])) { + $count = $countResult['data'][0]['count'] ?? 0; + $this->println(" β€’ $tableName: $count records"); + } + } + + return 0; + } + + private function cleanupDatabase(): int { + $this->println("🧹 Cleaning up database..."); + + if (!$this->dbManager->connect()) { + $this->println("❌ Cannot connect to database"); + return 1; + } + + // Drop tables in correct order (foreign key constraints) + $tables = ['posts', 'users']; + + foreach ($tables as $table) { + $this->println(" β€’ Dropping table: $table"); + $this->dbManager->query("DROP TABLE IF EXISTS `$table`"); + } + + $this->println("βœ… Database cleanup completed!"); + return 0; + } +} + +// Create and configure the CLI runner +$runner = new Runner(); +$runner->register(new DatabaseCommand()); +$runner->setDefaultCommand('help'); + +// Start the application +exit($runner->start()); diff --git a/examples/09-database-ops/migrations/001_create_users_table.sql b/examples/09-database-ops/migrations/001_create_users_table.sql new file mode 100644 index 0000000..7628d54 --- /dev/null +++ b/examples/09-database-ops/migrations/001_create_users_table.sql @@ -0,0 +1,14 @@ +-- Create users table +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + email VARCHAR(255) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + status ENUM('active', 'inactive') DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + INDEX idx_email (email), + INDEX idx_status (status), + INDEX idx_created_at (created_at) +); diff --git a/examples/09-database-ops/seeds/users.json b/examples/09-database-ops/seeds/users.json new file mode 100644 index 0000000..f76be0e --- /dev/null +++ b/examples/09-database-ops/seeds/users.json @@ -0,0 +1,32 @@ +[ + { + "name": "John Doe", + "email": "john.doe@example.com", + "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", + "status": "active" + }, + { + "name": "Jane Smith", + "email": "jane.smith@example.com", + "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", + "status": "active" + }, + { + "name": "Bob Johnson", + "email": "bob.johnson@example.com", + "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", + "status": "inactive" + }, + { + "name": "Alice Brown", + "email": "alice.brown@example.com", + "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", + "status": "active" + }, + { + "name": "Charlie Wilson", + "email": "charlie.wilson@example.com", + "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", + "status": "active" + } +] From 6b3aad9f2dd0f5f6797e2bcaa46d516110b10964 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:31:38 +0300 Subject: [PATCH 10/12] docs: Updated Example 10 --- examples/10-multi-command-app/README.md | 458 ++++++++++++++++-- .../commands/UserCommand.php | 51 +- examples/10-multi-command-app/data/users.json | 2 +- examples/10-multi-command-app/main.php | 3 - 4 files changed, 433 insertions(+), 81 deletions(-) diff --git a/examples/10-multi-command-app/README.md b/examples/10-multi-command-app/README.md index 9c099b7..7b1facd 100644 --- a/examples/10-multi-command-app/README.md +++ b/examples/10-multi-command-app/README.md @@ -1,53 +1,455 @@ # Multi-Command Application Example -This example demonstrates building a complete, production-ready CLI application with multiple commands, configuration management, and advanced features. +This example demonstrates building a complete, production-ready CLI application with comprehensive user management, data persistence, export functionality, and advanced CLI features using WebFiori CLI. ## 🎯 What You'll Learn -- Structuring large CLI applications -- Command organization and discovery +- Building complex multi-command CLI applications +- User management system with CRUD operations +- Data persistence with JSON file storage +- Export functionality (JSON, CSV formats) +- Interactive user input and validation +- Search and filtering capabilities +- Batch operations and file processing +- Error handling and logging systems - Configuration management -- Data persistence and storage -- Error handling and logging -- Testing CLI applications -- Documentation and help systems +- Interactive mode for continuous operations ## πŸ“ Project Structure ``` 10-multi-command-app/ β”œβ”€β”€ commands/ # Command classes -β”‚ β”œβ”€β”€ UserCommand.php -β”‚ β”œβ”€β”€ ConfigCommand.php -β”‚ β”œβ”€β”€ DataCommand.php -β”‚ └── SystemCommand.php +β”‚ └── UserCommand.php # Complete user management system β”œβ”€β”€ config/ # Configuration files -β”‚ β”œβ”€β”€ app.json -β”‚ └── database.json -β”œβ”€β”€ data/ # Data storage -β”‚ β”œβ”€β”€ users.json -β”‚ └── logs/ -β”œβ”€β”€ tests/ # Unit tests -β”œβ”€β”€ AppManager.php # Application manager -β”œβ”€β”€ main.php # Entry point -└── README.md # This file +β”‚ └── app.json # Application configuration +β”œβ”€β”€ data/ # Data storage and logs +β”‚ β”œβ”€β”€ users.json # User data persistence +β”‚ └── logs/ # Application logs +β”‚ └── app.log # Main application log +β”œβ”€β”€ AppManager.php # Core application manager +β”œβ”€β”€ main.php # Application entry point +└── README.md # This documentation ``` ## πŸš€ Running the Application -### Basic Commands +### Basic Usage ```bash # Show all available commands php main.php help -# User management -php main.php user:list -php main.php user:create --name="John Doe" --email="john@example.com" -php main.php user:update --id=1 --name="Jane Doe" -php main.php user:delete --id=1 +# Show specific command help +php main.php help --command=user -# Configuration management -php main.php config:show +# Start interactive mode +php main.php -i +``` + +### User Management Operations +```bash +# List all users +php main.php user --action=list + +# Create new user +php main.php user --action=create --name="John Doe" --email="john@example.com" --status=active + +# Update existing user +php main.php user --action=update --id=1 --name="Jane Doe" --status=inactive + +# Delete user (with confirmation) +php main.php user --action=delete --id=1 + +# Search users +php main.php user --action=search --search="john" + +# Export users +php main.php user --action=export --format=json --file=users.json +php main.php user --action=export --format=csv --file=users.csv +``` + +## πŸ“‹ Available Commands + +### User Command (`user`) +Complete user management system with the following actions: + +#### Actions (`--action`) +- `list` - Display all users in formatted table +- `create` - Create new user with validation +- `update` - Update existing user by ID +- `delete` - Delete user with confirmation prompt +- `search` - Search users by name or email +- `export` - Export users to file (JSON/CSV) + +#### Parameters +- `--action` - Action to perform (**Required**) +- `--id` - User ID for update/delete operations +- `--name` - User full name +- `--email` - User email address (validated) +- `--status` - User status (active/inactive) +- `--format` - Output format (table/json/csv) - Default: table +- `--search` - Search term for filtering +- `--limit` - Maximum number of results - Default: 50 +- `--batch` - Enable batch mode for bulk operations +- `--file` - File path for batch operations or export + +#### Validation Rules +- Email must be valid email format +- Status must be 'active' or 'inactive' +- ID must exist for update/delete operations +- Name and email required for create operations + +## 🎨 Example Output + +### User List (Table Format) +```bash +php main.php user --action=list +``` +``` +Info: πŸ‘₯ User Management - List Users + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Id β”‚ Name β”‚ Email β”‚ Status β”‚ Created At β”‚ Updated At β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 1 β”‚ John Doe β”‚ john.doe@example.com β”‚ active β”‚ 2024-01-15 10:30:00 β”‚ 2024-01-15 10:30:00 β”‚ +β”‚ 2 β”‚ Jane Smith β”‚ jane.smith@example.com β”‚ active β”‚ 2024-01-16 14:20:00 β”‚ 2024-01-16 14:20:00 β”‚ +β”‚ 3 β”‚ Bob Johnson β”‚ bob.johnson@example.com β”‚ inactive β”‚ 2024-01-17 09:15:00 β”‚ 2024-01-17 09:15:00 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Info: πŸ“Š Total: 3 users | Active: 2 | Inactive: 1 +``` + +### User Creation +```bash +php main.php user --action=create --name="Alice Brown" --email="alice@example.com" --status=active +``` +``` +Success: βœ… User created successfully! + +Info: πŸ‘€ User Information: + β€’ ID: 4 + β€’ Name: Alice Brown + β€’ Email: alice@example.com + β€’ Status: Active + β€’ Created: 2025-09-27 19:19:41 + β€’ Updated: 2025-09-27 19:19:41 +``` + +### User Update +```bash +php main.php user --action=update --id=4 --name="Alice Cooper" --status=inactive +``` +``` +Info: Updating user: Alice Brown (alice@example.com) +Success: βœ… User updated successfully! + +Info: πŸ‘€ User Information: + β€’ ID: 4 + β€’ Name: Alice Cooper + β€’ Email: alice@example.com + β€’ Status: Inactive + β€’ Created: 2025-09-27 19:19:41 + β€’ Updated: 2025-09-27 19:19:51 +``` + +### User Search +```bash +php main.php user --action=search --search="john" +``` +``` +Info: πŸ” Search Results for: 'john' + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Id β”‚ Name β”‚ Email β”‚ Status β”‚ Created At β”‚ Updated At β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 1 β”‚ John Doe β”‚ john.doe@example.com β”‚ active β”‚ 2024-01-15 10:30:00 β”‚ 2024-01-15 10:30:00 β”‚ +β”‚ 3 β”‚ Bob Johnson β”‚ bob.johnson@example.com β”‚ inactive β”‚ 2024-01-17 09:15:00 β”‚ 2024-01-17 09:15:00 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +Info: Found 2 user(s) matching 'john' +``` + +### User Export (JSON) +```bash +php main.php user --action=export --format=json --file=users_export.json +``` +``` +Info: πŸ“€ Exporting 4 users to users_export.json +Success: βœ… Export completed successfully! +Info: πŸ“‹ Export Summary: + β€’ Format: JSON + β€’ Records: 4 + β€’ File Size: 881.0 B + β€’ Location: users_export.json +``` + +### User Export (CSV) +```bash +php main.php user --action=export --format=csv --file=users_export.csv +``` +``` +Info: πŸ“€ Exporting 4 users to users_export.csv +Success: βœ… Export completed successfully! +Info: πŸ“‹ Export Summary: + β€’ Format: CSV + β€’ Records: 4 + β€’ File Size: 422.0 B + β€’ Location: users_export.csv +``` + +### User Deletion (with Confirmation) +```bash +php main.php user --action=delete --id=4 +``` +``` +Warning: ⚠️ You are about to delete user: Alice Cooper (alice@example.com) +Are you sure you want to delete this user?(y/N) +Success: βœ… User deleted successfully! +``` + +### JSON Output Format +```bash +php main.php user --action=list --format=json +``` +``` +Info: πŸ‘₯ User Management - List Users + +[ + { + "id": 1, + "name": "John Doe", + "email": "john.doe@example.com", + "status": "active", + "created_at": "2024-01-15 10:30:00", + "updated_at": "2024-01-15 10:30:00" + }, + { + "id": 2, + "name": "Jane Smith", + "email": "jane.smith@example.com", + "status": "active", + "created_at": "2024-01-16 14:20:00", + "updated_at": "2024-01-16 14:20:00" + } +] + +Info: πŸ“Š Total: 2 users | Active: 2 | Inactive: 0 +``` + +### Interactive Mode +```bash +php main.php -i +``` +``` +>> Running in interactive mode. +>> Type command name or 'exit' to close. +>> user --action=list +Info: πŸ‘₯ User Management - List Users +[Table output...] +>> exit +``` + +### Error Handling Examples + +#### Missing Required Action +```bash +php main.php user +``` +``` +Error: The following required argument(s) are missing: '--action' +``` + +#### Invalid Action +```bash +php main.php user --action=invalid +``` +``` +Error: The following argument(s) have invalid values: '--action' +Info: Allowed values for the argument '--action': +list +create +update +delete +search +export +``` + +#### User Not Found +```bash +php main.php user --action=update --id=999 --name="Test" +``` +``` +Error: User with ID 999 not found. +``` + +#### Validation Error +```bash +php main.php user --action=create --name="Test User" +``` +``` +Enter user email: +Error: Validation failed: + β€’ Field email must be a valid email address +``` + +## πŸ§ͺ Test Scenarios + +### 1. Complete User Lifecycle +```bash +# Create, update, search, and delete user +php main.php user --action=create --name="Test User" --email="test@example.com" --status=active +php main.php user --action=update --id=4 --name="Updated User" --status=inactive +php main.php user --action=search --search="updated" +php main.php user --action=delete --id=4 +``` + +### 2. Export and Format Testing +```bash +# Test different export formats +php main.php user --action=export --format=json --file=test.json +php main.php user --action=export --format=csv --file=test.csv +php main.php user --action=list --format=json +php main.php user --action=list --format=table +``` + +### 3. Search and Filter Testing +```bash +# Test search functionality +php main.php user --action=search --search="john" +php main.php user --action=search --search="@example.com" +php main.php user --action=search --search="active" +``` + +### 4. Interactive Mode Testing +```bash +# Test interactive mode +echo -e "user --action=list\nuser --action=create --name='Interactive User' --email='interactive@example.com'\nexit" | php main.php -i +``` + +### 5. Error Handling Testing +```bash +# Test various error conditions +php main.php user --action=update --id=999 +php main.php user --action=create --name="Test" +php main.php user --action=delete --id=999 +php main.php user --action=invalid +``` + +### 6. Batch Operations Testing +```bash +# Test batch file processing +echo '[{"name":"Batch User 1","email":"batch1@example.com","status":"active"}]' > batch.json +php main.php user --action=create --batch --file=batch.json +``` + +## πŸ’‘ Key Features Demonstrated + +### 1. Application Architecture +- **Multi-Command Structure**: Organized command classes with clear separation +- **Configuration Management**: Centralized app configuration and settings +- **Data Persistence**: JSON-based data storage with automatic backup +- **Logging System**: Comprehensive application logging with timestamps + +### 2. User Management System +- **CRUD Operations**: Complete Create, Read, Update, Delete functionality +- **Data Validation**: Email validation, status validation, required field checks +- **Search Functionality**: Search by name, email, or status +- **Confirmation Prompts**: Safety confirmations for destructive operations + +### 3. Export and Import +- **Multiple Formats**: JSON and CSV export capabilities +- **File Management**: Automatic file naming and size reporting +- **Batch Operations**: Bulk user creation from JSON files +- **Data Integrity**: Validation during import/export operations + +### 4. User Experience +- **Formatted Output**: Uses WebFiori CLI's built-in `table()` method for consistent, professional table formatting +- **Interactive Input**: Prompts for missing required information +- **Progress Feedback**: Clear success/error messages with emojis +- **Help System**: Comprehensive help documentation for all commands + +### 5. Advanced CLI Features +- **Interactive Mode**: Continuous command execution without restart +- **Format Options**: Multiple output formats (table, JSON, CSV) +- **Search and Filter**: Advanced filtering capabilities +- **Logging**: Application activity logging for debugging and monitoring + +## πŸ”§ Technical Implementation + +### Core Classes +- `UserCommand`: Complete user management command with all CRUD operations +- `AppManager`: Application lifecycle management, logging, and configuration +- `Runner`: WebFiori CLI runner with command registration and execution +- **Built-in `table()` method**: Uses WebFiori CLI's native table formatting for consistent, professional display + +### Data Storage +- **JSON Files**: User data stored in `data/users.json` +- **Automatic Backup**: Data persistence with atomic writes +- **Schema Validation**: Consistent data structure enforcement +- **Migration Support**: Data format versioning and upgrades + +### User Data Structure +```json +{ + "id": 1, + "name": "John Doe", + "email": "john.doe@example.com", + "status": "active", + "created_at": "2024-01-15 10:30:00", + "updated_at": "2024-01-15 10:30:00" +} +``` + +### Export Formats +- **JSON**: Structured data with full field information +- **CSV**: Comma-separated values with headers +- **Table**: Formatted console output with borders and alignment + +## 🎯 Best Practices Demonstrated + +### 1. Command Organization +- Single responsibility principle for commands +- Clear command naming and structure +- Comprehensive argument validation +- Consistent error handling patterns + +### 2. Data Management +- Atomic file operations for data integrity +- Backup and recovery mechanisms +- Data validation and sanitization +- Consistent data format and structure + +### 3. User Experience +- Clear and informative output messages +- Confirmation prompts for destructive actions +- Multiple output format options +- Comprehensive help and documentation + +### 4. Error Handling +- Graceful error recovery +- Informative error messages +- Input validation and sanitization +- Logging for debugging and monitoring + +### 5. Code Quality +- Modular and maintainable code structure +- Comprehensive documentation +- Consistent coding standards +- Testable command implementations + +## πŸ”— Related Examples + +- **[01-basic-command](../01-basic-command/)** - Simple command creation +- **[02-command-with-args](../02-command-with-args/)** - Argument handling +- **[06-table-display](../06-table-display/)** - Advanced table formatting +- **[08-file-processing](../08-file-processing/)** - File operations and processing + +## πŸ“š Further Reading + +- [WebFiori CLI Documentation](https://webfiori.com/docs/cli) +- [Command Design Patterns](https://refactoring.guru/design-patterns/command) +- [CLI Application Best Practices](https://clig.dev/) +- [JSON Data Management](https://www.json.org/json-en.html) +- [CSV File Format Specification](https://tools.ietf.org/html/rfc4180) php main.php config:set --key="app.debug" --value="true" php main.php config:get --key="app.name" diff --git a/examples/10-multi-command-app/commands/UserCommand.php b/examples/10-multi-command-app/commands/UserCommand.php index 2f40074..754ab10 100644 --- a/examples/10-multi-command-app/commands/UserCommand.php +++ b/examples/10-multi-command-app/commands/UserCommand.php @@ -330,53 +330,6 @@ private function displayUserInfo(array $user): void { $this->println(" β€’ Updated: {$user['updated_at']}"); } - /** - * Display users in table format. - */ - private function displayUsersTable(array $users): void { - // Table header - $this->prints('β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”', ['color' => 'blue']); - $this->println(); - - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' ID ', ['bold' => true]); - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' Name ', ['bold' => true]); - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' Email ', ['bold' => true]); - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' Status ', ['bold' => true]); - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' Created ', ['bold' => true]); - $this->prints('β”‚', ['color' => 'blue']); - $this->println(); - - $this->prints('β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€', ['color' => 'blue']); - $this->println(); - - // Table rows - foreach ($users as $user) { - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' '.str_pad($user['id'], 2).' '); - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' '.str_pad(substr($user['name'], 0, 19), 19).' '); - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' '.str_pad(substr($user['email'], 0, 23), 23).' '); - $this->prints('β”‚', ['color' => 'blue']); - - $statusColor = $user['status'] === 'active' ? 'green' : 'red'; - $this->prints(' '.str_pad(ucfirst($user['status']), 11).' ', ['color' => $statusColor]); - - $this->prints('β”‚', ['color' => 'blue']); - $this->prints(' '.str_pad(substr($user['created_at'], 0, 10), 11).' '); - $this->prints('β”‚', ['color' => 'blue']); - $this->println(); - } - - $this->prints('β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜', ['color' => 'blue']); - $this->println(); - } - /** * Export users to file. */ @@ -486,7 +439,7 @@ private function listUsers(): int { $this->println(); if ($format === 'table') { - $this->displayUsersTable($users); + $this->table($users); } else { $output = $this->app->formatData($users, $format); $this->println($output); @@ -525,7 +478,7 @@ private function searchUsers(): int { } if ($format === 'table') { - $this->displayUsersTable($filteredUsers); + $this->table($filteredUsers); } else { $output = $this->app->formatData(array_values($filteredUsers), $format); $this->println($output); diff --git a/examples/10-multi-command-app/data/users.json b/examples/10-multi-command-app/data/users.json index 6ae1383..1cbfe00 100644 --- a/examples/10-multi-command-app/data/users.json +++ b/examples/10-multi-command-app/data/users.json @@ -23,4 +23,4 @@ "created_at": "2024-01-17 09:15:00", "updated_at": "2024-01-17 09:15:00" } -] +] \ No newline at end of file diff --git a/examples/10-multi-command-app/main.php b/examples/10-multi-command-app/main.php index 7967477..5568db9 100644 --- a/examples/10-multi-command-app/main.php +++ b/examples/10-multi-command-app/main.php @@ -13,7 +13,6 @@ * - Comprehensive error handling and logging */ -use WebFiori\Cli\Commands\HelpCommand; use WebFiori\Cli\Runner; // Load dependencies @@ -25,13 +24,11 @@ $runner = new Runner(); // Register core commands -$runner->register(new HelpCommand()); // Register application commands $runner->register(new UserCommand()); // Set default command -$runner->setDefaultCommand('help'); // Initialize application $app = new AppManager(); From dd61a0453e3fbf07f444686a24ee8de659bc2708 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 19:34:36 +0300 Subject: [PATCH 11/12] docs: Removed Examples --- WebFiori/Cli/Command.php | 15 +- examples/13-database-cli/DatabaseManager.php | 578 ------------------ examples/13-database-cli/README.md | 258 -------- examples/13-database-cli/main.php | 36 -- .../migrations/001_create_users_table.sql | 14 - examples/13-database-cli/seeds/users.json | 32 - examples/15-table-display/README.md | 248 -------- .../15-table-display/TableDemoCommand.php | 459 -------------- examples/15-table-display/main.php | 17 - examples/15-table-display/simple-example.php | 59 -- examples/16-table-usage/BasicTableCommand.php | 133 ---- examples/16-table-usage/README.md | 293 --------- examples/16-table-usage/TableUsageCommand.php | 259 -------- examples/16-table-usage/main.php | 22 - 14 files changed, 13 insertions(+), 2410 deletions(-) delete mode 100644 examples/13-database-cli/DatabaseManager.php delete mode 100644 examples/13-database-cli/README.md delete mode 100644 examples/13-database-cli/main.php delete mode 100644 examples/13-database-cli/migrations/001_create_users_table.sql delete mode 100644 examples/13-database-cli/seeds/users.json delete mode 100644 examples/15-table-display/README.md delete mode 100644 examples/15-table-display/TableDemoCommand.php delete mode 100644 examples/15-table-display/main.php delete mode 100644 examples/15-table-display/simple-example.php delete mode 100644 examples/16-table-usage/BasicTableCommand.php delete mode 100644 examples/16-table-usage/README.md delete mode 100644 examples/16-table-usage/TableUsageCommand.php delete mode 100644 examples/16-table-usage/main.php diff --git a/WebFiori/Cli/Command.php b/WebFiori/Cli/Command.php index 64377e7..1ff5939 100644 --- a/WebFiori/Cli/Command.php +++ b/WebFiori/Cli/Command.php @@ -1035,12 +1035,18 @@ public function removeArgument(string $name) : bool { * @param int $defaultIndex The index of the default value in case no value * is selected and the user hit enter. * + * * @param int $maxTrials The maximum number of trials the user can do to select + * a value. If -1 is passed, the user can select a value forever. + * * @return string|null The method will return the value which is selected by - * the user. If choices array is empty, null is returned. + * the user. If choices array is empty, null is returned. Also, null is returned + * if max trials is reached and it is not -1. + * * */ - public function select(string $prompt, array $choices, int $defaultIndex = -1): ?string { + public function select(string $prompt, array $choices, int $defaultIndex = -1, int $maxTrials = -1): ?string { if (count($choices) != 0) { + $currentTry = 0; do { $this->println($prompt, [ 'color' => 'gray', @@ -1055,6 +1061,11 @@ public function select(string $prompt, array $choices, int $defaultIndex = -1): if ($check !== null) { return $check; } + $currentTry++; + + if ($currentTry == $maxTrials && $maxTrials > 0) { + return null; + } } while (true); } diff --git a/examples/13-database-cli/DatabaseManager.php b/examples/13-database-cli/DatabaseManager.php deleted file mode 100644 index 4c91537..0000000 --- a/examples/13-database-cli/DatabaseManager.php +++ /dev/null @@ -1,578 +0,0 @@ -migrationsPath = $basePath.'/migrations'; - $this->seedsPath = $basePath.'/seeds'; - $this->loadConfig(); - } - - /** - * Connect to database. - */ - public function connect(array $config = null): bool { - if ($config) { - $this->config = array_merge($this->config, $config); - } - - try { - $dsn = $this->buildDsn(); - $this->connection = new PDO( - $dsn, - $this->config['username'] ?? '', - $this->config['password'] ?? '', - [ - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); - - return true; - } catch (PDOException $e) { - throw new Exception("Database connection failed: ".$e->getMessage()); - } - } - - /** - * Create database backup. - */ - public function createBackup(string $outputPath = null): array { - $this->ensureConnected(); - - if (!$outputPath) { - $timestamp = date('Y-m-d_H-i-s'); - $outputPath = "backup_{$timestamp}.sql"; - } - - $tables = $this->getTables(); - $backup = []; - - // Add header - $backup[] = "-- Database Backup"; - $backup[] = "-- Generated: ".date('Y-m-d H:i:s'); - $backup[] = "-- Database: ".($this->config['database'] ?? 'unknown'); - $backup[] = ""; - - foreach ($tables as $table) { - $tableName = $table['name']; - - // Skip migrations table - if ($tableName === 'migrations') { - continue; - } - - $backup[] = "-- Table: $tableName"; - $backup[] = "DROP TABLE IF EXISTS `$tableName`;"; - - // Get CREATE TABLE statement - $createResult = $this->query("SHOW CREATE TABLE `$tableName`"); - - if ($createResult['success'] && !empty($createResult['data'])) { - $createStatement = $createResult['data'][0]['Create Table'] ?? ''; - $backup[] = $createStatement.";"; - } - - // Get table data - $dataResult = $this->query("SELECT * FROM `$tableName`"); - - if ($dataResult['success'] && !empty($dataResult['data'])) { - $backup[] = ""; - - foreach ($dataResult['data'] as $row) { - $values = array_map(function ($value) { - return $value === null ? 'NULL' : "'".addslashes($value)."'"; - }, array_values($row)); - - $columns = '`'.implode('`, `', array_keys($row)).'`'; - $backup[] = "INSERT INTO `$tableName` ($columns) VALUES (".implode(', ', $values).");"; - } - } - - $backup[] = ""; - } - - $backupContent = implode("\n", $backup); - - if (file_put_contents($outputPath, $backupContent) !== false) { - return [ - 'success' => true, - 'file' => $outputPath, - 'size' => strlen($backupContent), - 'tables' => count($tables) - ]; - } else { - return [ - 'success' => false, - 'error' => "Failed to write backup file: $outputPath" - ]; - } - } - - /** - * Get list of available migrations. - */ - public function getAvailableMigrations(): array { - if (!is_dir($this->migrationsPath)) { - return []; - } - - $files = glob($this->migrationsPath.'/*.sql'); - $migrations = []; - - foreach ($files as $file) { - $filename = basename($file); - $migrations[] = [ - 'filename' => $filename, - 'path' => $file, - 'name' => pathinfo($filename, PATHINFO_FILENAME), - 'size' => filesize($file), - 'modified' => filemtime($file) - ]; - } - - // Sort by filename (which should include version numbers) - usort($migrations, fn($a, $b) => strcmp($a['filename'], $b['filename'])); - - return $migrations; - } - - /** - * Get connection status information. - */ - public function getConnectionStatus(): array { - if (!$this->isConnected()) { - return [ - 'connected' => false, - 'error' => 'Not connected to database' - ]; - } - - try { - $stmt = $this->connection->query('SELECT VERSION() as version'); - $result = $stmt->fetch(); - - return [ - 'connected' => true, - 'host' => $this->config['host'] ?? 'unknown', - 'database' => $this->config['database'] ?? 'unknown', - 'version' => $result['version'] ?? 'unknown', - 'driver' => $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME) - ]; - } catch (PDOException $e) { - return [ - 'connected' => false, - 'error' => $e->getMessage() - ]; - } - } - - /** - * Get executed migrations. - */ - public function getExecutedMigrations(): array { - $this->ensureConnected(); - $this->ensureMigrationsTable(); - - $result = $this->query('SELECT * FROM migrations ORDER BY executed_at ASC'); - - return $result['success'] ? $result['data'] : []; - } - - /** - * Get database schema information. - */ - public function getSchema(): array { - $this->ensureConnected(); - - $tables = $this->getTables(); - $schema = [ - 'database' => $this->config['database'] ?? 'unknown', - 'tables' => [], - 'total_tables' => count($tables), - 'total_size' => 0 - ]; - - foreach ($tables as $table) { - $tableInfo = $this->getTableInfo($table['name']); - $schema['tables'][] = $tableInfo; - $schema['total_size'] += $tableInfo['size_bytes'] ?? 0; - } - - return $schema; - } - - /** - * Get table columns. - */ - public function getTableColumns(string $tableName): array { - $this->ensureConnected(); - - $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); - - switch ($driver) { - case 'mysql': - $sql = "DESCRIBE `$tableName`"; - break; - case 'pgsql': - $sql = "SELECT column_name, data_type, is_nullable - FROM information_schema.columns - WHERE table_name = '$tableName'"; - break; - case 'sqlite': - $sql = "PRAGMA table_info($tableName)"; - break; - default: - return []; - } - - $result = $this->query($sql); - - return $result['success'] ? $result['data'] : []; - } - - /** - * Get detailed table information. - */ - public function getTableInfo(string $tableName): array { - $this->ensureConnected(); - - $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); - - // Get column information - $columns = $this->getTableColumns($tableName); - - // Get row count - $countResult = $this->query("SELECT COUNT(*) as count FROM `$tableName`"); - $rowCount = $countResult['success'] ? $countResult['data'][0]['count'] : 0; - - // Get table size (MySQL specific) - $sizeBytes = 0; - - if ($driver === 'mysql') { - $sizeResult = $this->query( - "SELECT (data_length + index_length) as size_bytes - FROM information_schema.tables - WHERE table_schema = ? AND table_name = ?", - [$this->config['database'], $tableName] - ); - - if ($sizeResult['success'] && !empty($sizeResult['data'])) { - $sizeBytes = $sizeResult['data'][0]['size_bytes'] ?? 0; - } - } - - return [ - 'name' => $tableName, - 'columns' => $columns, - 'column_count' => count($columns), - 'row_count' => $rowCount, - 'size_bytes' => $sizeBytes, - 'size_human' => $this->formatBytes($sizeBytes) - ]; - } - - /** - * Get list of tables. - */ - public function getTables(): array { - $this->ensureConnected(); - - $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); - - switch ($driver) { - case 'mysql': - $sql = 'SHOW TABLES'; - break; - case 'pgsql': - $sql = "SELECT tablename as table_name FROM pg_tables WHERE schemaname = 'public'"; - break; - case 'sqlite': - $sql = "SELECT name as table_name FROM sqlite_master WHERE type='table'"; - break; - default: - throw new Exception("Unsupported database driver: $driver"); - } - - $result = $this->query($sql); - - if (!$result['success']) { - return []; - } - - $tables = []; - - foreach ($result['data'] as $row) { - $tableName = array_values($row)[0]; // Get first column value - $tables[] = ['name' => $tableName]; - } - - return $tables; - } - - /** - * Check if connected to database. - */ - public function isConnected(): bool { - return $this->connection !== null; - } - - /** - * Execute SQL query. - */ - public function query(string $sql, array $params = []): array { - $this->ensureConnected(); - - $startTime = microtime(true); - - try { - if (empty($params)) { - $stmt = $this->connection->query($sql); - } else { - $stmt = $this->connection->prepare($sql); - $stmt->execute($params); - } - - $executionTime = microtime(true) - $startTime; - - // Record query for history - $this->executedQueries[] = [ - 'sql' => $sql, - 'params' => $params, - 'execution_time' => $executionTime, - 'timestamp' => date('Y-m-d H:i:s') - ]; - - $results = $stmt->fetchAll(); - - return [ - 'success' => true, - 'data' => $results, - 'row_count' => $stmt->rowCount(), - 'execution_time' => $executionTime, - 'affected_rows' => $stmt->rowCount() - ]; - } catch (PDOException $e) { - return [ - 'success' => false, - 'error' => $e->getMessage(), - 'sql' => $sql, - 'execution_time' => microtime(true) - $startTime - ]; - } - } - - /** - * Run migration. - */ - public function runMigration(string $filename): array { - $this->ensureConnected(); - $this->ensureMigrationsTable(); - - $migrationPath = $this->migrationsPath.'/'.$filename; - - if (!file_exists($migrationPath)) { - return [ - 'success' => false, - 'error' => "Migration file not found: $filename" - ]; - } - - // Check if already executed - $result = $this->query('SELECT COUNT(*) as count FROM migrations WHERE filename = ?', [$filename]); - - if ($result['success'] && $result['data'][0]['count'] > 0) { - return [ - 'success' => false, - 'error' => "Migration already executed: $filename" - ]; - } - - // Read and execute migration - $sql = file_get_contents($migrationPath); - $statements = $this->splitSqlStatements($sql); - - $this->connection->beginTransaction(); - - try { - foreach ($statements as $statement) { - if (trim($statement)) { - $this->connection->exec($statement); - } - } - - // Record migration - $this->query( - 'INSERT INTO migrations (filename, executed_at) VALUES (?, ?)', - [$filename, date('Y-m-d H:i:s')] - ); - - $this->connection->commit(); - - return [ - 'success' => true, - 'message' => "Migration executed successfully: $filename" - ]; - } catch (PDOException $e) { - $this->connection->rollBack(); - - return [ - 'success' => false, - 'error' => "Migration failed: ".$e->getMessage() - ]; - } - } - - /** - * Seed database with test data. - */ - public function seedTable(string $tableName, string $seedFile = null): array { - $this->ensureConnected(); - - if (!$seedFile) { - $seedFile = $this->seedsPath."/{$tableName}.json"; - } - - if (!file_exists($seedFile)) { - return [ - 'success' => false, - 'error' => "Seed file not found: $seedFile" - ]; - } - - $seedData = json_decode(file_get_contents($seedFile), true); - - if (json_last_error() !== JSON_ERROR_NONE) { - return [ - 'success' => false, - 'error' => "Invalid JSON in seed file: ".json_last_error_msg() - ]; - } - - if (empty($seedData)) { - return [ - 'success' => false, - 'error' => "No data found in seed file" - ]; - } - - $inserted = 0; - $errors = []; - - foreach ($seedData as $record) { - $columns = array_keys($record); - $placeholders = array_fill(0, count($columns), '?'); - - $sql = "INSERT INTO `$tableName` (`".implode('`, `', $columns)."`) VALUES (".implode(', ', $placeholders).")"; - - $result = $this->query($sql, array_values($record)); - - if ($result['success']) { - $inserted++; - } else { - $errors[] = $result['error']; - } - } - - return [ - 'success' => empty($errors), - 'inserted' => $inserted, - 'total' => count($seedData), - 'errors' => $errors - ]; - } - - /** - * Build DSN string from config. - */ - private function buildDsn(): string { - $driver = $this->config['driver'] ?? 'mysql'; - $host = $this->config['host'] ?? 'localhost'; - $port = $this->config['port'] ?? 3306; - $database = $this->config['database'] ?? ''; - - return "$driver:host=$host;port=$port;dbname=$database;charset=utf8mb4"; - } - - /** - * Ensure database connection exists. - */ - private function ensureConnected(): void { - if (!$this->isConnected()) { - throw new Exception('Not connected to database. Call connect() first.'); - } - } - - /** - * Ensure migrations table exists. - */ - private function ensureMigrationsTable(): void { - $sql = "CREATE TABLE IF NOT EXISTS migrations ( - id INT AUTO_INCREMENT PRIMARY KEY, - filename VARCHAR(255) NOT NULL UNIQUE, - executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - )"; - - $this->connection->exec($sql); - } - - /** - * Format bytes to human readable format. - */ - private function formatBytes(int $bytes): string { - if ($bytes === 0) { - return '0 B'; - } - - $units = ['B', 'KB', 'MB', 'GB', 'TB']; - $unitIndex = 0; - - while ($bytes >= 1024 && $unitIndex < count($units) - 1) { - $bytes /= 1024; - $unitIndex++; - } - - return sprintf('%.1f %s', $bytes, $units[$unitIndex]); - } - - /** - * Load database configuration. - */ - private function loadConfig(): void { - $this->config = [ - 'driver' => 'mysql', - 'host' => 'localhost', - 'port' => 3306, - 'database' => 'test_db', - 'username' => 'root', - 'password' => '' - ]; - } - - /** - * Split SQL into individual statements. - */ - private function splitSqlStatements(string $sql): array { - // Simple split by semicolon (could be improved for complex cases) - $statements = explode(';', $sql); - - return array_filter(array_map('trim', $statements)); - } -} diff --git a/examples/13-database-cli/README.md b/examples/13-database-cli/README.md deleted file mode 100644 index 96439ce..0000000 --- a/examples/13-database-cli/README.md +++ /dev/null @@ -1,258 +0,0 @@ -# Database CLI Tool Example - -This example demonstrates building a comprehensive database management CLI tool with migrations, seeding, and advanced database operations. - -## 🎯 What You'll Learn - -- Database connection management -- Migration system implementation -- Data seeding and fixtures -- Query execution and results formatting -- Database schema inspection -- Backup and restore operations -- Performance monitoring and optimization - -## πŸ“ Project Structure - -``` -13-database-cli/ -β”œβ”€β”€ commands/ # Database command classes -β”‚ β”œβ”€β”€ MigrateCommand.php -β”‚ β”œβ”€β”€ SeedCommand.php -β”‚ β”œβ”€β”€ QueryCommand.php -β”‚ └── SchemaCommand.php -β”œβ”€β”€ migrations/ # Database migration files -β”‚ β”œβ”€β”€ 001_create_users_table.sql -β”‚ β”œβ”€β”€ 002_create_posts_table.sql -β”‚ └── 003_add_indexes.sql -β”œβ”€β”€ seeds/ # Database seed files -β”‚ β”œβ”€β”€ users.json -β”‚ └── posts.json -β”œβ”€β”€ DatabaseManager.php # Core database functionality -β”œβ”€β”€ main.php # Entry point -└── README.md # This file -``` - -## πŸš€ Running the Examples - -### Database Connection -```bash -# Test database connection -php main.php db:connect --host=localhost --database=myapp - -# Show connection status -php main.php db:status -``` - -### Migrations -```bash -# Run all pending migrations -php main.php migrate - -# Run specific migration -php main.php migrate --file=001_create_users_table.sql - -# Rollback last migration -php main.php migrate:rollback - -# Show migration status -php main.php migrate:status -``` - -### Data Seeding -```bash -# Seed all tables -php main.php seed - -# Seed specific table -php main.php seed --table=users - -# Seed with custom data -php main.php seed --file=custom_data.json -``` - -### Query Operations -```bash -# Execute SQL query -php main.php query --sql="SELECT * FROM users LIMIT 10" - -# Execute query from file -php main.php query --file=reports/monthly_stats.sql - -# Interactive query mode -php main.php query --interactive -``` - -### Schema Operations -```bash -# Show database schema -php main.php schema - -# Describe specific table -php main.php schema:table --name=users - -# Generate schema documentation -php main.php schema:docs --output=schema.md -``` - -### Backup & Restore -```bash -# Create database backup -php main.php backup --output=backup_2024-01-20.sql - -# Restore from backup -php main.php restore --file=backup_2024-01-20.sql - -# List available backups -php main.php backup:list -``` - -## πŸ“– Key Features - -### 1. Migration System -- **Version control**: Track database schema changes -- **Rollback support**: Undo migrations safely -- **Dependency management**: Handle migration dependencies -- **Batch operations**: Run multiple migrations -- **Status tracking**: Monitor migration state - -### 2. Data Management -- **Seeding**: Populate tables with test data -- **Fixtures**: Reusable data sets -- **Import/Export**: Data transfer utilities -- **Validation**: Data integrity checks -- **Relationships**: Handle foreign key constraints - -### 3. Query Interface -- **Interactive mode**: Real-time query execution -- **Result formatting**: Multiple output formats -- **Query history**: Track executed queries -- **Performance metrics**: Query execution stats -- **Syntax highlighting**: Enhanced readability - -### 4. Schema Management -- **Inspection**: Analyze database structure -- **Documentation**: Generate schema docs -- **Comparison**: Compare schema versions -- **Optimization**: Index and performance suggestions -- **Visualization**: Schema relationship diagrams - -## 🎨 Expected Output - -### Migration Status -``` -πŸ“Š Migration Status -================== - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Migration β”‚ Status β”‚ Executed At β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 001_create_users_table.sql β”‚ βœ… Done β”‚ 2024-01-15 10:30:00 β”‚ -β”‚ 002_create_posts_table.sql β”‚ βœ… Done β”‚ 2024-01-15 10:30:15 β”‚ -β”‚ 003_add_indexes.sql β”‚ ⏳ Pending β”‚ - β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -πŸ“ˆ Summary: 2 completed, 1 pending -``` - -### Query Results -``` -πŸ” Query Results -=============== - -Query: SELECT id, name, email, created_at FROM users LIMIT 5 -Execution time: 0.023s -Rows returned: 5 - -β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ID β”‚ Name β”‚ Email β”‚ Created At β”‚ -β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 1 β”‚ John Doe β”‚ john@example.com β”‚ 2024-01-15 10:30:00 β”‚ -β”‚ 2 β”‚ Jane Smith β”‚ jane@example.com β”‚ 2024-01-15 11:15:30 β”‚ -β”‚ 3 β”‚ Bob Johnson β”‚ bob@example.com β”‚ 2024-01-15 12:45:15 β”‚ -β”‚ 4 β”‚ Alice Brown β”‚ alice@example.com β”‚ 2024-01-15 14:20:45 β”‚ -β”‚ 5 β”‚ Charlie Lee β”‚ charlie@example.com β”‚ 2024-01-15 15:10:20 β”‚ -β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -πŸ’‘ Query completed successfully -``` - -### Schema Information -``` -πŸ—„οΈ Database Schema: myapp -========================== - -πŸ“Š Tables Overview: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Table β”‚ Columns β”‚ Rows β”‚ Size β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ users β”‚ 8 β”‚ 1,234 β”‚ 2.3 MB β”‚ -β”‚ posts β”‚ 12 β”‚ 5,678 β”‚ 15.7 MB β”‚ -β”‚ comments β”‚ 6 β”‚ 12,345 β”‚ 8.9 MB β”‚ -β”‚ categories β”‚ 4 β”‚ 25 β”‚ 4.2 KB β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -πŸ”— Relationships: - β€’ users β†’ posts (1:many) - β€’ posts β†’ comments (1:many) - β€’ categories β†’ posts (1:many) - -πŸ“ˆ Total: 4 tables, 19,282 rows, 26.9 MB -``` - -### Backup Progress -``` -πŸ’Ύ Creating Database Backup -=========================== - -Analyzing database structure... -[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 100.0% - -Exporting table data: - β€’ users: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 1,234 rows - β€’ posts: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 5,678 rows - β€’ comments: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 12,345 rows - β€’ categories: [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 25 rows - -βœ… Backup completed successfully! - -πŸ“‹ Backup Summary: - β€’ File: backup_2024-01-20_14-30-15.sql - β€’ Size: 45.2 MB - β€’ Tables: 4 - β€’ Total Rows: 19,282 - β€’ Duration: 00:02:15 - β€’ Compression: gzip (87% reduction) -``` - -## πŸ”— Next Steps - -After mastering this example, explore: -- **Real database integration**: Connect to MySQL, PostgreSQL, SQLite -- **ORM integration**: Use with Eloquent, Doctrine, etc. -- **Cloud database support**: AWS RDS, Google Cloud SQL -- **Advanced features**: Replication, clustering, performance tuning - -## πŸ’‘ Try This - -Extend the database CLI: - -1. **Add more database types**: Support MongoDB, Redis, etc. -2. **Implement connection pooling**: Manage multiple connections -3. **Add query optimization**: Analyze and suggest improvements -4. **Create data visualization**: Generate charts from query results -5. **Add replication support**: Master-slave configuration - -```php -// Example: Add query optimization -class QueryOptimizer { - public function analyze(string $query): array { - // Analyze query performance - return [ - 'execution_time' => 0.045, - 'rows_examined' => 1000, - 'suggestions' => ['Add index on user_id column'] - ]; - } -} -``` diff --git a/examples/13-database-cli/main.php b/examples/13-database-cli/main.php deleted file mode 100644 index 7033d0c..0000000 --- a/examples/13-database-cli/main.php +++ /dev/null @@ -1,36 +0,0 @@ -register(new HelpCommand()); - -// Initialize database manager -$dbManager = new DatabaseManager(); - -// Set default command -$runner->setDefaultCommand('help'); - -// Start the application -exit($runner->start()); diff --git a/examples/13-database-cli/migrations/001_create_users_table.sql b/examples/13-database-cli/migrations/001_create_users_table.sql deleted file mode 100644 index 7628d54..0000000 --- a/examples/13-database-cli/migrations/001_create_users_table.sql +++ /dev/null @@ -1,14 +0,0 @@ --- Create users table -CREATE TABLE users ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(100) NOT NULL, - email VARCHAR(255) NOT NULL UNIQUE, - password VARCHAR(255) NOT NULL, - status ENUM('active', 'inactive') DEFAULT 'active', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - INDEX idx_email (email), - INDEX idx_status (status), - INDEX idx_created_at (created_at) -); diff --git a/examples/13-database-cli/seeds/users.json b/examples/13-database-cli/seeds/users.json deleted file mode 100644 index f76be0e..0000000 --- a/examples/13-database-cli/seeds/users.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "name": "John Doe", - "email": "john.doe@example.com", - "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", - "status": "active" - }, - { - "name": "Jane Smith", - "email": "jane.smith@example.com", - "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", - "status": "active" - }, - { - "name": "Bob Johnson", - "email": "bob.johnson@example.com", - "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", - "status": "inactive" - }, - { - "name": "Alice Brown", - "email": "alice.brown@example.com", - "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", - "status": "active" - }, - { - "name": "Charlie Wilson", - "email": "charlie.wilson@example.com", - "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", - "status": "active" - } -] diff --git a/examples/15-table-display/README.md b/examples/15-table-display/README.md deleted file mode 100644 index 4754cbc..0000000 --- a/examples/15-table-display/README.md +++ /dev/null @@ -1,248 +0,0 @@ -# πŸ“Š Example 15: Table Display - -A comprehensive demonstration of the WebFiori CLI Table feature, showcasing professional tabular data display capabilities with various styling options, data formatting, and responsive design. - -## 🎯 What This Example Demonstrates - -### Core Table Features -- **Multiple table styles** (bordered, simple, minimal, compact, markdown) -- **Column configuration** (width, alignment, formatting) -- **Data type handling** (currency, dates, percentages, booleans) -- **Color themes** (default, dark, colorful, professional) -- **Status-based colorization** (active=green, error=red, etc.) -- **Responsive design** that adapts to terminal width - -### Real-World Use Cases -- **User Management** - Display user accounts with status indicators -- **Product Catalogs** - Show inventory with pricing and stock levels -- **Service Monitoring** - System health dashboards with metrics -- **Data Export** - Various output formats for integration - -## πŸš€ Running the Example - -### Basic Usage -```bash -# Run all demonstrations -php main.php table-demo - -# Show help -php main.php help --command-name=table-demo -``` - -### Specific Demonstrations -```bash -# User management table -php main.php table-demo --demo=users - -# Product catalog -php main.php table-demo --demo=products - -# Service status monitoring -php main.php table-demo --demo=services - -# Table style variations -php main.php table-demo --demo=styles - -# Color theme showcase -php main.php table-demo --demo=themes - -# Data export capabilities -php main.php table-demo --demo=export -``` - -### Customization Options -```bash -# Use different table style -php main.php table-demo --demo=users --style=simple - -# Apply color theme -php main.php table-demo --demo=products --theme=colorful - -# Set custom width -php main.php table-demo --demo=services --width=100 - -# Combine options -php main.php table-demo --demo=users --style=bordered --theme=professional --width=120 -``` - -## πŸ“‹ Available Options - -### Demo Types -- `users` - User management system with status indicators -- `products` - Product catalog with pricing and inventory -- `services` - Service monitoring dashboard -- `styles` - Showcase of different table styles -- `themes` - Color theme demonstrations -- `export` - Data export format examples -- `all` - Run all demonstrations (default) - -### Table Styles -- `bordered` - Unicode box-drawing characters (default) -- `simple` - ASCII characters for maximum compatibility -- `minimal` - Clean look with reduced borders -- `compact` - Space-efficient layout -- `markdown` - Markdown-compatible format - -### Color Themes -- `default` - Standard theme with basic colors -- `dark` - Optimized for dark terminals -- `light` - Optimized for light terminals -- `colorful` - Vibrant colors and styling -- `professional` - Business-appropriate styling -- `minimal` - No colors, just formatting - -## 🎨 Example Output - -### User Management Table -``` -User Management Dashboard -β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ID β”‚ Name β”‚ Email β”‚ Status β”‚ Created β”‚ Role β”‚ Balance β”‚ -β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 1 β”‚ John Doe β”‚ john.doe@example.com β”‚ Active β”‚ Jan 15, 24 β”‚ Admin β”‚ $1,250.75 β”‚ -β”‚ 2 β”‚ Jane Smith β”‚ jane.smith@example.com β”‚ Inactive β”‚ Jan 16, 24 β”‚ User β”‚ $890.50 β”‚ -β”‚ 3 β”‚ Bob Johnson β”‚ bob.johnson@example.com β”‚ Active β”‚ Jan 17, 24 β”‚ Managerβ”‚ $2,100.00 β”‚ -β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Service Status Monitor -``` -System Health Dashboard -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Service β”‚ Version β”‚ Status β”‚ Uptime β”‚ Response β”‚ Memory β”‚ Health β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Web Server β”‚ nginx/1.20 β”‚ Running β”‚ 99.9% β”‚ 45ms β”‚ 2.1GB β”‚ βœ… β”‚ -β”‚ Database β”‚ MySQL 8.0 β”‚ Running β”‚ 99.8% β”‚ 12ms β”‚ 4.5GB β”‚ βœ… β”‚ -β”‚ Cache Server β”‚ Redis 6.2 β”‚ Stopped β”‚ 0% β”‚ N/A β”‚ 0MB β”‚ ❌ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -## πŸ’‘ Key Features Demonstrated - -### 1. Column Configuration -```php -->configureColumn('Price', [ - 'width' => 10, - 'align' => 'right', - 'formatter' => fn($value) => '$' . number_format($value, 2) -]) -``` - -### 2. Status-Based Colorization -```php -->colorizeColumn('Status', function($value) { - return match(strtolower($value)) { - 'active' => ['color' => 'green', 'bold' => true], - 'inactive' => ['color' => 'red', 'bold' => true], - 'pending' => ['color' => 'yellow', 'bold' => true], - default => [] - }; -}) -``` - -### 3. Data Formatting -```php -->configureColumn('Created', [ - 'formatter' => fn($date) => date('M j, Y', strtotime($date)) -]) -``` - -### 4. Responsive Design -```php -->setMaxWidth($terminalWidth) -->configureColumn('Email', ['truncate' => true]) -``` - -## πŸ”§ Integration Examples - -### In a CLI Command -```php -use WebFiori\Cli\CLICommand; -use WebFiori\Cli\Table\TableBuilder; - -class ListUsersCommand extends CLICommand { - public function exec(): int { - $users = $this->getUsersFromDatabase(); - - $table = TableBuilder::create() - ->setHeaders(['ID', 'Name', 'Email', 'Status']) - ->setData($users) - ->colorizeColumn('Status', function($value) { - return match(strtolower($value)) { - 'active' => ['color' => 'green'], - 'inactive' => ['color' => 'red'], - default => [] - }; - }); - - echo $table->render(); - return 0; - } -} -``` - -### With Database Results -```php -// Fetch data from database -$results = $pdo->query("SELECT id, name, email, status FROM users")->fetchAll(); - -// Display in table -$table = TableBuilder::create() - ->setHeaders(['ID', 'Name', 'Email', 'Status']) - ->setData($results) - ->setMaxWidth(100); - -echo $table->render(); -``` - -### Export Data -```php -use WebFiori\Cli\Table\TableData; - -$data = new TableData($headers, $rows); - -// Export to JSON -file_put_contents('users.json', $data->toJson(true)); - -// Export to CSV -file_put_contents('users.csv', $data->toCsv(true)); -``` - -## 🎯 Best Practices Shown - -### 1. Responsive Design -- Auto-detect terminal width -- Configure column truncation for long content -- Use appropriate column widths - -### 2. User Experience -- Clear status indicators with colors -- Consistent data formatting -- Meaningful column headers - -### 3. Performance -- Efficient rendering for large datasets -- Memory-conscious data handling -- Fast column width calculations - -### 4. Accessibility -- High contrast color options -- ASCII fallbacks for compatibility -- Clear visual hierarchy - -## πŸ”— Related Examples - -After mastering this example, explore: -- **[10-multi-command-app](../10-multi-command-app/)** - Complete CLI application architecture -- **[04-output-formatting](../04-output-formatting/)** - ANSI colors and formatting -- **[13-database-cli](../13-database-cli/)** - Database management tools - -## πŸ“š Additional Resources - -- **Table Documentation**: `WebFiori/Cli/Table/README.md` -- **WebFiori CLI Guide**: Main project documentation -- **ANSI Color Reference**: Terminal color codes and compatibility - ---- - -This example demonstrates the full power of the WebFiori CLI Table feature, showing how to create professional, responsive, and visually appealing data displays for command-line applications. diff --git a/examples/15-table-display/TableDemoCommand.php b/examples/15-table-display/TableDemoCommand.php deleted file mode 100644 index 7930560..0000000 --- a/examples/15-table-display/TableDemoCommand.php +++ /dev/null @@ -1,459 +0,0 @@ - [ - 'optional' => true, - 'description' => 'Specific demo to run (users, products, services, styles, themes, export)', - 'values' => ['users', 'products', 'services', 'styles', 'themes', 'export', 'all'] - ], - '--style' => [ - 'optional' => true, - 'description' => 'Table style to use', - 'values' => ['bordered', 'simple', 'minimal', 'compact', 'markdown'], - 'default' => 'bordered' - ], - '--theme' => [ - 'optional' => true, - 'description' => 'Color theme to use', - 'values' => ['default', 'dark', 'light', 'colorful', 'professional', 'minimal'], - 'default' => 'default' - ], - '--width' => [ - 'optional' => true, - 'description' => 'Maximum table width (default: auto-detect)', - 'default' => '0' - ] - ], 'Demonstrates WebFiori CLI Table display capabilities with various examples'); - } - - public function exec(): int { - $this->println('🎯 WebFiori CLI Table Feature Demonstration', ['bold' => true, 'color' => 'light-cyan']); - $this->println('============================================'); - $this->println(''); - - $demo = $this->getArgValue('--demo') ?? 'all'; - $style = $this->getArgValue('--style') ?? 'bordered'; - $theme = $this->getArgValue('--theme') ?? 'default'; - $width = (int)($this->getArgValue('--width') ?? '0'); - - if ($width === 0) { - $width = $this->getTerminalWidth(); - } - - $this->println("Configuration:", ['color' => 'yellow']); - $this->println(" β€’ Demo: $demo"); - $this->println(" β€’ Style: $style"); - $this->println(" β€’ Theme: $theme"); - $this->println(" β€’ Width: {$width} characters"); - $this->println(''); - - try { - switch ($demo) { - case 'users': - $this->demoUserManagement($style, $theme, $width); - break; - case 'products': - $this->demoProductCatalog($style, $theme, $width); - break; - case 'services': - $this->demoServiceStatus($style, $theme, $width); - break; - case 'styles': - $this->demoTableStyles($width); - break; - case 'themes': - $this->demoColorThemes($width); - break; - case 'export': - $this->demoDataExport($style, $theme, $width); - break; - case 'all': - default: - $this->runAllDemos($style, $theme, $width); - break; - } - - $this->println(''); - $this->success('✨ Table demonstration completed successfully!'); - $this->println(''); - $this->info('πŸ’‘ Tips:'); - $this->println(' β€’ Use --demo= to run specific demonstrations'); - $this->println(' β€’ Try different --style and --theme combinations'); - $this->println(' β€’ Adjust --width for different terminal sizes'); - - return 0; - } catch (Exception $e) { - $this->error('Demo failed: '.$e->getMessage()); - - return 1; - } - } - - /** - * Demonstrate color themes. - */ - private function demoColorThemes(int $width): void { - $this->println('🌈 Color Theme Showcase', ['bold' => true, 'color' => 'light-magenta']); - $this->println('-----------------------'); - - $data = [ - ['Active', 25, '83.3%'], - ['Inactive', 3, '10.0%'], - ['Pending', 2, '6.7%'] - ]; - - $themes = [ - 'default' => 'Standard theme with basic colors', - 'dark' => 'Dark theme for dark terminals', - 'colorful' => 'Vibrant colors and styling', - 'professional' => 'Business-appropriate styling' - ]; - - foreach ($themes as $themeName => $description) { - $this->println("Theme: ".ucfirst($themeName)." ($description)", ['color' => 'yellow']); - - $table = TableBuilder::create() - ->setHeaders(['Status', 'Count', 'Percentage']) - ->addRows($data) - ->setTheme(TableTheme::create($themeName)) - ->setMaxWidth(min($width, 50)) - ->configureColumn('Count', ['align' => 'right']) - ->configureColumn('Percentage', [ - 'align' => 'right', - 'formatter' => fn($value) => str_replace('%', '', $value).'%' - ]) - ->colorizeColumn('Status', function ($value) { - return match (strtolower($value)) { - 'active' => ['color' => 'green', 'bold' => true], - 'inactive' => ['color' => 'red'], - 'pending' => ['color' => 'yellow'], - default => [] - }; - }); - - echo $table->render(); - $this->println(''); - } - - $this->info('Themes automatically adapt to terminal capabilities.'); - } - - /** - * Demonstrate data export capabilities. - */ - private function demoDataExport(string $style, string $theme, int $width): void { - $this->println('πŸ’Ύ Data Export Capabilities', ['bold' => true, 'color' => 'light-green']); - $this->println('---------------------------'); - - $exportData = [ - ['1', 'John Doe', 'john@example.com', 'Active'], - ['2', 'Jane Smith', 'jane@example.com', 'Inactive'], - ['3', 'Bob Johnson', 'bob@example.com', 'Active'] - ]; - - $table = TableBuilder::create() - ->setHeaders(['ID', 'Name', 'Email', 'Status']) - ->addRows($exportData) - ->setTitle('Sample Export Data') - ->useStyle($style) - ->setTheme(TableTheme::create($theme)) - ->setMaxWidth($width); - - echo $table->render(); - - $this->println(''); - $this->info('Export formats available:'); - $this->println(' β€’ JSON format (structured data)'); - $this->println(' β€’ CSV format (spreadsheet compatible)'); - $this->println(' β€’ Array format (PHP arrays)'); - $this->println(' β€’ Associative arrays (key-value pairs)'); - $this->println(''); - $this->println('Note: In a real application, you would access the TableData'); - $this->println('object to export data in various formats.'); - } - - /** - * Demonstrate product catalog table. - */ - private function demoProductCatalog(string $style, string $theme, int $width): void { - $this->println('πŸ›οΈ Product Catalog', ['bold' => true, 'color' => 'blue']); - $this->println('------------------'); - - $products = [ - ['LAP001', 'MacBook Pro 16"', 2499.99, 15, 'Electronics', true, 4.8], - ['MOU002', 'Wireless Mouse', 29.99, 0, 'Accessories', true, 4.2], - ['KEY003', 'Mechanical Keyboard', 149.99, 25, 'Accessories', true, 4.6], - ['MON004', '4K Monitor 27"', 399.99, 8, 'Electronics', false, 4.4], - ['HDD005', 'External SSD 1TB', 199.99, 50, 'Storage', true, 4.7] - ]; - - $table = TableBuilder::create() - ->setHeaders(['SKU', 'Product Name', 'Price', 'Stock', 'Category', 'Featured', 'Rating']) - ->addRows($products) - ->setTitle('Product Inventory') - ->useStyle($style) - ->setTheme(TableTheme::create($theme)) - ->setMaxWidth($width) - ->configureColumn('SKU', ['width' => 8, 'align' => 'center']) - ->configureColumn('Product Name', ['width' => 20, 'truncate' => true]) - ->configureColumn('Price', [ - 'width' => 10, - 'align' => 'right', - 'formatter' => fn($value) => '$'.number_format($value, 2) - ]) - ->configureColumn('Stock', [ - 'width' => 6, - 'align' => 'right', - 'formatter' => fn($value) => $value > 0 ? (string)$value : 'Out' - ]) - ->configureColumn('Category', ['width' => 12, 'align' => 'center']) - ->configureColumn('Featured', [ - 'width' => 9, - 'align' => 'center', - 'formatter' => fn($value) => $value ? '⭐ Yes' : ' No' - ]) - ->configureColumn('Rating', [ - 'width' => 7, - 'align' => 'center', - 'formatter' => fn($value) => 'β˜… '.number_format($value, 1) - ]) - ->colorizeColumn('Stock', function ($value) { - if ($value === 'Out' || $value === 0) { - return ['color' => 'red', 'bold' => true]; - } elseif (is_numeric($value) && $value < 10) { - return ['color' => 'yellow']; - } - - return ['color' => 'green']; - }); - - echo $table->render(); - - $this->println(''); - $this->info('Features demonstrated:'); - $this->println(' β€’ Currency formatting'); - $this->println(' β€’ Stock level indicators with colors'); - $this->println(' β€’ Boolean formatting with icons'); - $this->println(' β€’ Rating display with stars'); - $this->println(' β€’ Product name truncation'); - } - - /** - * Demonstrate service status monitoring. - */ - private function demoServiceStatus(string $style, string $theme, int $width): void { - $this->println('πŸ”§ Service Status Monitor', ['bold' => true, 'color' => 'magenta']); - $this->println('-------------------------'); - - $services = [ - ['Web Server', 'nginx/1.20', 'Running', '99.9%', '45ms', '2.1GB', 'βœ…'], - ['Database', 'MySQL 8.0', 'Running', '99.8%', '12ms', '4.5GB', 'βœ…'], - ['Cache Server', 'Redis 6.2', 'Stopped', '0%', 'N/A', '0MB', '❌'], - ['API Gateway', 'Kong 3.0', 'Running', '99.7%', '78ms', '512MB', 'βœ…'], - ['Message Queue', 'RabbitMQ', 'Warning', '95.2%', '156ms', '1.2GB', '⚠️'], - ['Load Balancer', 'HAProxy', 'Running', '100%', '5ms', '128MB', 'βœ…'] - ]; - - $table = TableBuilder::create() - ->setHeaders(['Service', 'Version', 'Status', 'Uptime', 'Response', 'Memory', 'Health']) - ->addRows($services) - ->setTitle('System Health Dashboard') - ->useStyle($style) - ->setTheme(TableTheme::create($theme)) - ->setMaxWidth($width) - ->configureColumn('Service', ['width' => 14, 'align' => 'left']) - ->configureColumn('Version', ['width' => 12, 'align' => 'center']) - ->configureColumn('Status', ['width' => 10, 'align' => 'center']) - ->configureColumn('Uptime', ['width' => 8, 'align' => 'right']) - ->configureColumn('Response', ['width' => 10, 'align' => 'right']) - ->configureColumn('Memory', ['width' => 8, 'align' => 'right']) - ->configureColumn('Health', ['width' => 8, 'align' => 'center']) - ->colorizeColumn('Status', function ($value) { - return match (strtolower($value)) { - 'running' => ['color' => 'green', 'bold' => true], - 'stopped' => ['color' => 'red', 'bold' => true], - 'warning' => ['color' => 'yellow', 'bold' => true], - default => [] - }; - }) - ->colorizeColumn('Health', function ($value) { - return match ($value) { - 'βœ…' => ['color' => 'green'], - '❌' => ['color' => 'red'], - '⚠️' => ['color' => 'yellow'], - default => [] - }; - }); - - echo $table->render(); - - $this->println(''); - $this->info('Features demonstrated:'); - $this->println(' β€’ System monitoring data display'); - $this->println(' β€’ Multiple status indicators'); - $this->println(' β€’ Performance metrics formatting'); - $this->println(' β€’ Health status with emoji indicators'); - $this->println(' β€’ Memory usage display'); - } - - /** - * Demonstrate different table styles. - */ - private function demoTableStyles(int $width): void { - $this->println('🎨 Table Style Variations', ['bold' => true, 'color' => 'cyan']); - $this->println('-------------------------'); - - $data = [ - ['Coffee', '$3.50', 'Hot'], - ['Tea', '$2.75', 'Hot'], - ['Juice', '$4.25', 'Cold'] - ]; - - $styles = [ - 'bordered' => 'Unicode box-drawing characters', - 'simple' => 'ASCII characters for compatibility', - 'minimal' => 'Clean look with minimal borders', - 'compact' => 'Space-efficient layout', - 'markdown' => 'Markdown-compatible format' - ]; - - foreach ($styles as $styleName => $description) { - $this->println("Style: ".ucfirst($styleName)." ($description)", ['color' => 'yellow']); - - $table = TableBuilder::create() - ->setHeaders(['Item', 'Price', 'Temperature']) - ->addRows($data) - ->useStyle($styleName) - ->setMaxWidth(min($width, 60)); // Limit width for style demo - - echo $table->render(); - $this->println(''); - } - - $this->info('All table styles are responsive and adapt to terminal width.'); - } - - /** - * Demonstrate user management table. - */ - private function demoUserManagement(string $style, string $theme, int $width): void { - $this->println('πŸ‘₯ User Management System', ['bold' => true, 'color' => 'green']); - $this->println('-------------------------'); - - $users = [ - ['1', 'John Doe', 'john.doe@example.com', 'Active', '2024-01-15', 'Admin', '$1,250.75'], - ['2', 'Jane Smith', 'jane.smith@example.com', 'Inactive', '2024-01-16', 'User', '$890.50'], - ['3', 'Bob Johnson', 'bob.johnson@example.com', 'Active', '2024-01-17', 'Manager', '$2,100.00'], - ['4', 'Alice Brown', 'alice.brown@example.com', 'Pending', '2024-01-18', 'User', '$750.25'], - ['5', 'Charlie Davis', 'charlie.davis@example.com', 'Active', '2024-01-19', 'Admin', '$1,800.80'] - ]; - - $table = TableBuilder::create() - ->setHeaders(['ID', 'Name', 'Email', 'Status', 'Created', 'Role', 'Balance']) - ->addRows($users) - ->setTitle('User Management Dashboard') - ->useStyle($style) - ->setTheme(TableTheme::create($theme)) - ->setMaxWidth($width) - ->configureColumn('ID', ['width' => 4, 'align' => 'center']) - ->configureColumn('Name', ['width' => 15, 'align' => 'left']) - ->configureColumn('Email', ['width' => 25, 'truncate' => true]) - ->configureColumn('Status', ['width' => 10, 'align' => 'center']) - ->configureColumn('Created', [ - 'width' => 12, - 'align' => 'center', - 'formatter' => fn($date) => date('M j, Y', strtotime($date)) - ]) - ->configureColumn('Role', ['width' => 8, 'align' => 'center']) - ->configureColumn('Balance', [ - 'width' => 12, - 'align' => 'right', - 'formatter' => fn($value) => str_replace('$', '', $value) // Remove existing $ for proper formatting - ]) - ->colorizeColumn('Status', function ($value) { - return match (strtolower($value)) { - 'active' => ['color' => 'green', 'bold' => true], - 'inactive' => ['color' => 'red', 'bold' => true], - 'pending' => ['color' => 'yellow', 'bold' => true], - default => [] - }; - }); - - echo $table->render(); - - $this->println(''); - $this->info('Features demonstrated:'); - $this->println(' β€’ Column width control and alignment'); - $this->println(' β€’ Date formatting'); - $this->println(' β€’ Status-based colorization'); - $this->println(' β€’ Email truncation for long addresses'); - $this->println(' β€’ Responsive design within terminal width'); - } - - /** - * Get terminal width with fallback. - */ - private function getTerminalWidth(): int { - // Try to get terminal width - $width = exec('tput cols 2>/dev/null'); - - if (is_numeric($width)) { - return (int)$width; - } - - // Fallback to environment variable - $width = getenv('COLUMNS'); - - if ($width !== false && is_numeric($width)) { - return (int)$width; - } - - // Default fallback - return 80; - } - - /** - * Run all demonstrations. - */ - private function runAllDemos(string $style, string $theme, int $width): void { - $this->demoUserManagement($style, $theme, $width); - $this->println(''); - $this->demoProductCatalog($style, $theme, $width); - $this->println(''); - $this->demoServiceStatus($style, $theme, $width); - $this->println(''); - $this->demoTableStyles($width); - $this->println(''); - $this->demoColorThemes($width); - } -} diff --git a/examples/15-table-display/main.php b/examples/15-table-display/main.php deleted file mode 100644 index 685d706..0000000 --- a/examples/15-table-display/main.php +++ /dev/null @@ -1,17 +0,0 @@ -register(new HelpCommand()); -$runner->register(new TableDemoCommand()); -$runner->setDefaultCommand('help'); -// Start the application -exit($runner->start()); diff --git a/examples/15-table-display/simple-example.php b/examples/15-table-display/simple-example.php deleted file mode 100644 index 46cd63d..0000000 --- a/examples/15-table-display/simple-example.php +++ /dev/null @@ -1,59 +0,0 @@ -setHeaders(['Name', 'Age', 'City']) - ->addRow(['John Doe', 30, 'New York']) - ->addRow(['Jane Smith', 25, 'Los Angeles']) - ->addRow(['Bob Johnson', 35, 'Chicago']); - -echo $basicTable->render()."\n\n"; - -// Example 2: Formatted table with colors -echo "Example 2: Formatted Table with Colors\n"; -echo "--------------------------------------\n"; - -$formattedTable = TableBuilder::create() - ->setHeaders(['Product', 'Price', 'Status']) - ->addRow(['Laptop', 1299.99, 'Available']) - ->addRow(['Mouse', 29.99, 'Out of Stock']) - ->addRow(['Keyboard', 89.99, 'Available']) - ->configureColumn('Price', [ - 'align' => 'right', - 'formatter' => fn($value) => '$'.number_format($value, 2) - ]) - ->colorizeColumn('Status', function ($value) { - return match ($value) { - 'Available' => ['color' => 'green', 'bold' => true], - 'Out of Stock' => ['color' => 'red', 'bold' => true], - default => [] - }; - }); - -echo $formattedTable->render()."\n\n"; - -echo "✨ Simple examples completed successfully!\n"; diff --git a/examples/16-table-usage/BasicTableCommand.php b/examples/16-table-usage/BasicTableCommand.php deleted file mode 100644 index 7833c72..0000000 --- a/examples/16-table-usage/BasicTableCommand.php +++ /dev/null @@ -1,133 +0,0 @@ -println('πŸš€ Basic Table Usage', ['bold' => true, 'color' => 'cyan']); - $this->println('===================='); - $this->println(''); - - // Example 1: Simplest possible table - $this->info('1. Simplest Table'); - $this->println(''); - - $data = [ - ['Alice', 'Active'], - ['Bob', 'Inactive'], - ['Carol', 'Active'] - ]; - - $this->println('Just data and headers:'); - $this->table($data, ['Name', 'Status']); - $this->println(''); - - // Example 2: With title - $this->info('2. Table with Title'); - $this->println(''); - - $this->println('Adding a title:'); - $this->table($data, ['Name', 'Status'], [ - TableOptions::TITLE => 'User Status' - ]); - $this->println(''); - - // Example 3: Different style - $this->info('3. Different Style'); - $this->println(''); - - $this->println('Using simple ASCII style:'); - $this->table($data, ['Name', 'Status'], [ - TableOptions::STYLE => TableStyle::SIMPLE, - TableOptions::TITLE => 'User Status (ASCII)' - ]); - $this->println(''); - - // Example 4: With colors - $this->info('4. Adding Colors'); - $this->println(''); - - $this->println('Colorizing the Status column:'); - $this->table($data, ['Name', 'Status'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::TITLE => 'User Status (Colored)', - TableOptions::COLORIZE => [ - 'Status' => function ($value) { - if ($value === 'Active') { - return ['color' => 'green', 'bold' => true]; - } else { - return ['color' => 'red']; - } - } - ] - ]); - $this->println(''); - - // Example 5: Professional theme - $this->info('5. Professional Theme'); - $this->println(''); - - $this->println('Using professional theme:'); - $this->table($data, ['Name', 'Status'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'User Status (Professional)' - ]); - $this->println(''); - - // Example 6: Real-world data - $this->info('6. Real-World Example'); - $this->println(''); - - $employees = [ - ['John Doe', 'Manager', '$75,000', 'Full-time'], - ['Jane Smith', 'Developer', '$65,000', 'Full-time'], - ['Mike Johnson', 'Designer', '$55,000', 'Part-time'], - ['Sarah Wilson', 'Analyst', '$60,000', 'Full-time'] - ]; - - $this->println('Employee directory with formatting:'); - $this->table($employees, ['Name', 'Position', 'Salary', 'Type'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'Employee Directory', - TableOptions::COLUMNS => [ - 'Salary' => ['align' => 'right'] - ], - TableOptions::COLORIZE => [ - 'Type' => function ($value) { - return $value === 'Full-time' - ? ['color' => 'green'] - : ['color' => 'yellow']; - } - ] - ]); - $this->println(''); - - $this->success('βœ… Basic table usage examples completed!'); - $this->println(''); - - $this->info('πŸ’‘ Quick Tips:'); - $this->println(' β€’ Start with: $this->table($data, $headers)'); - $this->println(' β€’ Add title: [TableOptions::TITLE => "My Table"]'); - $this->println(' β€’ Change style: [TableOptions::STYLE => TableStyle::SIMPLE]'); - $this->println(' β€’ Add colors: [TableOptions::COLORIZE => [...]]'); - $this->println(' β€’ Use professional theme for business reports'); - $this->println(''); - $this->println('Run "table-usage" command for comprehensive examples!'); - - return 0; - } -} diff --git a/examples/16-table-usage/README.md b/examples/16-table-usage/README.md deleted file mode 100644 index f741dbb..0000000 --- a/examples/16-table-usage/README.md +++ /dev/null @@ -1,293 +0,0 @@ -# πŸ“Š Example 16: Complete Table Usage Guide - -This comprehensive example demonstrates all aspects of using tables in WebFiori CLI applications, from basic table creation to advanced styling and configuration. - -## 🎯 What This Example Demonstrates - -### Two Commands Available - -#### 1. `basic-table` - Quick Start Guide -- **Simple table creation** - Get started in 30 seconds -- **Progressive examples** - From simplest to real-world usage -- **Essential features** - Title, styles, colors, themes -- **Quick tips** - Best practices for immediate use - -#### 2. `table-usage` - Comprehensive Guide -- **Complete feature coverage** - All table capabilities -- **Advanced configuration** - Professional styling and formatting -- **Real-world examples** - System monitoring, user management, reports -- **Best practices** - Professional development guidelines - -### Core Table Features -- **Basic Table Creation** - Simple data display with headers -- **Command Integration** - Using `$this->table()` method in commands -- **Data Formatting** - Currency, dates, percentages, and custom formatting -- **Status Colorization** - Conditional color application based on data values -- **Column Configuration** - Width, alignment, and custom formatters - -### Styling and Themes -- **Table Styles** - All available styles (bordered, simple, minimal, etc.) -- **Color Themes** - Professional themes for different environments -- **Responsive Design** - Tables that adapt to terminal width -- **Custom Styling** - Advanced configuration options - -### Advanced Features -- **TableOptions Constants** - Type-safe configuration keys -- **TableStyle Constants** - Clean style name constants (no STYLE_ prefix) -- **TableTheme Constants** - Clean theme name constants (no THEME_ prefix) -- **Helper Methods** - Validation and utility functions -- **Error Handling** - Graceful handling of edge cases - -## πŸš€ Quick Start - -### Run the Basic Example -```bash -php main.php basic-table -``` - -This command shows: -1. **Simplest Table** - Just data and headers -2. **Table with Title** - Adding a title -3. **Different Style** - Using ASCII style -4. **Adding Colors** - Status colorization -5. **Professional Theme** - Business styling -6. **Real-World Example** - Employee directory - -### Run the Comprehensive Guide -```bash -php main.php table-usage -``` - -This command covers: -1. **Basic Table Usage** - Simple data display -2. **Command Integration** - Method chaining and integration -3. **Data Formatting** - Custom formatters and alignment -4. **System Status Dashboard** - Real-world monitoring example -5. **Style Showcase** - All 10 table styles demonstrated -6. **Theme Showcase** - All 7 color themes demonstrated -7. **User Management** - Complete CRUD-style table -8. **Constants Usage** - Type-safe configuration -9. **Error Handling** - Edge case management -10. **Best Practices** - Professional development guidelines - -## πŸ’‘ Basic Usage Examples - -### Simplest Possible Table -```php -use WebFiori\Cli\Command; - -class MyCommand extends Command { - public function exec(): int { - $data = [ - ['John Doe', 'Active'], - ['Jane Smith', 'Inactive'] - ]; - - // Just data and headers - that's it! - $this->table($data, ['Name', 'Status']); - - return 0; - } -} -``` - -### Adding a Title -```php -$this->table($data, ['Name', 'Status'], [ - TableOptions::TITLE => 'User Status' -]); -``` - -### Changing Style -```php -$this->table($data, ['Name', 'Status'], [ - TableOptions::STYLE => TableStyle::SIMPLE, - TableOptions::TITLE => 'User Status (ASCII)' -]); -``` - -### Adding Colors -```php -$this->table($data, ['Name', 'Status'], [ - TableOptions::COLORIZE => [ - 'Status' => function($value) { - return $value === 'Active' - ? ['color' => 'green', 'bold' => true] - : ['color' => 'red']; - } - ] -]); -``` - -## πŸ“‹ Configuration Options - -### TableOptions Constants -| Constant | Description | Example Values | -|----------|-------------|----------------| -| `STYLE` | Table visual style | `TableStyle::BORDERED` | -| `THEME` | Color theme | `TableTheme::PROFESSIONAL` | -| `TITLE` | Table title | `'User Report'` | -| `WIDTH` | Maximum width | `120` | -| `SHOW_HEADERS` | Show/hide headers | `true` | -| `COLUMNS` | Column configuration | `['Name' => ['align' => 'left']]` | -| `COLORIZE` | Column colorization | `['Status' => $colorFunction]` | - -### TableStyle Constants (Clean) -| Constant | Description | Visual Style | -|----------|-------------|--------------| -| `BORDERED` | Unicode box-drawing | `β”Œβ”€β”β”‚β””β”€β”˜` | -| `SIMPLE` | ASCII characters | `+-+|+-+` | -| `MINIMAL` | Clean minimal borders | `───` | -| `COMPACT` | Space-efficient | `│───` | -| `MARKDOWN` | Markdown-compatible | `|---|` | - -### TableTheme Constants (Clean) -| Constant | Description | Use Case | -|----------|-------------|----------| -| `DEFAULT` | Standard colors | General purpose | -| `DARK` | Dark terminal optimized | Dark backgrounds | -| `LIGHT` | Light terminal optimized | Light backgrounds | -| `PROFESSIONAL` | Business styling | Reports and presentations | -| `COLORFUL` | Vibrant colors | Status dashboards | - -## πŸ’‘ Best Practices - -### 1. Use Constants for Type Safety -```php -// βœ… Good - Type-safe with IDE support -use WebFiori\Cli\Table\TableStyle; -use WebFiori\Cli\Table\TableTheme; - -$config = [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL -]; - -// ❌ Avoid - Prone to typos -$config = [ - 'style' => 'borded', // Typo! - 'theme' => 'professional' -]; -``` - -### 2. Start Simple, Add Features Gradually -```php -// Step 1: Basic table -$this->table($data, $headers); - -// Step 2: Add title -$this->table($data, $headers, [ - TableOptions::TITLE => 'My Report' -]); - -// Step 3: Add styling -$this->table($data, $headers, [ - TableOptions::TITLE => 'My Report', - TableOptions::STYLE => TableStyle::PROFESSIONAL -]); - -// Step 4: Add colors -$this->table($data, $headers, [ - TableOptions::TITLE => 'My Report', - TableOptions::STYLE => TableStyle::PROFESSIONAL, - TableOptions::COLORIZE => [ - 'Status' => fn($v) => $v === 'Active' ? ['color' => 'green'] : ['color' => 'red'] - ] -]); -``` - -### 3. Create Reusable Configurations -```php -class TableConfigurations { - public static function getReportStyle(): array { - return [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::SHOW_HEADERS => true - ]; - } - - public static function getStatusStyle(): array { - return [ - TableOptions::STYLE => TableStyle::SIMPLE, - TableOptions::THEME => TableTheme::COLORFUL - ]; - } -} -``` - -## πŸ”§ Common Use Cases - -### 1. User Management -```php -$users = [ - ['Alice Johnson', 'alice@example.com', 'Admin', 'Active'], - ['Bob Smith', 'bob@example.com', 'User', 'Inactive'] -]; - -$this->table($users, ['Name', 'Email', 'Role', 'Status'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'User Directory' -]); -``` - -### 2. System Status -```php -$services = [ - ['Web Server', 'nginx', 'Running', '99.9%'], - ['Database', 'MySQL', 'Running', '99.8%'], - ['Cache', 'Redis', 'Stopped', '0%'] -]; - -$this->table($services, ['Service', 'Type', 'Status', 'Uptime'], [ - TableOptions::STYLE => TableStyle::SIMPLE, - TableOptions::THEME => TableTheme::COLORFUL, - TableOptions::COLORIZE => [ - 'Status' => function($value) { - return match(strtolower($value)) { - 'running' => ['color' => 'green', 'bold' => true], - 'stopped' => ['color' => 'red', 'bold' => true], - default => [] - }; - } - ] -]); -``` - -## 🎨 Learning Path - -### Beginner (5 minutes) -1. Run `php main.php basic-table` -2. Try the simplest example: `$this->table($data, $headers)` -3. Add a title and change the style - -### Intermediate (15 minutes) -1. Add status colorization -2. Try different themes -3. Format columns with alignment - -### Advanced (30 minutes) -1. Run `php main.php table-usage` -2. Study the comprehensive examples -3. Implement custom formatters and complex colorization - -## πŸ” Error Handling - -The table system includes comprehensive error handling: - -- **Missing table classes**: Graceful fallback with error message -- **Empty data**: Informative message instead of empty table -- **Invalid options**: Uses sensible defaults -- **Malformed data**: Handles edge cases gracefully - -## πŸ“š Additional Resources - -- **TableOptions Class**: Complete list of configuration options -- **TableStyle Class**: All available table styles -- **TableTheme Class**: All available color themes -- **Helper Methods**: Validation and utility functions - ---- - -This example provides everything you need to create professional, beautiful tables in your WebFiori CLI applications, from basic usage to advanced features! diff --git a/examples/16-table-usage/TableUsageCommand.php b/examples/16-table-usage/TableUsageCommand.php deleted file mode 100644 index 88ba787..0000000 --- a/examples/16-table-usage/TableUsageCommand.php +++ /dev/null @@ -1,259 +0,0 @@ -println('πŸ“Š WebFiori CLI Table Usage - Complete Guide', ['bold' => true, 'color' => 'cyan']); - $this->println('==============================================='); - $this->println(''); - - // Section 1: Basic Table Usage - $this->info('1. Basic Table Usage'); - $this->println('===================='); - $this->println(''); - - $basicData = [ - ['Alice Johnson', 'Manager', 'Active'], - ['Bob Smith', 'Developer', 'Active'], - ['Carol Davis', 'Designer', 'Inactive'] - ]; - - $this->println('Simple table with basic data:'); - $this->table($basicData, ['Name', 'Role', 'Status']); - $this->println(''); - - // Section 2: Command Integration - $this->info('2. Command Integration'); - $this->println('======================'); - $this->println(''); - - $this->println('Using $this->table() method in commands:'); - $this->table([ - ['Method Chaining', 'Supported'], - ['Error Handling', 'Built-in'], - ['Auto-loading', 'Automatic'] - ], ['Feature', 'Status'], [ - TableOptions::STYLE => TableStyle::SIMPLE, - TableOptions::TITLE => 'Command Integration Features' - ]); - $this->println(''); - - // Section 3: Data Formatting - $this->info('3. Data Formatting'); - $this->println('=================='); - $this->println(''); - - $simpleSalesData = [ - ['Q1 2024', '$125,000', 'Excellent'], - ['Q2 2024', '$98,000', 'Good'], - ['Q3 2024', '$156,000', 'Excellent'], - ['Q4 2024', '$87,000', 'Fair'] - ]; - - $this->println('Advanced data formatting with pre-formatted data:'); - $this->table($simpleSalesData, ['Quarter', 'Revenue', 'Performance'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'Quarterly Sales Report' - ]); - $this->println(''); - - // Section 4: System Status Example - $this->info('4. System Status Dashboard'); - $this->println('=========================='); - $this->println(''); - - $serviceStatusData = [ - ['Web Server', 'Running'], - ['Database', 'Running'], - ['Cache Server', 'Stopped'] - ]; - - $this->println('System monitoring dashboard:'); - $this->table($serviceStatusData, ['Service', 'Status']); - $this->println(''); - - // Section 5: Style Showcase - $this->info('5. Table Styles Showcase'); - $this->println('========================'); - $this->println(''); - - $showcaseData = [ - ['Coffee', '$3.50', 'Hot'], - ['Tea', '$2.75', 'Hot'], - ['Juice', '$4.25', 'Cold'] - ]; - - $styles = [ - TableStyle::BORDERED => 'Bordered Style (Unicode)', - TableStyle::SIMPLE => 'Simple Style (ASCII)', - TableStyle::MINIMAL => 'Minimal Style (Clean)', - TableStyle::COMPACT => 'Compact Style (Space-efficient)' - ]; - - foreach ($styles as $style => $description) { - $this->println($description.':'); - $this->table($showcaseData, ['Item', 'Price', 'Temperature'], [ - TableOptions::STYLE => $style, - TableOptions::WIDTH => 60 - ]); - $this->println(''); - } - - // Section 6: Theme Showcase - $this->info('6. Color Themes Showcase'); - $this->println('========================'); - $this->println(''); - - $this->println('Default Theme:'); - $this->table([ - ['Active', '25'], - ['Inactive', '3'] - ], ['Status', 'Count'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::TITLE => 'Default Theme Example' - ]); - $this->println(''); - - $this->println('Professional Theme:'); - $this->table([ - ['Active', '25'], - ['Inactive', '3'] - ], ['Status', 'Count'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'Professional Theme Example' - ]); - $this->println(''); - - // Section 7: User Management Example - $this->info('7. User Management Example'); - $this->println('=========================='); - $this->println(''); - - $users = [ - [1, 'Alice Johnson', 'alice@example.com', 'Admin', 'Active', '$1,250.75'], - [2, 'Bob Smith', 'bob@example.com', 'User', 'Active', '$890.50'], - [3, 'Carol Davis', 'carol@example.com', 'Manager', 'Inactive', '$2,100.00'], - [4, 'David Wilson', 'david@example.com', 'User', 'Pending', '$750.25'] - ]; - - $this->println('Complete user management table:'); - $this->table($users, ['ID', 'Name', 'Email', 'Role', 'Status', 'Balance'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'User Management Dashboard', - TableOptions::COLUMNS => [ - 'ID' => ['align' => 'center'], - 'Balance' => ['align' => 'right'] - ] - ]); - $this->println(''); - - // Section 8: Constants Usage - $this->info('8. Using Constants for Type Safety'); - $this->println('==================================='); - $this->println(''); - - $this->println('Available TableOptions constants:'); - $options = [ - ['STYLE', 'Table visual style'], - ['THEME', 'Color theme'], - ['TITLE', 'Table title'], - ['WIDTH', 'Maximum width'], - ['COLUMNS', 'Column configuration'], - ['COLORIZE', 'Color rules'] - ]; - - $this->table($options, ['Constant', 'Description'], [ - TableOptions::STYLE => TableStyle::MINIMAL, - TableOptions::TITLE => 'TableOptions Constants' - ]); - $this->println(''); - - $this->println('Available TableStyle constants:'); - $styleConstants = [ - ['BORDERED', 'Unicode box-drawing characters'], - ['SIMPLE', 'ASCII characters for compatibility'], - ['MINIMAL', 'Clean look with minimal borders'], - ['COMPACT', 'Space-efficient layout'], - ['MARKDOWN', 'Markdown-compatible format'] - ]; - - $this->table($styleConstants, ['Constant', 'Description'], [ - TableOptions::STYLE => TableStyle::MINIMAL, - TableOptions::TITLE => 'TableStyle Constants' - ]); - $this->println(''); - - $this->println('Available TableTheme constants:'); - $themeConstants = [ - ['DEFAULT', 'Standard theme with basic colors'], - ['DARK', 'Optimized for dark terminals'], - ['PROFESSIONAL', 'Business-appropriate styling'], - ['COLORFUL', 'Vibrant colors and styling'] - ]; - - $this->table($themeConstants, ['Constant', 'Description'], [ - TableOptions::STYLE => TableStyle::MINIMAL, - TableOptions::TITLE => 'TableTheme Constants' - ]); - $this->println(''); - - // Section 9: Error Handling - $this->info('9. Error Handling'); - $this->println('================='); - $this->println(''); - - $this->println('Testing empty data handling:'); - $this->table([], ['Name', 'Status']); - $this->println(''); - - // Section 10: Best Practices Summary - $this->info('10. Best Practices Summary'); - $this->println('=========================='); - $this->println(''); - - $bestPractices = [ - ['Use Constants', 'Always use TableOptions, TableStyle, and TableTheme constants'], - ['Format Data', 'Use column formatters for currency, dates, and percentages'], - ['Colorize Status', 'Apply colors to status columns for better visibility'], - ['Responsive Design', 'Let tables adapt to terminal width automatically'], - ['Error Handling', 'Table system handles edge cases gracefully'], - ['Reusable Config', 'Create configuration templates for consistency'] - ]; - - $this->table($bestPractices, ['Practice', 'Description'], [ - TableOptions::STYLE => TableStyle::BORDERED, - TableOptions::THEME => TableTheme::PROFESSIONAL, - TableOptions::TITLE => 'WebFiori CLI Table Best Practices' - ]); - $this->println(''); - - $this->success('βœ… Complete table usage demonstration finished!'); - $this->println(''); - - $this->info('πŸ’‘ Key Takeaways:'); - $this->println(' β€’ Use $this->table() method in any Command class'); - $this->println(' β€’ Leverage constants for type safety and IDE support'); - $this->println(' β€’ Apply formatters and colorization for professional output'); - $this->println(' β€’ Choose appropriate styles and themes for your use case'); - $this->println(' β€’ Tables automatically handle responsive design and errors'); - $this->println(' β€’ Create reusable configurations for consistency'); - - return 0; - } -} diff --git a/examples/16-table-usage/main.php b/examples/16-table-usage/main.php deleted file mode 100644 index 57fd1d0..0000000 --- a/examples/16-table-usage/main.php +++ /dev/null @@ -1,22 +0,0 @@ -register(new HelpCommand()); -$runner->setDefaultCommand('help'); - -// Register both table commands -$runner->register(new TableUsageCommand()); -$runner->register(new BasicTableCommand()); - -// Start the application -exit($runner->start()); From 0101875f2620983a251ae7ef68087bb604688461 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Sat, 27 Sep 2025 20:01:39 +0300 Subject: [PATCH 12/12] docs: Updated Documentation --- README.md | 49 +++++++++---------- examples/03-user-input/SimpleCommand.php | 2 +- .../FormattingDemoCommand.php | 8 +-- .../06-table-display/TableDemoCommand.php | 16 +++--- examples/06-table-display/simple-example.php | 6 +-- examples/09-database-ops/main.php | 12 ++--- examples/09-database-ops/seeds/users.json | 20 ++++---- .../commands/UserCommand.php | 6 +-- examples/10-multi-command-app/data/users.json | 12 ++--- 9 files changed, 65 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 38dcecd..35ffc2d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Class library that can help in writing command line based applications with mini

- + @@ -104,13 +104,13 @@ exit(\$runner->start()); A complete sample application with multiple examples can be found here: **[πŸ“ View Sample Application](https://github.com/WebFiori/cli/tree/main/examples)** The sample application includes: -- **[Basic Commands](https://github.com/WebFiori/cli/tree/main/examples/01-basic-command)** - Simple command creation -- **[Arguments Handling](https://github.com/WebFiori/cli/tree/main/examples/02-command-with-args)** - Working with command arguments -- **[Interactive Mode](https://github.com/WebFiori/cli/tree/main/examples/03-interactive-mode)** - Building interactive applications +- **[Basic Commands](https://github.com/WebFiori/cli/tree/main/examples/01-basic-hello-world)** - Simple command creation +- **[Arguments Handling](https://github.com/WebFiori/cli/tree/main/examples/02-arguments-and-options)** - Working with command arguments +- **[User Input](https://github.com/WebFiori/cli/tree/main/examples/03-user-input)** - Building interactive applications - **[Multi-Command Apps](https://github.com/WebFiori/cli/tree/main/examples/10-multi-command-app)** - Complex applications with multiple commands -- **[Progress Bars](https://github.com/WebFiori/cli/tree/main/examples/05-progress-bars)** - Visual progress indicators +- **[Progress Bars](https://github.com/WebFiori/cli/tree/main/examples/07-progress-bars)** - Visual progress indicators - **[Table Display](https://github.com/WebFiori/cli/tree/main/examples/06-table-display)** - Formatting data in tables -- **[Testing Examples](https://github.com/WebFiori/cli/tree/main/examples/tests)** - Unit testing your commands +- **[Database Operations](https://github.com/WebFiori/cli/tree/main/examples/09-database-ops)** - Database CLI commands ## Installation @@ -165,7 +165,7 @@ php app.php greet # Output: Hello from WebFiori CLI! ``` -**[πŸ“– View Complete Example](https://github.com/WebFiori/cli/tree/main/examples/01-basic-command)** +**[πŸ“– View Complete Example](https://github.com/WebFiori/cli/tree/main/examples/01-basic-hello-world)** ### Command with Arguments @@ -210,7 +210,7 @@ php app.php greet-person --name=Sarah # Output: Hello Friend Sarah! ``` -**[πŸ“– View Complete Example](https://github.com/WebFiori/cli/tree/main/examples/02-command-with-args)** +**[πŸ“– View Complete Example](https://github.com/WebFiori/cli/tree/main/examples/02-arguments-and-options)** ### Multi-Command Application @@ -394,7 +394,7 @@ This will show following output in terminal: >> ``` -**[πŸ“– View Interactive Mode Example](https://github.com/WebFiori/cli/tree/main/examples/03-interactive-mode)** +**[πŸ“– View Interactive Mode Example](https://github.com/WebFiori/cli/tree/main/examples/05-interactive-commands)** ### Input and Output Streams @@ -411,7 +411,7 @@ $command->setInputStream(new FileInputStream('input.txt')); $command->setOutputStream(new FileOutputStream('output.txt')); ``` -**[πŸ“– View Streams Example](https://github.com/WebFiori/cli/tree/main/examples/04-custom-streams)** +**[πŸ“– View Streams Example](https://github.com/WebFiori/cli/tree/main/examples/08-file-processing)** ### ANSI Colors and Formatting @@ -427,7 +427,7 @@ public function exec(): int { } ``` -**[πŸ“– View Formatting Example](https://github.com/WebFiori/cli/tree/main/examples/07-ansi-formatting)** +**[πŸ“– View Formatting Example](https://github.com/WebFiori/cli/tree/main/examples/04-output-formatting)** ### Progress Bars @@ -449,7 +449,7 @@ public function exec(): int { } ``` -**[πŸ“– View Progress Bar Example](https://github.com/WebFiori/cli/tree/main/examples/05-progress-bars)** +**[πŸ“– View Progress Bar Example](https://github.com/WebFiori/cli/tree/main/examples/07-progress-bars)** ### Table Display @@ -458,8 +458,8 @@ Display data in formatted tables: ```php public function exec(): int { $data = [ - ['John Doe', 30, 'New York'], - ['Jane Smith', 25, 'Los Angeles'] + ['Ahmed Hassan', 30, 'Cairo'], + ['Sarah Johnson', 25, 'Los Angeles'] ]; $headers = ['Name', 'Age', 'City']; @@ -593,34 +593,33 @@ class HelloCommandTest extends CommandTestCase { ``` -**[πŸ“– View Testing Examples](https://github.com/WebFiori/cli/tree/main/examples/tests)** +**[πŸ“– View Testing Examples](https://github.com/WebFiori/cli/tree/main/examples/10-multi-command-app)** ## Examples Explore comprehensive examples to learn different aspects of WebFiori CLI: ### Basic Examples -- **[πŸ“ Basic Command](https://github.com/WebFiori/cli/tree/main/examples/01-basic-command)** - Create your first CLI command -- **[πŸ“ Command with Arguments](https://github.com/WebFiori/cli/tree/main/examples/02-command-with-args)** - Handle command-line arguments -- **[πŸ“ Interactive Mode](https://github.com/WebFiori/cli/tree/main/examples/03-interactive-mode)** - Build interactive CLI applications +- **[πŸ“ Basic Command](https://github.com/WebFiori/cli/tree/main/examples/01-basic-hello-world)** - Create your first CLI command +- **[πŸ“ Command with Arguments](https://github.com/WebFiori/cli/tree/main/examples/02-arguments-and-options)** - Handle command-line arguments +- **[πŸ“ User Input](https://github.com/WebFiori/cli/tree/main/examples/03-user-input)** - Read and validate user input +- **[πŸ“ Output Formatting](https://github.com/WebFiori/cli/tree/main/examples/04-output-formatting)** - Colors and text formatting ### Advanced Examples -- **[πŸ“ Custom Streams](https://github.com/WebFiori/cli/tree/main/examples/04-custom-streams)** - Custom input/output handling -- **[πŸ“ Progress Bars](https://github.com/WebFiori/cli/tree/main/examples/05-progress-bars)** - Visual progress indicators +- **[πŸ“ Interactive Commands](https://github.com/WebFiori/cli/tree/main/examples/05-interactive-commands)** - Build interactive CLI applications - **[πŸ“ Table Display](https://github.com/WebFiori/cli/tree/main/examples/06-table-display)** - Format data in tables -- **[πŸ“ ANSI Formatting](https://github.com/WebFiori/cli/tree/main/examples/07-ansi-formatting)** - Colors and text formatting +- **[πŸ“ Progress Bars](https://github.com/WebFiori/cli/tree/main/examples/07-progress-bars)** - Visual progress indicators - **[πŸ“ File Processing](https://github.com/WebFiori/cli/tree/main/examples/08-file-processing)** - File manipulation commands - **[πŸ“ Database Operations](https://github.com/WebFiori/cli/tree/main/examples/09-database-ops)** - Database CLI commands ### Complete Applications - **[πŸ“ Multi-Command Application](https://github.com/WebFiori/cli/tree/main/examples/10-multi-command-app)** - Full-featured CLI application -- **[πŸ“ Testing Suite](https://github.com/WebFiori/cli/tree/main/examples/tests)** - Unit testing examples ### Quick Links - **[πŸ“– All Examples](https://github.com/WebFiori/cli/tree/main/examples)** - Browse all available examples -- **[πŸ§ͺ Test Examples](https://github.com/WebFiori/cli/tree/main/examples/tests/HelloCommandTest.php)** - See how to test your commands -- **[πŸš€ Sample App](https://github.com/WebFiori/cli/tree/main/examples/10-multi-command-app/app.php)** - Ready-to-run sample application +- **[πŸš€ Sample App](https://github.com/WebFiori/cli/tree/main/examples/10-multi-command-app/main.php)** - Ready-to-run sample application + --- -**Ready to build amazing CLI applications? Start with the [πŸ“ Basic Command Example](https://github.com/WebFiori/cli/tree/main/examples/01-basic-command) and work your way up!** +**Ready to build amazing CLI applications? Start with the [πŸ“ Basic Command Example](https://github.com/WebFiori/cli/tree/main/examples/01-basic-hello-world) and work your way up!** diff --git a/examples/03-user-input/SimpleCommand.php b/examples/03-user-input/SimpleCommand.php index bf26df7..79eb5b6 100644 --- a/examples/03-user-input/SimpleCommand.php +++ b/examples/03-user-input/SimpleCommand.php @@ -14,7 +14,7 @@ public function exec(): int { // Simulate collecting data $data = [ - 'name' => 'John Doe', + 'name' => 'Ahmed Hassan', 'email' => 'john@example.com', 'age' => 30, 'country' => 'Canada', diff --git a/examples/04-output-formatting/FormattingDemoCommand.php b/examples/04-output-formatting/FormattingDemoCommand.php index 45eab7e..ec24911 100644 --- a/examples/04-output-formatting/FormattingDemoCommand.php +++ b/examples/04-output-formatting/FormattingDemoCommand.php @@ -216,9 +216,9 @@ private function createLists(): void { private function createSimpleTable(): void { $headers = ['Name', 'Age', 'City']; $rows = [ - ['John Doe', '30', 'New York'], - ['Jane Smith', '25', 'Los Angeles'], - ['Bob Johnson', '35', 'Chicago'] + ['Ahmed Hassan', '30', 'Cairo'], + ['Sarah Johnson', '25', 'Los Angeles'], + ['Omar Al-Rashid', '35', 'Dubai'] ]; // Header @@ -263,7 +263,7 @@ private function createStyledTable(): void { $this->println(); $data = [ - ['Alice Brown', '28', 'Engineering'], + ['Fatima Al-Zahra', '28', 'Engineering'], ['Charlie Davis', '32', 'Marketing'], ['Diana Wilson', '29', 'Design'] ]; diff --git a/examples/06-table-display/TableDemoCommand.php b/examples/06-table-display/TableDemoCommand.php index 980b1a0..8c6a4d6 100644 --- a/examples/06-table-display/TableDemoCommand.php +++ b/examples/06-table-display/TableDemoCommand.php @@ -177,9 +177,9 @@ private function demoDataExport(string $style, string $theme, int $width): void $this->println('---------------------------'); $exportData = [ - ['1', 'John Doe', 'john@example.com', 'Active'], - ['2', 'Jane Smith', 'jane@example.com', 'Inactive'], - ['3', 'Bob Johnson', 'bob@example.com', 'Active'] + ['1', 'Ahmed Hassan', 'ahmed.hassan@example.com', 'Active'], + ['2', 'Sarah Johnson', 'sarah.johnson@example.com', 'Inactive'], + ['3', 'Omar Al-Rashid', 'omar.alrashid@example.com', 'Active'] ]; $table = TableBuilder::create() @@ -372,11 +372,11 @@ private function demoUserManagement(string $style, string $theme, int $width): v $this->println('-------------------------'); $users = [ - ['1', 'John Doe', 'john.doe@example.com', 'Active', '2024-01-15', 'Admin', '$1,250.75'], - ['2', 'Jane Smith', 'jane.smith@example.com', 'Inactive', '2024-01-16', 'User', '$890.50'], - ['3', 'Bob Johnson', 'bob.johnson@example.com', 'Active', '2024-01-17', 'Manager', '$2,100.00'], - ['4', 'Alice Brown', 'alice.brown@example.com', 'Pending', '2024-01-18', 'User', '$750.25'], - ['5', 'Charlie Davis', 'charlie.davis@example.com', 'Active', '2024-01-19', 'Admin', '$1,800.80'] + ['1', 'Ahmed Hassan', 'ahmed.hassan@example.com', 'Active', '2024-01-15', 'Admin', '$1,250.75'], + ['2', 'Sarah Johnson', 'sarah.johnson@example.com', 'Inactive', '2024-01-16', 'User', '$890.50'], + ['3', 'Omar Al-Rashid', 'omar.alrashid@example.com', 'Active', '2024-01-17', 'Manager', '$2,100.00'], + ['4', 'Fatima Al-Zahra', 'fatima.alzahra@example.com', 'Pending', '2024-01-18', 'User', '$750.25'], + ['5', 'Michael Davis', 'michael.davis@example.com', 'Active', '2024-01-19', 'Admin', '$1,800.80'] ]; $table = TableBuilder::create() diff --git a/examples/06-table-display/simple-example.php b/examples/06-table-display/simple-example.php index 46cd63d..4a0316b 100644 --- a/examples/06-table-display/simple-example.php +++ b/examples/06-table-display/simple-example.php @@ -27,9 +27,9 @@ $basicTable = TableBuilder::create() ->setHeaders(['Name', 'Age', 'City']) - ->addRow(['John Doe', 30, 'New York']) - ->addRow(['Jane Smith', 25, 'Los Angeles']) - ->addRow(['Bob Johnson', 35, 'Chicago']); + ->addRow(['Ahmed Hassan', 30, 'Cairo']) + ->addRow(['Sarah Johnson', 25, 'Los Angeles']) + ->addRow(['Omar Al-Rashid', 35, 'Dubai']); echo $basicTable->render()."\n\n"; diff --git a/examples/09-database-ops/main.php b/examples/09-database-ops/main.php index 74aa496..0432552 100644 --- a/examples/09-database-ops/main.php +++ b/examples/09-database-ops/main.php @@ -135,9 +135,9 @@ private function seedDatabase(): int { // Insert sample users $users = [ - ['John Doe', 'john@example.com'], - ['Jane Smith', 'jane@example.com'], - ['Bob Johnson', 'bob@example.com'] + ['Ahmed Hassan', 'ahmed.hassan@example.com'], + ['Sarah Johnson', 'sarah.johnson@example.com'], + ['Omar Al-Rashid', 'omar.alrashid@example.com'] ]; foreach ($users as $user) { @@ -150,9 +150,9 @@ private function seedDatabase(): int { // Insert sample posts $posts = [ [1, 'First Post', 'This is the content of the first post.'], - [1, 'Second Post', 'This is another post by John.'], - [2, 'Jane\'s Post', 'Hello from Jane!'], - [3, 'Bob\'s Thoughts', 'Some thoughts from Bob.'] + [1, 'Second Post', 'This is another post by Ahmed.'], + [2, 'Sarah\'s Post', 'Hello from Sarah!'], + [3, 'Omar\'s Thoughts', 'Some thoughts from Omar.'] ]; foreach ($posts as $post) { diff --git a/examples/09-database-ops/seeds/users.json b/examples/09-database-ops/seeds/users.json index f76be0e..441bcef 100644 --- a/examples/09-database-ops/seeds/users.json +++ b/examples/09-database-ops/seeds/users.json @@ -1,31 +1,31 @@ [ { - "name": "John Doe", - "email": "john.doe@example.com", + "name": "Ahmed Hassan", + "email": "ahmed.hassan@example.com", "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", "status": "active" }, { - "name": "Jane Smith", - "email": "jane.smith@example.com", + "name": "Sarah Johnson", + "email": "sarah.johnson@example.com", "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", "status": "active" }, { - "name": "Bob Johnson", - "email": "bob.johnson@example.com", + "name": "Omar Al-Rashid", + "email": "omar.alrashid@example.com", "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", "status": "inactive" }, { - "name": "Alice Brown", - "email": "alice.brown@example.com", + "name": "Fatima Al-Zahra", + "email": "fatima.alzahra@example.com", "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", "status": "active" }, { - "name": "Charlie Wilson", - "email": "charlie.wilson@example.com", + "name": "Michael Davis", + "email": "michael.davis@example.com", "password": "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", "status": "active" } diff --git a/examples/10-multi-command-app/commands/UserCommand.php b/examples/10-multi-command-app/commands/UserCommand.php index 754ab10..1a3ec37 100644 --- a/examples/10-multi-command-app/commands/UserCommand.php +++ b/examples/10-multi-command-app/commands/UserCommand.php @@ -497,10 +497,10 @@ private function showUsage(): int { $this->println(); $this->println('Examples:'); $this->println(' php main.php user --action=list'); - $this->println(' php main.php user --action=create --name="John Doe" --email="john@example.com"'); - $this->println(' php main.php user --action=update --id=1 --name="Jane Doe"'); + $this->println(' php main.php user --action=create --name="Ahmed Hassan" --email="ahmed.hassan@example.com"'); + $this->println(' php main.php user --action=update --id=1 --name="Sarah Johnson"'); $this->println(' php main.php user --action=delete --id=1'); - $this->println(' php main.php user --action=search --search="john"'); + $this->println(' php main.php user --action=search --search="ahmed"'); $this->println(' php main.php user --action=export --format=json'); return 0; diff --git a/examples/10-multi-command-app/data/users.json b/examples/10-multi-command-app/data/users.json index 1cbfe00..12ec73c 100644 --- a/examples/10-multi-command-app/data/users.json +++ b/examples/10-multi-command-app/data/users.json @@ -1,24 +1,24 @@ [ { "id": 1, - "name": "John Doe", - "email": "john.doe@example.com", + "name": "Ahmed Hassan", + "email": "ahmed.hassan@example.com", "status": "active", "created_at": "2024-01-15 10:30:00", "updated_at": "2024-01-15 10:30:00" }, { "id": 2, - "name": "Jane Smith", - "email": "jane.smith@example.com", + "name": "Sarah Johnson", + "email": "sarah.johnson@example.com", "status": "active", "created_at": "2024-01-16 14:20:00", "updated_at": "2024-01-16 14:20:00" }, { "id": 3, - "name": "Bob Johnson", - "email": "bob.johnson@example.com", + "name": "Omar Al-Rashid", + "email": "omar.alrashid@example.com", "status": "inactive", "created_at": "2024-01-17 09:15:00", "updated_at": "2024-01-17 09:15:00"