diff --git a/.gitignore b/.gitignore index f45219c..dcec61b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /vendor/ -/.idea \ No newline at end of file +/.idea +composer.lock \ No newline at end of file diff --git a/README.md b/README.md index cc2194d..988454b 100644 --- a/README.md +++ b/README.md @@ -434,6 +434,391 @@ class UserReportCommand implements CommandInterface usleep(500000); } + // Final result + if ($export) { + $console->success("Report exported to: $export"); +```php +use PhpDevCommunity\Console\Argument\CommandArgument; + +// Using the constructor +new CommandArgument( + 'recipient', // The name of the argument + true, // The argument is required + null, // No default value + 'The email address of the recipient' // Description +); + +// Using static methods (Recommended) +CommandArgument::required('recipient', 'The email address of the recipient'); +CommandArgument::optional('recipient', null, 'The email address of the recipient'); +``` + +If a required argument is not provided, an exception is thrown. + +--- + +### 2 Options + +An **option** is a named parameter, often prefixed with a double dash (`--`) or a shortcut (`-`). For example, in the following command: + +```bash +bin/console send-email recipient@example.com --subject "Meeting Reminder" +``` + +`--subject` is an option. Options are defined using the `CommandOption` class. Here are the main properties of an option: + +##### Example of defining an option: + +```php +use PhpDevCommunity\Console\Option\CommandOption; + +new CommandOption( + 'subject', // The name of the option + 's', // Shortcut + 'The subject of the email', // Description + false // Not a flag, expects a value +); +``` + +An option with a flag does not accept a value; its mere presence indicates that it is enabled. + +--- + +### 3 Usage in a Command + +In a command, arguments and options are defined by overriding the `getArguments()` and `getOptions()` methods from the `CommandInterface`. + +##### Example: + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; +use PhpDevCommunity\Console\Option\CommandOption; + +public function getArguments(): array +{ + return [ + new CommandArgument('recipient', true, null, 'The email address of the recipient'), + ]; +} + +public function getOptions(): array +{ + return [ + new CommandOption('subject', 's', 'The subject of the email', false), + ]; +} +``` + +In this example: +- `recipient` is a required argument. +- `--subject` (or `-s`) is an option that expects a value. + +> [!NOTE] +> **Global Options**: The options `--help` (`-h`) and `--verbose` (`-v`) are **globally available** for all commands. You **must not** define them manually in your commands, as they are automatically handled by the application. + +--- + +### 4 Validation and Management + +Arguments and options are automatically validated when the command is executed. For instance, if a required argument is missing or an attempt is made to access an undefined option, an exception will be thrown. + +The `InputInterface` allows you to retrieve these parameters in the `execute` method: +- Arguments: `$input->getArgumentValue('recipient')` +- Options: `$input->getOptionValue('subject')` or `$input->hasOption('verbose')` + +This ensures clear and consistent management of the parameters passed within your PHP project. + +## Handling Different Output Types + +Output management provides clear and useful information during command execution. Below is a practical example demonstrating output functionalities. + +### Example: Command `UserReportCommand` + +This command generates a report for a specific user and uses various output features. + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; +use PhpDevCommunity\Console\Command\CommandInterface; +use PhpDevCommunity\Console\InputInterface; +use PhpDevCommunity\Console\Option\CommandOption; +use PhpDevCommunity\Console\Output\ConsoleOutput; +use PhpDevCommunity\Console\OutputInterface; + +class UserReportCommand implements CommandInterface +{ + public function getName(): string + { + return 'user:report'; + } + + public function getDescription(): string + { + return 'Generates a detailed report for a specific user.'; + } + + public function getArguments(): array + { + return [ + new CommandArgument('user_id', true, null, 'The ID of the user to generate the report for'), + ]; + } + + public function getOptions(): array + { + return [ + new CommandOption('export', 'e', 'Export the report to a file', false), + ]; + } + + public function execute(InputInterface $input, OutputInterface $output): void + { + $console = new ConsoleOutput($output); + + // Main title + $console->title('User Report Generation'); + + // Arguments and options + $userId = $input->getArgumentValue('user_id'); + $verbose = $input->hasOption('verbose'); // Available globally + $export = $input->hasOption('export') ? $input->getOptionValue('export') : null; + + $console->info("Generating report for User ID: $userId"); + + // Simulating user data retrieval + $console->spinner(); + $userData = [ + 'name' => 'John Doe', + 'email' => 'john.doe@example.com', + 'active' => true, + 'roles' => ['admin', 'user'] + ]; + + if ($verbose) { + $console->debug('User data retrieved successfully.'); + } + + // Displaying user data + $console->json($userData); + + // Displaying user roles as a list + $console->listKeyValues([ + 'Name' => $userData['name'], + 'Email' => $userData['email'], + 'Active' => $userData['active'] ? 'Yes' : 'No', + ]); + $console->list($userData['roles']); + + // Table of recent activities + $headers = ['ID', 'Activity', 'Timestamp']; + $rows = [ + ['1', 'Login', '2024-12-22 12:00:00'], + ['2', 'Update Profile', '2024-12-22 12:30:00'], + ]; + $console->table($headers, $rows); + + // Progress bar + for ($i = 0; $i <= 100; $i += 20) { + $console->progressBar(100, $i); + usleep(500000); + } + + // Final result + if ($export) { + $console->success("Report exported to: $export"); +```php +use PhpDevCommunity\Console\Argument\CommandArgument; + +// Using the constructor +new CommandArgument( + 'recipient', // The name of the argument + true, // The argument is required + null, // No default value + 'The email address of the recipient' // Description +); + +// Using static methods (Recommended) +CommandArgument::required('recipient', 'The email address of the recipient'); +CommandArgument::optional('recipient', null, 'The email address of the recipient'); +``` + +If a required argument is not provided, an exception is thrown. + +--- + +### 2 Options + +An **option** is a named parameter, often prefixed with a double dash (`--`) or a shortcut (`-`). For example, in the following command: + +```bash +bin/console send-email recipient@example.com --subject "Meeting Reminder" +``` + +`--subject` is an option. Options are defined using the `CommandOption` class. Here are the main properties of an option: + +- **Name (`name`)**: The full name of the option, used with `--`. +- **Shortcut (`shortcut`)**: A short alias, used with a single dash (`-`). +- **Description (`description`)**: A brief description of the option, useful for help messages. +- **Flag (`isFlag`)**: Indicates whether the option is a simple flag (present or absent) or if it accepts a value. + +##### Example of defining an option: + +```php +use PhpDevCommunity\Console\Option\CommandOption; + +// Using the constructor +new CommandOption( + 'subject', // The name of the option + 's', // Shortcut + 'The subject of the email', // Description + false // Not a flag, expects a value +); + +// Using static methods (Recommended) +CommandOption::withValue('subject', 's', 'The subject of the email'); +``` + +An option with a flag does not accept a value; its mere presence indicates that it is enabled. + +--- + +### 3 Usage in a Command + +In a command, arguments and options are defined by overriding the `getArguments()` and `getOptions()` methods from the `CommandInterface`. + +##### Example: + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; +use PhpDevCommunity\Console\Option\CommandOption; + +public function getArguments(): array +{ + return [ + CommandArgument::required('recipient', 'The email address of the recipient'), + ]; +} + +public function getOptions(): array +{ + return [ + CommandOption::withValue('subject', 's', 'The subject of the email'), + ]; +} +``` + +In this example: +- `recipient` is a required argument. +- `--subject` (or `-s`) is an option that expects a value. + +> [!NOTE] +> **Global Options**: The options `--help` (`-h`) and `--verbose` (`-v`) are **globally available** for all commands. You **must not** define them manually in your commands, as they are automatically handled by the application. + +--- + +### 4 Validation and Management + +Arguments and options are automatically validated when the command is executed. For instance, if a required argument is missing, an exception will be thrown. + +The `InputInterface` allows you to retrieve these parameters in the `execute` method: +- Arguments: `$input->getArgumentValue('recipient')` (Throws exception if missing and required) +- Options: `$input->getOptionValue('subject')` (Returns `null` if not present) or `$input->hasOption('verbose')` + +This ensures clear and consistent management of the parameters passed within your PHP project. + +## Handling Different Output Types + +Output management provides clear and useful information during command execution. Below is a practical example demonstrating output functionalities. + +### Example: Command `UserReportCommand` + +This command generates a report for a specific user and uses various output features. + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; +use PhpDevCommunity\Console\Command\CommandInterface; +use PhpDevCommunity\Console\InputInterface; +use PhpDevCommunity\Console\Option\CommandOption; +use PhpDevCommunity\Console\Output\ConsoleOutput; +use PhpDevCommunity\Console\OutputInterface; + +class UserReportCommand implements CommandInterface +{ + public function getName(): string + { + return 'user:report'; + } + + public function getDescription(): string + { + return 'Generates a detailed report for a specific user.'; + } + + public function getArguments(): array + { + return [ + CommandArgument::required('user_id', 'The ID of the user to generate the report for'), + ]; + } + + public function getOptions(): array + { + return [ + CommandOption::withValue('export', 'e', 'Export the report to a file'), + ]; + } + + public function execute(InputInterface $input, OutputInterface $output): void + { + $console = new ConsoleOutput($output); + + // Main title + $console->title('User Report Generation'); + + // Arguments and options + $userId = $input->getArgumentValue('user_id'); + $verbose = $input->hasOption('verbose'); // Available globally + $export = $input->getOptionValue('export'); // Returns null if not set + + $console->info("Generating report for User ID: $userId"); + + // Simulating user data retrieval + $console->spinner(); + $userData = [ + 'name' => 'John Doe', + 'email' => 'john.doe@example.com', + 'active' => true, + 'roles' => ['admin', 'user'] + ]; + + if ($verbose) { + $console->debug('User data retrieved successfully.'); + } + + // Displaying user data + $console->json($userData); + + // Displaying user roles as a list + $console->listKeyValues([ + 'Name' => $userData['name'], + 'Email' => $userData['email'], + 'Active' => $userData['active'] ? 'Yes' : 'No', + ]); + $console->list($userData['roles']); + + // Table of recent activities + $headers = ['ID', 'Activity', 'Timestamp']; + $rows = [ + ['1', 'Login', '2024-12-22 12:00:00'], + ['2', 'Update Profile', '2024-12-22 12:30:00'], + ]; + $console->table($headers, $rows); + + // Progress bar + for ($i = 0; $i <= 100; $i += 20) { + $console->progressBar(100, $i); + usleep(500000); + } + // Final result if ($export) { $console->success("Report exported to: $export"); @@ -453,25 +838,408 @@ class UserReportCommand implements CommandInterface #### Features Used -1. **Rich Messages**: - - `success($message)`: Displays a success message. - - `warning($message)`: Displays a warning message. - - `error($message)`: Displays a critical error message. - - `info($message)`: Displays an informational message. - - `title($title)`: Displays a main title. +1. **Rich Messages**: + * `success($message)`: Displays a success message. + * `warning($message)`: Displays a warning message. + * `error($message)`: Displays a critical error message. + * `info($message)`: Displays an informational message. + * `debug($message)`: Displays a debug message (only visible with `-v`). + * `title($title)`: Displays a main title. + +2. **Structured Output**: + * `json($data)`: Displays data in JSON format. + * `list($items)`: Displays a simple list. + * `listKeyValues($data)`: Displays key-value pairs. + * `table($headers, $rows)`: Displays tabular data. + +3. **Progression and Interactivity**: + * `progressBar($total, $current)`: Displays a progress bar. + * `spinner()`: Displays a loading spinner. + * `confirm($question)`: Prompts for user confirmation. + +### Verbosity and Error Handling + +- **Global Verbosity**: The `-v` or `--verbose` flag is **globally available** for all commands. You do not need to define it. Passing it will enable `debug()` messages. +- **Error Handling**: The `error()` method writes messages to `STDERR`, allowing you to separate error output from standard output (useful for piping). + +--- + +# Documentation en Français + +Une bibliothèque PHP légère conçue pour simplifier la gestion des commandes dans les applications console. Cette bibliothèque est sans dépendance et se concentre sur une solution rationalisée et efficace pour créer des outils CLI en PHP. + +## Installation + +Vous pouvez installer cette bibliothèque via [Composer](https://getcomposer.org/). Assurez-vous que votre projet respecte la version minimale de PHP requise (7.4). + +```bash +composer require phpdevcommunity/php-console +``` + +## Prérequis + +- Version PHP 7.4 ou supérieure + +## Table des Matières + +1. [Configuration dans une Application PHP](#configuration-dans-une-application-php) +2. [Créer une Commande](#créer-une-commande) +3. [Définir des Arguments et des Options](#définir-des-arguments-et-des-options) +4. [Gérer les Différents Types de Sortie](#gérer-les-différents-types-de-sortie) + +--- + +## Configuration dans une Application PHP + +Pour utiliser cette bibliothèque dans n'importe quelle application PHP (Symfony, Laravel, Slim ou autres), créez d'abord un répertoire `bin` dans votre projet. Ensuite, ajoutez un fichier de script, par exemple `bin/console`, avec le contenu suivant : + +```php +#!/usr/bin/php +boot(); +// $container = $kernel->getContainer(); +// $app = $container->get(CommandRunner::class); + + +$app = new CommandRunner([]); +$exitCode = $app->run(new CommandParser(), new Output()); +exit($exitCode); +``` + +Par convention, le fichier est nommé `bin/console`, mais vous pouvez choisir le nom que vous préférez. Ce script sert de point d'entrée principal pour vos commandes CLI. Assurez-vous que le fichier est exécutable en lançant la commande suivante : + +```bash +chmod +x bin/console +``` + +## Créer une Commande + +Pour ajouter une commande à votre application, vous devez créer une classe qui implémente l'interface `CommandInterface`. Voici un exemple d'implémentation pour une commande appelée `send-email` : + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; +use PhpDevCommunity\Console\Command\CommandInterface; +use PhpDevCommunity\Console\InputInterface; +use PhpDevCommunity\Console\Option\CommandOption; +use PhpDevCommunity\Console\OutputInterface; + +class SendEmailCommand implements CommandInterface +{ + public function getName(): string + { + return 'send-email'; + } + + public function getDescription(): string + { + return 'Envoie un email au destinataire spécifié avec un sujet optionnel.'; + } + + public function getOptions(): array + { + return [ + CommandOption::withValue('subject', 's', "Le sujet de l'email"), + ]; + } + + public function getArguments(): array + { + return [ + CommandArgument::required('recipient', "L'adresse email du destinataire"), + ]; + } + + public function execute(InputInterface $input, OutputInterface $output): void + { + // Valider et récupérer l'email du destinataire + if (!$input->hasArgument('recipient')) { + $output->writeln("Erreur : L'email du destinataire est requis."); + return; + } + $recipient = $input->getArgumentValue('recipient'); + + // Valider le format de l'email + if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) { + $output->writeln("Erreur : L'adresse email fournie n'est pas valide."); + return; + } + + // Récupérer l'option sujet (si fournie) + $subject = $input->getOptionValue('subject') ?? 'Pas de sujet'; + + // Simuler l'envoi de l'email + $output->writeln("Envoi de l'email..."); + $output->writeln('Destinataire : ' . $recipient); + $output->writeln('Sujet : ' . $subject); + $output->writeln('Email envoyé avec succès !'); + } +} +``` + +### Enregistrer la Commande dans `CommandRunner` + +Après avoir créé votre commande, vous devez l'enregistrer dans le `CommandRunner` pour qu'elle puisse être exécutée. Voici un exemple : + +```php +use PhpDevCommunity\Console\CommandRunner; + +$app = new CommandRunner([ + new SendEmailCommand() +]); +``` + +Le `CommandRunner` prend un tableau de commandes en paramètre. Chaque commande doit être une instance d'une classe implémentant `CommandInterface`. Une fois enregistrée, la commande peut être appelée depuis la console. + +### Exemple d'Utilisation dans le Terminal + +1. **Commande sans option sujet :** + + ```bash + bin/console send-email john.doe@example.com + ``` + + **Sortie :** + ``` + Envoi de l'email... + Destinataire : john.doe@example.com + Sujet : Pas de sujet + Email envoyé avec succès ! + ``` + +2. **Commande avec option sujet :** + + ```bash + bin/console send-email john.doe@example.com --subject "Rappel de Réunion" + ``` + + **Sortie :** + ``` + Envoi de l'email... + Destinataire : john.doe@example.com + Sujet : Rappel de Réunion + Email envoyé avec succès ! + ``` + +3. **Commande avec format d'email invalide :** + + ```bash + bin/console send-email invalid-email + ``` + + **Sortie :** + ``` + Erreur : L'adresse email fournie n'est pas valide. + ``` + +## Définir des Arguments et des Options + +Les arguments et les options permettent aux développeurs de personnaliser le comportement d'une commande en fonction des paramètres passés. Ces concepts sont gérés respectivement par les classes `CommandArgument` et `CommandOption`. + +--- + +### 1 Arguments + +Un **argument** est un paramètre positionnel passé à une commande. Par exemple : + +```bash +bin/console send-email recipient@example.com +``` + +`recipient@example.com` est un argument. Les arguments sont définis via la classe `CommandArgument`. Voici les propriétés principales : + +- **Nom (`name`)** : Le nom unique de l'argument. +- **Requis (`isRequired`)** : Indique si l'argument est obligatoire. +- **Valeur par défaut (`defaultValue`)** : La valeur utilisée si aucun argument n'est fourni. +- **Description (`description`)** : Une brève description de l'argument. + +##### Exemple de définition d'un argument : + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; + +// Via le constructeur +new CommandArgument( + 'recipient', // Le nom de l'argument + true, // L'argument est requis + null, // Pas de valeur par défaut + "L'adresse email du destinataire" // Description +); + +// Via les méthodes statiques (Recommandé) +CommandArgument::required('recipient', "L'adresse email du destinataire"); +CommandArgument::optional('recipient', null, "L'adresse email du destinataire"); +``` + +--- + +### 2 Options + +Une **option** est un paramètre nommé, souvent préfixé par un double tiret (`--`) ou un raccourci (`-`). Par exemple : + +```bash +bin/console send-email recipient@example.com --subject "Rappel de Réunion" +``` + +`--subject` est une option. Les options sont définies via la classe `CommandOption`. Voici les propriétés principales : + +- **Nom (`name`)** : Le nom complet de l'option. +- **Raccourci (`shortcut`)** : Un alias court. +- **Description (`description`)** : Une brève description. +- **Drapeau (`isFlag`)** : Indique si l'option est un simple drapeau (présent ou absent) ou si elle attend une valeur. + +##### Exemple de définition d'une option : + +```php +use PhpDevCommunity\Console\Option\CommandOption; + +// Via le constructeur +new CommandOption( + 'subject', // Le nom de l'option + 's', // Raccourci + "Le sujet de l'email", // Description + false // Ce n'est pas un drapeau, attend une valeur +); + +// Via les méthodes statiques (Recommandé) +CommandOption::withValue('subject', 's', "Le sujet de l'email"); +``` + +Une option avec un drapeau n'accepte pas de valeur ; sa simple présence indique qu'elle est activée. + +--- + +### 3 Utilisation dans une Commande + +Dans une commande, les arguments et options sont définis en surchargeant les méthodes `getArguments()` et `getOptions()` de l'interface `CommandInterface`. + +##### Exemple : + +```php +public function getArguments(): array +{ + return [ + CommandArgument::required('recipient', "L'adresse email du destinataire"), + ]; +} + +public function getOptions(): array +{ + return [ + CommandOption::withValue('subject', 's', "Le sujet de l'email"), + ]; +} +``` + +Dans cet exemple : +- `recipient` est un argument requis. +- `--subject` (ou `-s`) est une option qui attend une valeur. + +> [!NOTE] +> **Options Globales** : Les options `--help` (`-h`) et `--verbose` (`-v`) sont **disponibles globalement** pour toutes les commandes. Vous **ne devez pas** les définir manuellement dans vos commandes, car elles sont gérées automatiquement par l'application. + +--- + +### 4 Validation et Gestion + +Les arguments et options sont automatiquement validés lors de l'exécution de la commande. L'`InputInterface` permet de récupérer ces paramètres dans la méthode `execute` : +- Arguments : `$input->getArgumentValue('recipient')` (Lève une exception si manquant et requis) +- Options : `$input->getOptionValue('subject')` (Retourne `null` si absent) ou `$input->hasOption('verbose')` + +## Gérer les Différents Types de Sortie + +La gestion de la sortie fournit des informations claires et utiles pendant l'exécution de la commande. + +### Exemple : Commande `UserReportCommand` + +```php +use PhpDevCommunity\Console\Argument\CommandArgument; +use PhpDevCommunity\Console\Command\CommandInterface; +use PhpDevCommunity\Console\InputInterface; +use PhpDevCommunity\Console\Option\CommandOption; +use PhpDevCommunity\Console\Output\ConsoleOutput; +use PhpDevCommunity\Console\OutputInterface; + +class UserReportCommand implements CommandInterface +{ + // ... (méthodes getName, getDescription, getArguments, getOptions comme ci-dessus) + + public function execute(InputInterface $input, OutputInterface $output): void + { + $console = new ConsoleOutput($output); + + // Titre principal + $console->title('Génération du Rapport Utilisateur'); + + $userId = $input->getArgumentValue('user_id'); + $verbose = $input->hasOption('verbose'); // Disponible globalement + $export = $input->getOptionValue('export'); // Retourne null si non défini + + $console->info("Génération du rapport pour l'ID Utilisateur : $userId"); + + // Spinner + $console->spinner(); + + if ($verbose) { + $console->debug('Données utilisateur récupérées avec succès.'); + } + + // Affichage des données + $console->success('Rapport généré avec succès !'); + } +} +``` + +#### Fonctionnalités Utilisées + +1. **Messages Riches** : + * `success($message)` : Affiche un message de succès. + * `warning($message)` : Affiche un message d'avertissement. + * `error($message)` : Affiche un message d'erreur critique (sur STDERR). + * `info($message)` : Affiche un message d'information. + * `debug($message)` : Affiche un message de debug (visible uniquement avec `-v`). + * `title($title)` : Affiche un titre principal. + +2. **Sortie Structurée** : + * `json($data)` : Affiche des données au format JSON. + * `list($items)` : Affiche une liste simple. + * `listKeyValues($data)` : Affiche des paires clé-valeur. + * `table($headers, $rows)` : Affiche des données tabulaires. + +3. **Progression et Interactivité** : + * `progressBar($total, $current)` : Affiche une barre de progression. + * `spinner()` : Affiche un spinner de chargement. + * `confirm($question)` : Demande une confirmation à l'utilisateur. -2. **Structured Output**: - - `json($data)`: Displays data in JSON format. - - `list($items)`: Displays a simple list. - - `listKeyValues($data)`: Displays key-value pairs. - - `table($headers, $rows)`: Displays tabular data. +### Verbosité et Gestion des Erreurs -3. **Progression and Interactivity**: - - `progressBar($total, $current)`: Displays a progress bar. - - `spinner()`: Displays a loading spinner. - - `confirm($question)`: Prompts for user confirmation. +- **Verbosité Globale** : Le drapeau `-v` ou `--verbose` est **disponible globalement** pour toutes les commandes. Vous n'avez pas besoin de le définir. L'utiliser activera les messages `debug()`.(This line is already `debug`, so no change needed here, but I'll double check the context). +- **Gestion des Erreurs** : La méthode `error()` écrit les messages sur `STDERR`, ce qui permet de séparer la sortie d'erreur de la sortie standard (utile pour les pipes). --- -## License +## Licence -This library is open-source software licensed under the [MIT license](LICENSE). \ No newline at end of file +Cette bibliothèque est un logiciel open-source sous licence [MIT](LICENSE). \ No newline at end of file diff --git a/bin/console b/bin/console deleted file mode 100644 index dc02cf5..0000000 --- a/bin/console +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/php -run(new CommandParser(), new Output()); -exit($exitCode); \ No newline at end of file diff --git a/composer.json b/composer.json index 4560d3a..0e029f1 100644 --- a/composer.json +++ b/composer.json @@ -11,10 +11,11 @@ "require": { "php": ">=7.4", "ext-mbstring": "*", - "ext-json": "*" + "ext-json": "*", + "ext-ctype": "*" }, "require-dev": { - "phpdevcommunity/unitester": "^0.1.0@alpha" + "depo/unitester": "^1.0.0" }, "license": "MIT", "authors": [ @@ -23,4 +24,4 @@ "homepage": "https://www.phpdevcommunity.com" } ] -} +} \ No newline at end of file diff --git a/examples/commands.php b/examples/commands.php index 79b6e33..bd30c48 100755 --- a/examples/commands.php +++ b/examples/commands.php @@ -28,10 +28,10 @@ // $container = $kernel->getContainer(); // $app = $container->get(CommandRunner::class); -$app = new CommandRunner([ +$runner = new CommandRunner([ new FooCommand(), ]); -$exitCode = $app->run(new CommandParser(), new Output()); +$exitCode = $runner->run(new CommandParser(), new Output()); exit($exitCode); diff --git a/src/Argument/CommandArgument.php b/src/Argument/CommandArgument.php index 35dc6e8..c6ca6cf 100755 --- a/src/Argument/CommandArgument.php +++ b/src/Argument/CommandArgument.php @@ -9,9 +9,20 @@ final class CommandArgument private $defaultValue; private ?string $description; - public function __construct(string $name, bool $isRequired = false, $defaultValue = null, ?string $description = null) + public function __construct(string $name, bool $isRequired = false, $defaultValue = null, ?string $description = null) { - $this->name = $name; + if ($name === '') { + throw new \InvalidArgumentException("Option name cannot be empty."); + } + if (!ctype_alpha($name)) { + throw new \InvalidArgumentException("Option name must contain only letters. '$name' is invalid."); + } + + if ($isRequired && $defaultValue !== null) { + throw new \LogicException("Argument '$name' cannot be required and have a default value."); + } + + $this->name = strtolower($name); $this->isRequired = $isRequired; $this->defaultValue = $defaultValue; $this->description = $description; @@ -47,4 +58,13 @@ public function getDescription(): ?string return $this->description; } + public static function required(string $name, ?string $description = null): self + { + return new self($name, true, null, $description); + } + + public static function optional(string $name, $default = null, ?string $description = null): self + { + return new self($name, false, $default, $description); + } } \ No newline at end of file diff --git a/src/Command/HelpCommand.php b/src/Command/HelpCommand.php index 52696d4..592d7d2 100644 --- a/src/Command/HelpCommand.php +++ b/src/Command/HelpCommand.php @@ -5,6 +5,7 @@ use PhpDevCommunity\Console\InputInterface; +use PhpDevCommunity\Console\Option\CommandOption; use PhpDevCommunity\Console\Output; use PhpDevCommunity\Console\OutputInterface; @@ -44,6 +45,22 @@ public function execute(InputInterface $input, OutputInterface $output): void $commands[$command->getName()] = $command->getDescription(); } $io->listKeyValues($commands, true); + + $io->writeColor('Options:', 'yellow'); + $io->write(PHP_EOL); + $options = []; + foreach ([new CommandOption('help', 'h', 'Display this help message.', true), new CommandOption('verbose', 'v', 'Enable verbose output', true)] as $option) { + $name = sprintf('--%s', $option->getName()); + if ($option->getShortcut() !== null) { + $name = sprintf('-%s, --%s', $option->getShortcut(), $option->getName()); + } + + if (!$option->isFlag()) { + $name = sprintf('%s=VALUE', $name); + } + $options[$name] = $option->getDescription(); + } + $io->listKeyValues($options, true); } /** diff --git a/src/CommandParser.php b/src/CommandParser.php index b433230..d04fa6d 100755 --- a/src/CommandParser.php +++ b/src/CommandParser.php @@ -15,7 +15,7 @@ final class CommandParser private array $options = []; private array $arguments = []; - public function __construct(array $argv = null) + public function __construct(?array $argv = null) { $argv = $argv ?? $_SERVER['argv'] ?? []; array_shift($argv); diff --git a/src/CommandRunner.php b/src/CommandRunner.php index a58c6d1..989f639 100644 --- a/src/CommandRunner.php +++ b/src/CommandRunner.php @@ -5,6 +5,7 @@ use InvalidArgumentException; use PhpDevCommunity\Console\Command\CommandInterface; use PhpDevCommunity\Console\Command\HelpCommand; +use PhpDevCommunity\Console\Option\CommandOption; use PhpDevCommunity\Console\Output\ConsoleOutput; use Throwable; use const PHP_EOL; @@ -13,16 +14,16 @@ final class CommandRunner { const CLI_ERROR = 1; const CLI_SUCCESS = 0; + public const CLI_COMMAND_NOT_FOUND = 10; // Aucune commande trouvée + public const CLI_INVALID_ARGUMENTS = 11; // Arguments invalides + public const CLI_AMBIGUOUS_COMMAND = 12; // Plusieurs correspondances possibles /** * @var CommandInterface[] */ private array $commands = []; - /** - * @var CommandInterface - */ - private CommandInterface $defaultCommand; + private HelpCommand $defaultCommand; /** * Application constructor. @@ -43,6 +44,10 @@ public function __construct(array $commands) public function run(CommandParser $commandParser, OutputInterface $output): int { + if ($commandParser->hasOption('verbose') || $commandParser->hasOption('v')) { + $output->setVerbose(true); + } + try { if ($commandParser->getCommandName() === null || $commandParser->getCommandName() === '--help') { @@ -50,18 +55,29 @@ public function run(CommandParser $commandParser, OutputInterface $output): int return self::CLI_SUCCESS; } - $command = null; + $commands = []; foreach ($this->commands as $currentCommand) { - if ($currentCommand->getName() === $commandParser->getCommandName()) { - $command = $currentCommand; - break; + if (self::stringStartsWith($currentCommand->getName(), $commandParser->getCommandName())) { + $commands[] = $currentCommand; } } - if ($command === null) { - throw new InvalidArgumentException(sprintf('Command "%s" is not defined.', $commandParser->getCommandName())); + if (empty($commands)) { + throw new InvalidArgumentException(sprintf('Command "%s" is not defined.', $commandParser->getCommandName()), self::CLI_COMMAND_NOT_FOUND); + } + + if (count($commands) > 1) { + $names = []; + foreach ($commands as $command) { + $names[$command->getName()] = $command->getDescription(); + } + $consoleOutput = new ConsoleOutput($output); + $consoleOutput->error(sprintf('Command "%s" is ambiguous.', $commandParser->getCommandName())); + $consoleOutput->listKeyValues($names, true); + return self::CLI_AMBIGUOUS_COMMAND; } + $command = $commands[0]; if ($commandParser->hasOption('help')) { $this->showCommandHelp($command, $output); return self::CLI_SUCCESS; @@ -73,7 +89,7 @@ public function run(CommandParser $commandParser, OutputInterface $output): int } catch (Throwable $e) { (new ConsoleOutput($output))->error($e->getMessage()); - return self::CLI_ERROR; + return in_array($e->getCode(), [self::CLI_COMMAND_NOT_FOUND, self::CLI_INVALID_ARGUMENTS]) ? $e->getCode() : self::CLI_ERROR; } } @@ -81,8 +97,31 @@ public function run(CommandParser $commandParser, OutputInterface $output): int private function execute(CommandInterface $command, CommandParser $commandParser, OutputInterface $output) { $argvOptions = []; - $options = $command->getOptions(); + $forbidden = ['help', 'h', 'verbose', 'v']; + foreach ($options as $option) { + $name = $option->getName(); + $shortcut = $option->getShortcut(); + if (in_array($name, $forbidden, true) || ($shortcut !== null && in_array($shortcut, $forbidden, true))) { + $invalid = in_array($name, $forbidden, true) ? $name : $shortcut; + throw new \InvalidArgumentException( + sprintf( + 'The option "%s" is reserved and cannot be used with the "%s" command.', + $invalid, + $command->getName() + ) + ); + } + } + + $options[] = CommandOption::flag('verbose', 'v', 'Enable verbose output'); + foreach ($options as $option) { + if ($option->isFlag()) { + $argvOptions["--{$option->getName()}"] = false; + }elseif ($option->getDefaultValue() !== null) { + $argvOptions["--{$option->getName()}"] = $option->getDefaultValue(); + } + } foreach ($commandParser->getOptions() as $name => $value) { $hasOption = false; foreach ($options as $option) { @@ -104,12 +143,14 @@ private function execute(CommandInterface $command, CommandParser $commandParser $arguments = $command->getArguments(); foreach ($arguments as $key => $argument) { - $key = strval($key); - if ($argument->isRequired() && empty($commandParser->getArgumentValue($key))) { + $keyArg = $argument->getName(); + if ($argument->isRequired() && (!$commandParser->hasArgument($key) || empty($commandParser->getArgumentValue($key)))) { throw new InvalidArgumentException(sprintf('Argument "%s" is required for command "%s".', $argument->getName(), $command->getName())); } if ($commandParser->hasArgument($key)) { - $argv["--{$argument->getName()}"] = $commandParser->getArgumentValue($key); + $argv["--{$keyArg}"] = $commandParser->getArgumentValue($key); + }else { + $argv["--{$keyArg}"] = $argument->getDefaultValue(); } } @@ -117,7 +158,20 @@ private function execute(CommandInterface $command, CommandParser $commandParser throw new InvalidArgumentException(sprintf('Too many arguments for command "%s". Expected %d, got %d.', $command->getName(), count($arguments), count($commandParser->getArguments()))); } - $command->execute(new Input($commandParser->getCommandName(), $argvOptions, $argv), $output); + $startTime = microtime(true); + $input = new Input($commandParser->getCommandName(), $argvOptions, $argv); + $command->execute($input, $output); + $endTime = microtime(true); + $peakMemoryBytes = memory_get_peak_usage(true); + $peakMemoryMB = round($peakMemoryBytes / 1024 / 1024, 2); + $duration = round($endTime - $startTime, 2); + if ($output->isVerbose()) { + $output->writeln(sprintf( + 'Execution time: %.2fs; Peak memory usage: %.2f MB', + $duration, + $peakMemoryMB + )); + } } private function showCommandHelp(CommandInterface $selectedCommand, OutputInterface $output): void @@ -148,8 +202,27 @@ private function showCommandHelp(CommandInterface $selectedCommand, OutputInterf if (!$option->isFlag()) { $name = sprintf('%s=VALUE', $name); } + if ($option->getDefaultValue() !== null) { + $name = sprintf('%s (default: %s)', $name, $option->getDefaultValue()); + } + $options[$name] = $option->getDescription(); } $consoleOutput->listKeyValues($options, true); } + + private static function stringStartsWith(string $command, string $input): bool + { + $commandParts = explode(':', $command); + $inputParts = explode(':', $input); + foreach ($inputParts as $i => $inPart) { + $cmdPart = $commandParts[$i] ?? null; + + if ($cmdPart === null || strpos($cmdPart, $inPart) !== 0) { + return false; + } + } + + return true; + } } diff --git a/src/Input.php b/src/Input.php index fdc00b5..0f93a18 100644 --- a/src/Input.php +++ b/src/Input.php @@ -39,7 +39,6 @@ public function hasOption(string $name): bool if (!self::startsWith($name, '--')) { $name = "--$name"; } - return array_key_exists($name, $this->options); } @@ -50,13 +49,16 @@ public function getOptionValue(string $name) } if (!$this->hasOption($name)) { - throw new \InvalidArgumentException(sprintf('Option "%s" is not defined.', $name)); + return null; } return $this->options[$name]; } public function getArgumentValue(string $name) { + if (!self::startsWith($name, '--')) { + $name = "--$name"; + } if (!$this->hasArgument($name)) { throw new \InvalidArgumentException(sprintf('Argument "%s" is not defined.', $name)); } @@ -65,6 +67,9 @@ public function getArgumentValue(string $name) public function hasArgument(string $name): bool { + if (!self::startsWith($name, '--')) { + $name = "--$name"; + } return array_key_exists($name, $this->arguments); } diff --git a/src/Option/CommandOption.php b/src/Option/CommandOption.php index 363b116..a662b39 100755 --- a/src/Option/CommandOption.php +++ b/src/Option/CommandOption.php @@ -9,16 +9,48 @@ final class CommandOption private ?string $description; private bool $isFlag; + /** + * @var bool|float|int|string + */ + private $default = null; + public function __construct( - string $name, + string $name, ?string $shortcut = null, ?string $description = null, - bool $isFlag = false - ) { - $this->name = $name; - $this->shortcut = $shortcut; + bool $isFlag = false, + $default = null + ) + { + + if ($name === '') { + throw new \InvalidArgumentException("Option name cannot be empty."); + } + + foreach (explode('-', $name) as $part) { + if ($part === '' || !ctype_alpha($part)) { + throw new \InvalidArgumentException("Option name must contain only letters and dashes. '$name' is invalid."); + } + } + + if ($shortcut !== null && (strlen($shortcut) !== 1 || !ctype_alpha($shortcut))) { + throw new \InvalidArgumentException('Shortcut must be a single character and contain only letters. "' . $shortcut . '" is invalid.'); + } + + if (!is_null($default) && !is_scalar($default)) { + throw new \InvalidArgumentException( + sprintf( + 'Invalid default value: expected a scalar (int, float, string, or bool), got "%s".', + gettype($default) + ) + ); + } + + $this->name = strtolower($name); + $this->shortcut = $shortcut !== null ? strtolower($shortcut) : null; $this->description = $description; $this->isFlag = $isFlag; + $this->default = $default; } public function getName(): string @@ -40,4 +72,18 @@ public function isFlag(): bool { return $this->isFlag; } -} \ No newline at end of file + + public function getDefaultValue() + { + return $this->default; + } + + public static function flag(string $name, ?string $shortcut = null, ?string $description = null): self { + return new self($name, $shortcut, $description, true, false); + } + + public static function withValue(string $name, ?string $shortcut = null, ?string $description = null, $default = null): self { + return new self($name, $shortcut, $description, false, $default); + } + +} diff --git a/src/Output.php b/src/Output.php index 2498124..734405c 100644 --- a/src/Output.php +++ b/src/Output.php @@ -22,6 +22,11 @@ public function __construct(callable $output = null) $this->output = $output; } + /** + * @var bool + */ + private bool $verbose = false; + public function write(string $message): void { $output = $this->output; @@ -33,4 +38,14 @@ public function writeln(string $message): void $this->write($message); $this->write(PHP_EOL); } + + public function setVerbose(bool $verbose): void + { + $this->verbose = $verbose; + } + + public function isVerbose(): bool + { + return $this->verbose; + } } diff --git a/src/Output/ConsoleOutput.php b/src/Output/ConsoleOutput.php index 13046a9..55bd7e7 100755 --- a/src/Output/ConsoleOutput.php +++ b/src/Output/ConsoleOutput.php @@ -61,7 +61,7 @@ public function success(string $message): void public function error(string $message): void { [$formattedMessage, $lineLength, $color] = $this->formatMessage('ERROR', $message, 'red'); - $this->outputMessage($formattedMessage, $lineLength, $color); + $this->outputMessage($formattedMessage, $lineLength, $color, true); } public function warning(string $message): void @@ -76,6 +76,16 @@ public function info(string $message): void $this->outputMessage($formattedMessage, $lineLength, $color); } + public function debug(string $message): void + { + if (!$this->output->isVerbose()) { + return; + } + [$formattedMessage, $lineLength, $color] = $this->formatMessage('DEBUG', $message, 'cyan'); + $this->outputMessage($formattedMessage, $lineLength, $color); + } + + public function title(string $message): void { $consoleWidth = $this->geTerminalWidth(); @@ -92,6 +102,7 @@ public function title(string $message): void public function list(array $items): void { foreach ($items as $item) { + $item = $this->variableToString($item); $this->write('- ' . $item); $this->write(PHP_EOL); } @@ -111,6 +122,8 @@ public function listKeyValues(array $items, bool $inlined = false): void } foreach ($items as $key => $value) { + $value = $this->variableToString($value); + $value = implode(' ', explode(PHP_EOL, $value)); $key = str_pad($key, $maxKeyLength, ' ', STR_PAD_RIGHT); $this->writeColor($key, 'green'); $this->write(' : '); @@ -296,7 +309,7 @@ public function boxed(string $message, string $borderChar = '*', int $padding = $this->write(PHP_EOL); } - public function writeColor(string $message, ?string $color = null, ?string $background = null): void + public function writeColor(string $message, ?string $color = null, ?string $background = null, bool $isError = false): void { $formattedMessage = ''; @@ -310,11 +323,15 @@ public function writeColor(string $message, ?string $color = null, ?string $back $formattedMessage .= $message . "\033[0m"; - $this->write($formattedMessage); + $this->write($formattedMessage, $isError); } - public function write(string $message): void + public function write(string $message, bool $isError = false): void { + if ($isError) { + fwrite(STDERR, $message); + return; + } $this->output->write($message); } @@ -323,24 +340,24 @@ public function writeln(string $message): void $this->output->writeln($message); } - private function outputMessage($formattedMessage, int $lineLength, string $color): void + private function outputMessage($formattedMessage, int $lineLength, string $color, bool $isError = false): void { - $this->write(PHP_EOL); - $this->writeColor(str_repeat(' ', $lineLength), 'white', $color); - $this->write(PHP_EOL); + $this->write(PHP_EOL, $isError); + $this->writeColor(str_repeat(' ', $lineLength), 'white', $color, $isError); + $this->write(PHP_EOL, $isError); if (is_string($formattedMessage)) { $formattedMessage = [$formattedMessage]; } foreach ($formattedMessage as $line) { - $this->writeColor($line, 'white', $color); + $this->writeColor($line, 'white', $color, $isError); } - $this->write(PHP_EOL); - $this->writeColor(str_repeat(' ', $lineLength), 'white', $color); - $this->write(PHP_EOL); - $this->write(PHP_EOL); + $this->write(PHP_EOL, $isError); + $this->writeColor(str_repeat(' ', $lineLength), 'white', $color, $isError); + $this->write(PHP_EOL, $isError); + $this->write(PHP_EOL, $isError); } private function formatMessage(string $prefix, string $message, string $color): array @@ -361,7 +378,11 @@ private function formatMessage(string $prefix, string $message, string $color): private function geTerminalWidth(): int { - return ((int)exec('tput cols') ?? 85 - 5); + $width = 85; + if (getenv('TERM')) { + $width = ((int) @exec('tput cols') ?: $width); + } + return $width - 5; } private function variableToString($variable): string @@ -384,4 +405,14 @@ private function variableToString($variable): string return var_export($variable, true); } + + public function setVerbose(bool $verbose): void + { + $this->output->setVerbose($verbose); + } + + public function isVerbose(): bool + { + return $this->output->isVerbose(); + } } diff --git a/src/OutputInterface.php b/src/OutputInterface.php index 64407b0..6c183a8 100644 --- a/src/OutputInterface.php +++ b/src/OutputInterface.php @@ -6,4 +6,6 @@ interface OutputInterface { public function write(string $message): void; public function writeln(string $message): void; + public function setVerbose(bool $verbose): void; + public function isVerbose(): bool; } diff --git a/tests/Command/CacheClearCommand.php b/tests/Command/CacheClearCommand.php new file mode 100644 index 0000000..7b49f8a --- /dev/null +++ b/tests/Command/CacheClearCommand.php @@ -0,0 +1,37 @@ +write('Test OK : Clear cache'); + } +} diff --git a/tests/Command/FooCommand.php b/tests/Command/FooCommand.php index d36d608..bfe8f3b 100755 --- a/tests/Command/FooCommand.php +++ b/tests/Command/FooCommand.php @@ -1,45 +1,44 @@ -writeln('Test OK'); - $output->writeln('ARGUMENTS: ' . json_encode($input->getArguments())); - $output->writeln('OPTIONS: ' . json_encode($input->getOptions())); - } -} +writeln('Test OK'); + $output->writeln('ARGUMENTS: ' . json_encode($input->getArguments())); + $output->writeln('OPTIONS: ' . json_encode($input->getOptions())); + } +} diff --git a/tests/Command/MakeControllerCommand.php b/tests/Command/MakeControllerCommand.php new file mode 100644 index 0000000..df43556 --- /dev/null +++ b/tests/Command/MakeControllerCommand.php @@ -0,0 +1,39 @@ +write('Test OK : Make a new controller'); + } +} diff --git a/tests/Command/MakeEntityCommand.php b/tests/Command/MakeEntityCommand.php new file mode 100644 index 0000000..7f79f66 --- /dev/null +++ b/tests/Command/MakeEntityCommand.php @@ -0,0 +1,37 @@ +write('Test OK : Make a new entity'); + } +} diff --git a/tests/Command/UserCreateCommand.php b/tests/Command/UserCreateCommand.php new file mode 100644 index 0000000..ebc0b3c --- /dev/null +++ b/tests/Command/UserCreateCommand.php @@ -0,0 +1,37 @@ +write('Test OK : User create'); + } +} diff --git a/tests/Command/UserDisabledCommand.php b/tests/Command/UserDisabledCommand.php new file mode 100644 index 0000000..5215a67 --- /dev/null +++ b/tests/Command/UserDisabledCommand.php @@ -0,0 +1,37 @@ +write('Test OK : User disabled'); + } +} diff --git a/tests/Command/UserListCommand.php b/tests/Command/UserListCommand.php new file mode 100644 index 0000000..05f29dd --- /dev/null +++ b/tests/Command/UserListCommand.php @@ -0,0 +1,40 @@ +write('Test OK : User list'); + $output->write(sprintf('LIMIT : %d', $input->getOptionValue('limit'))); + } +} diff --git a/tests/Command/UserResetPasswordCommand.php b/tests/Command/UserResetPasswordCommand.php new file mode 100644 index 0000000..90a5ac3 --- /dev/null +++ b/tests/Command/UserResetPasswordCommand.php @@ -0,0 +1,37 @@ +write('Test OK : User reset password'); + } +} diff --git a/tests/CommandArgumentTest.php b/tests/CommandArgumentTest.php index 89f16b8..afbd889 100755 --- a/tests/CommandArgumentTest.php +++ b/tests/CommandArgumentTest.php @@ -4,7 +4,7 @@ use PhpDevCommunity\Console\Argument\CommandArgument; use PhpDevCommunity\Console\Output; -use PhpDevCommunity\UniTester\TestCase; +use Depo\UniTester\TestCase; class CommandArgumentTest extends TestCase { @@ -90,4 +90,4 @@ public function testGetDescriptionReturnsCorrectValue() $this->assertEquals('description', $arg->getDescription()); } -} \ No newline at end of file +} diff --git a/tests/CommandOptionTest.php b/tests/CommandOptionTest.php index fa8249a..374b779 100755 --- a/tests/CommandOptionTest.php +++ b/tests/CommandOptionTest.php @@ -4,7 +4,7 @@ use PhpDevCommunity\Console\Option\CommandOption; use PhpDevCommunity\Console\Output; -use PhpDevCommunity\UniTester\TestCase; +use Depo\UniTester\TestCase; class CommandOptionTest extends TestCase { @@ -62,4 +62,4 @@ public function testIsFlag(): void $this->assertTrue($option->isFlag()); } -} \ No newline at end of file +} diff --git a/tests/CommandParserTest.php b/tests/CommandParserTest.php index 4c54bcd..9651598 100755 --- a/tests/CommandParserTest.php +++ b/tests/CommandParserTest.php @@ -3,7 +3,7 @@ namespace Test\PhpDevCommunity\Console; use PhpDevCommunity\Console\CommandParser; -use PhpDevCommunity\UniTester\TestCase; +use Depo\UniTester\TestCase; class CommandParserTest extends TestCase { @@ -78,4 +78,4 @@ private static function createArgv(array $argv): array { return array_merge(['bin/console'], $argv); } -} \ No newline at end of file +} diff --git a/tests/CommandRunnerTest.php b/tests/CommandRunnerTest.php new file mode 100644 index 0000000..dd5f3cb --- /dev/null +++ b/tests/CommandRunnerTest.php @@ -0,0 +1,81 @@ +commandRunner = new CommandRunner([ + new CacheClearCommand(), + new MakeControllerCommand(), + new MakeEntityCommand(), + new UserCreateCommand(), + new UserDisabledCommand(), + new UserResetPasswordCommand(), + new UserListCommand(), + ]); + } + + protected function tearDown(): void + { + // TODO: Implement tearDown() method. + } + + protected function execute(): void + { + $exitCode = $this->commandRunner->run(new CommandParser(self::createArgv(['c:c'])), new Output(function ($message) { + $this->assertEquals('Test OK : Clear cache', $message); + }) + ); + $this->assertEquals(0, $exitCode); + + $message = ''; + $exitCode = $this->commandRunner->run(new CommandParser(self::createArgv(['c:c', '--verbose'])), new Output(function ($outputMessage) use (&$message) { + $message .= $outputMessage; + }) + ); + $this->assertStringContains( $message, 'Test OK : Clear cache'); + $this->assertStringContains( $message, 'Execution time:'); + $this->assertStringContains( $message, 'Peak memory usage:'); + $this->assertEquals(0, $exitCode); + + + $messages = []; + $exitCode = $this->commandRunner->run(new CommandParser(self::createArgv(['app:user:list'])), new Output(function ($message) use(&$messages){ + $messages[] = $message; + }) + ); + $this->assertEquals(0, $exitCode); + $this->assertEquals('Test OK : User list', $messages[0]); + $this->assertEquals('LIMIT : 100', $messages[1]); + + $messages = []; + $exitCode = $this->commandRunner->run(new CommandParser(self::createArgv(['app:user:list', '-l', '1000'])), new Output(function ($message) use(&$messages){ + $messages[] = $message; + }) + ); + $this->assertEquals(0, $exitCode); + $this->assertEquals('Test OK : User list', $messages[0]); + $this->assertEquals('LIMIT : 1000', $messages[1]); + } + + private static function createArgv(array $argv): array + { + return array_merge(['bin/console'], $argv); + } +} diff --git a/tests/CommandTest.php b/tests/CommandTest.php index f6291fa..76b7065 100755 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -6,7 +6,7 @@ use PhpDevCommunity\Console\Input; use PhpDevCommunity\Console\Option\CommandOption; use PhpDevCommunity\Console\Output; -use PhpDevCommunity\UniTester\TestCase; +use Depo\UniTester\TestCase; use Test\PhpDevCommunity\Console\Command\FooCommand; class CommandTest extends TestCase @@ -93,4 +93,4 @@ public function testExecute(): void $this->assertEquals(6, $lines); } -} \ No newline at end of file +} diff --git a/tests/InputTest.php b/tests/InputTest.php index 58bcfff..06c79c6 100755 --- a/tests/InputTest.php +++ b/tests/InputTest.php @@ -4,7 +4,7 @@ use PhpDevCommunity\Console\Input; use PhpDevCommunity\Console\Output; -use PhpDevCommunity\UniTester\TestCase; +use Depo\UniTester\TestCase; class InputTest extends TestCase { @@ -64,14 +64,12 @@ public function testGetOptionValue() $input = new Input('test', ['--option' => 'value'], []); $this->assertEquals('value', $input->getOptionValue('option')); $this->assertEquals('value', $input->getOptionValue('--option')); - $this->expectException(\InvalidArgumentException::class, function () use ($input) { - $input->getOptionValue('invalid'); - }); + $this->assertEquals(null, $input->getOptionValue('invalid')); } public function testGetArgumentValue() { - $input = new Input('test', [], ['argument' => 'value']); + $input = new Input('test', [], ['--argument' => 'value']); $this->assertEquals('value', $input->getArgumentValue('argument')); $this->expectException(\InvalidArgumentException::class, function () use ($input) { $input->getArgumentValue('invalid'); @@ -80,8 +78,8 @@ public function testGetArgumentValue() public function testHasArgument() { - $input = new Input('test', [], ['argument' => 'value']); + $input = new Input('test', [], ['--argument' => 'value']); $this->assertTrue($input->hasArgument('argument')); $this->assertFalse($input->hasArgument('invalid')); } -} \ No newline at end of file +} diff --git a/tests/OutputTest.php b/tests/OutputTest.php index 11d74c5..7072570 100755 --- a/tests/OutputTest.php +++ b/tests/OutputTest.php @@ -3,7 +3,7 @@ namespace Test\PhpDevCommunity\Console; use PhpDevCommunity\Console\Output; -use PhpDevCommunity\UniTester\TestCase; +use Depo\UniTester\TestCase; class OutputTest extends TestCase { @@ -48,4 +48,4 @@ public function testWriteln() $output->writeln('Hello, world!'); $this->assertEquals(2, $lines); } -} \ No newline at end of file +}