From 7c06febefe0c7a479b8402f1f84c2ecf5d2f5022 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 20 May 2019 22:39:08 +1000 Subject: [PATCH 01/39] Updated example to use manpage() provided by the pointybeard/helpers-functions-cli package --- composer.json | 5 ++- example/example.php | 105 +++++++++++--------------------------------- 2 files changed, 28 insertions(+), 82 deletions(-) diff --git a/composer.json b/composer.json index 081d489..937c4d3 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.0.0", + "version": "1.0.1", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", @@ -20,7 +20,8 @@ "require-dev": { "phpunit/phpunit": "^8", "pointybeard/helpers-functions-strings": "~1.0", - "pointybeard/helpers-cli-colour": "~1.0" + "pointybeard/helpers-cli-colour": "~1.0", + "pointybeard/helpers-functions-cli": "~1.1" }, "support": { "issues": "https://github.com/pointybeard/helpers-cli-input/issues", diff --git a/example/example.php b/example/example.php index 075ff81..04c979c 100644 --- a/example/example.php +++ b/example/example.php @@ -4,9 +4,10 @@ declare(strict_types=1); include __DIR__.'/../vendor/autoload.php'; use pointybeard\Helpers\Cli\Input; +use pointybeard\Helpers\Cli\Colour\Colour; use pointybeard\Helpers\Functions\Flags; use pointybeard\Helpers\Functions\Strings; -use pointybeard\Helpers\Cli\Colour\Colour; +use pointybeard\Helpers\Functions\Cli; // Define what we are expecting to get from the command line $collection = (new Input\InputCollection()) @@ -52,87 +53,31 @@ $collection = (new Input\InputCollection()) // and validate the input according to our collection $argv = Input\InputHandlerFactory::build('Argv', $collection); -// Example of using an input collection to generate a usage string -function usage(Input\InputCollection $collection): string { - $arguments = []; - foreach ($collection->getArguments() as $a) { - $arguments[] = strtoupper( - // Wrap with square brackets if it's not required - Flags\is_flag_set(Input\AbstractInputType::FLAG_OPTIONAL, $a->flags()) || - !Flags\is_flag_set(Input\AbstractInputType::FLAG_REQUIRED, $a->flags()) - ? "[{$a->name()}]" - : $a->name() - ); - } - $arguments = trim(implode($arguments, ' ')); - return sprintf( - "Usage: php -f example.php -- [OPTIONS]... %s%s", - $arguments, - strlen($arguments) > 0 ? '...' : '' - ); -} - -// Example of using an input collection to generate a manual page -function manpage(Input\InputCollection $collection) : string { - - $arguments = $options = []; - - foreach ($collection->getArguments() as $a) { - $arguments[] = (string) $a; - } - - foreach ($collection->getOptions() as $o) { - $options[] = (string) $o; - } - - $arguments = implode($arguments, PHP_EOL.' '); - $options = implode($options, PHP_EOL.' '); - - return sprintf('%s 1.0.0, %s -%s - -Mandatory values for long options are mandatory for short options too. - -Arguments: - %s - -Options: - %s - -Examples: - php -f example/example.php -- -vvv -d example/example.json import -', - basename(__FILE__), - Strings\utf8_wordwrap( - "An example script for the PHP Helpers: Command-line Input and Input Type Handlers composer library (pointybeard/helpers-cli-input)." - ), - usage($collection), - $arguments, - $options - ); -} - // Display the manual in green text -echo Colour::colourise(manpage($collection), Colour::FG_GREEN) . PHP_EOL . PHP_EOL; +echo Colour::colourise(Cli\manpage( + basename(__FILE__), + '1.0.1', + 'An example script for the PHP Helpers: Command-line Input and Input Type Handlers composer library (pointybeard/helpers-cli-input).', + 'php -f example/example.php -- -vvv -d example/example.json import', + $collection +), Colour::FG_GREEN) . PHP_EOL . PHP_EOL; -/* -example.php 1.0.0, An example script for the PHP Helpers: Command-line Input and Input Type Handlers -composer library (pointybeard/helpers-cli-input). -Usage: php -f example.php -- [OPTIONS]... ACTION... - -Mandatory values for long options are mandatory for short options too. - -Arguments: - ACTION The name of the action to perform - -Options: - -v verbosity level. -v (errors only), -vv (warnings - and errors), -vvv (everything). - -d, --data=VALUE Path to the input JSON data - -Examples: - php -f example/example.php -- -vvv -d example/example.json import -*/ +// example.php 1.0.0, An example script for the PHP Helpers: Command-line Input and Input Type Handlers +// composer library (pointybeard/helpers-cli-input). +// Usage: example.php [OPTIONS]... ACTION... +// +// Mandatory values for long options are mandatory for short options too. +// +// Arguments: +// ACTION The name of the action to perform +// +// Options: +// -v verbosity level. -v (errors only), -vv (warnings +// and errors), -vvv (everything). +// -d, --data=VALUE Path to the input JSON data +// +// Examples: +// php -f example/example.php -- -vvv -d example/example.json import var_dump($argv->getArgument('action')); // string(6) "import" From 8d3141c79fb050389fded1842ab333375b5019cf Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 20 May 2019 22:39:48 +1000 Subject: [PATCH 02/39] Updated README and CHANGELOG for 1.0.1 --- CHANGELOG.md | 7 ++++++- README.md | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75f524d..a72f417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.0.1][] +#### Changed +- Updated example to use `Cli\manpage()` provided by the `pointybeard/helpers-functions-cli` package + ## 1.0.0 #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-cli-input/compare/1.0.0...integration +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.1...integration +[1.0.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.0...1.0.1 diff --git a/README.md b/README.md index 993641a..17b49a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.0.0 +- Version: v1.0.1 - Date: May 20 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) From 25f3fb8014acfb092540fc3f1bad3a6d840ccd17 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Thu, 23 May 2019 23:44:24 +1000 Subject: [PATCH 03/39] Fixed InputCollection::getArgumentsByIndex() so it returns NULL if the index does not exist instead of throwing an E_NOTICE message --- src/Input/InputCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Input/InputCollection.php b/src/Input/InputCollection.php index 525ab44..ddf99ba 100644 --- a/src/Input/InputCollection.php +++ b/src/Input/InputCollection.php @@ -77,7 +77,7 @@ class InputCollection public function getArgumentsByIndex(int $index): ?AbstractInputType { - return $this->arguments[$index]; + return $this->arguments[$index] ?? null; } public function getArguments(): array From 6e987bb4eb05bdcbe0a7bb072e2c880af5dfbf4e Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Thu, 23 May 2019 23:44:52 +1000 Subject: [PATCH 04/39] Updated README, composer.json, and CHANGELOG for 1.0.2 release --- CHANGELOG.md | 7 ++++++- README.md | 4 ++-- composer.json | 12 ++++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a72f417..98c1193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.0.2][] +#### Fixed +- Fixed `InputCollection::getArgumentsByIndex()` so it returns NULL if the index does not exist instead of throwing an E_NOTICE message + ## [1.0.1][] #### Changed - Updated example to use `Cli\manpage()` provided by the `pointybeard/helpers-functions-cli` package @@ -13,5 +17,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.1...integration +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.2...integration +[1.0.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.0...1.0.1 diff --git a/README.md b/README.md index 17b49a0..e8823ce 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.0.1 -- Date: May 20 2019 +- Version: v1.0.2 +- Date: May 23 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index 937c4d3..9bfb571 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.0.1", + "version": "1.0.2", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", @@ -14,14 +14,14 @@ ], "require": { "php": ">=7.2", - "pointybeard/helpers-foundation-factory": "~1.0", - "pointybeard/helpers-functions-flags": "~1.0" + "pointybeard/helpers-foundation-factory": "~1", + "pointybeard/helpers-functions-flags": "~1" }, "require-dev": { "phpunit/phpunit": "^8", - "pointybeard/helpers-functions-strings": "~1.0", - "pointybeard/helpers-cli-colour": "~1.0", - "pointybeard/helpers-functions-cli": "~1.1" + "pointybeard/helpers-functions-strings": "^1", + "pointybeard/helpers-cli-colour": "^1", + "pointybeard/helpers-functions-cli": "^1" }, "support": { "issues": "https://github.com/pointybeard/helpers-cli-input/issues", From 95e93ec1bcd0c0c20089c7db4bb3f39bc58e3381 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 13:22:35 +1000 Subject: [PATCH 05/39] Refactoring and improvemnts to Argument::__toString() and Option::__toString() --- src/Input/Types/Argument.php | 41 +++++++++++++++++++++++++++--- src/Input/Types/Option.php | 48 ++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/Input/Types/Argument.php b/src/Input/Types/Argument.php index f303c8d..1d589e6 100644 --- a/src/Input/Types/Argument.php +++ b/src/Input/Types/Argument.php @@ -6,18 +6,51 @@ namespace pointybeard\Helpers\Cli\Input\Types; use pointybeard\Helpers\Cli\Input; use pointybeard\Helpers\Functions\Strings; +use pointybeard\Helpers\Functions\Cli; class Argument extends Input\AbstractInputType { public function __toString() { - $name = strtoupper($this->name()); + // MAGIC VALUES!!! OH MY..... + $padCharacter = ' '; + $paddingBufferSize = 0.15; // 15% + $argumentNamePaddedWidth = 20; + $argumentNameMinimumPaddingWidth = 4; + $minimumWindowWidth = 80; - $first = str_pad(sprintf('%s ', $name), 20, ' '); + // Get the window dimensions but restrict width to minimum + // of $minimumWindowWidth + $window = Cli\get_window_size(); + $window['cols'] = max($minimumWindowWidth, $window['cols']); - $second = Strings\utf8_wordwrap_array($this->description(), 40); + // This shrinks the total line length (derived by the window width) by + // $paddingBufferSize + $paddingBuffer = (int) ceil($window['cols'] * $paddingBufferSize); + + // Create a string of $padCharacter which is prepended to each secondary + // line + $secondaryLineLeadPadding = str_pad( + '', + $argumentNamePaddedWidth, + $padCharacter, + STR_PAD_LEFT + ); + + $first = Strings\mb_str_pad( + strtoupper($this->name()).str_repeat($padCharacter, $argumentNameMinimumPaddingWidth), + $argumentNamePaddedWidth, + $padCharacter + ); + + $second = Strings\utf8_wordwrap_array( + $this->description(), + $window['cols'] - $argumentNamePaddedWidth - $paddingBuffer + ); + + // Skip the first item (notice $ii starts at value of '1') for ($ii = 1; $ii < count($second); ++$ii) { - $second[$ii] = str_pad('', 22, ' ', \STR_PAD_LEFT).$second[$ii]; + $second[$ii] = $secondaryLineLeadPadding.$second[$ii]; } return $first.implode($second, PHP_EOL); diff --git a/src/Input/Types/Option.php b/src/Input/Types/Option.php index 3771de1..c3ef0d0 100644 --- a/src/Input/Types/Option.php +++ b/src/Input/Types/Option.php @@ -6,6 +6,7 @@ namespace pointybeard\Helpers\Cli\Input\Types; use pointybeard\Helpers\Functions\Flags; use pointybeard\Helpers\Functions\Strings; +use pointybeard\Helpers\Functions\Cli; use pointybeard\Helpers\Cli\Input; class Option extends Input\AbstractInputType @@ -22,19 +23,56 @@ class Option extends Input\AbstractInputType public function __toString() { - $long = null !== $this->long() ? ', --'.$this->long() : null; - if (null != $long) { + // MAGIC VALUES!!! OH MY..... + $padCharacter = ' '; + $paddingBufferSize = 0.15; // 15% + $optionNamePaddedWidth = 30; + $minimumWindowWidth = 80; + $secondaryLineIndentlength = 2; + + // Get the window dimensions but restrict width to minimum + // of $minimumWindowWidth + $window = Cli\get_window_size(); + $window['cols'] = max($minimumWindowWidth, $window['cols']); + + // This shrinks the total line length (derived by the window width) by + // $paddingBufferSize + $paddingBuffer = (int) ceil($window['cols'] * $paddingBufferSize); + + // Create a string of $padCharacter which is prepended to each secondary + // line + $secondaryLineLeadPadding = str_pad( + '', + $optionNamePaddedWidth, + $padCharacter, + STR_PAD_LEFT + ); + + $short = '-'.$this->name(); + $long = null; + + if (null !== $this->long()) { + $long = '--'.$this->long(); if (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_REQUIRED)) { $long .= '=VALUE'; } elseif (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_OPTIONAL)) { $long .= '[=VALUE]'; } } - $first = str_pad(sprintf('-%s%s ', $this->name(), $long), 36, ' '); - $second = Strings\utf8_wordwrap_array($this->description(), 40); + $first = Strings\mb_str_pad( + $short.(null !== $long ? ", {$long}" : ''), // -O, --LONG, + $optionNamePaddedWidth, + $padCharacter + ); + + $second = Strings\utf8_wordwrap_array( + $this->description(), + $window['cols'] - $optionNamePaddedWidth - $paddingBuffer + ); + for ($ii = 1; $ii < count($second); ++$ii) { - $second[$ii] = str_pad('', 38, ' ', \STR_PAD_LEFT).$second[$ii]; + $second[$ii] = $secondaryLineLeadPadding.$second[$ii]; } return $first.implode($second, PHP_EOL); From 9ac0e21d041756e685d3b1fe3a464127acadb405 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 13:28:34 +1000 Subject: [PATCH 06/39] Updated example to reflect changes to manpage() function in pointybeard/helpers-functions-cli package --- example/example.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/example/example.php b/example/example.php index 04c979c..6af92e1 100644 --- a/example/example.php +++ b/example/example.php @@ -5,8 +5,6 @@ include __DIR__.'/../vendor/autoload.php'; use pointybeard\Helpers\Cli\Input; use pointybeard\Helpers\Cli\Colour\Colour; -use pointybeard\Helpers\Functions\Flags; -use pointybeard\Helpers\Functions\Strings; use pointybeard\Helpers\Functions\Cli; // Define what we are expecting to get from the command line @@ -54,30 +52,32 @@ $collection = (new Input\InputCollection()) $argv = Input\InputHandlerFactory::build('Argv', $collection); // Display the manual in green text -echo Colour::colourise(Cli\manpage( +echo Cli\manpage( basename(__FILE__), - '1.0.1', + '1.0.2', 'An example script for the PHP Helpers: Command-line Input and Input Type Handlers composer library (pointybeard/helpers-cli-input).', - 'php -f example/example.php -- -vvv -d example/example.json import', - $collection -), Colour::FG_GREEN) . PHP_EOL . PHP_EOL; + $collection, + Colour::FG_GREEN, + Colour::FG_WHITE, + [ + 'Examples' => 'php -f example/example.php -- -vvv -d example/example.json import' + ] +).PHP_EOL.PHP_EOL; -// example.php 1.0.0, An example script for the PHP Helpers: Command-line Input and Input Type Handlers -// composer library (pointybeard/helpers-cli-input). +// example.php 1.0.2, An example script for the PHP Helpers: Command-line Input +// and Input Type Handlers composer library (pointybeard/helpers-cli-input). // Usage: example.php [OPTIONS]... ACTION... // -// Mandatory values for long options are mandatory for short options too. -// // Arguments: -// ACTION The name of the action to perform +// ACTION The name of the action to perform // // Options: -// -v verbosity level. -v (errors only), -vv (warnings -// and errors), -vvv (everything). -// -d, --data=VALUE Path to the input JSON data +// -v verbosity level. -v (errors only), -vv +// (warnings and errors), -vvv (everything). +// -d, --data=VALUE Path to the input JSON data // // Examples: -// php -f example/example.php -- -vvv -d example/example.json import +// php -f example/example.php -- -vvv -d example/example.json import var_dump($argv->getArgument('action')); // string(6) "import" From b36bfeac3dbde731f3d88ed694cf4aeafd6fd6a4 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 13:29:08 +1000 Subject: [PATCH 07/39] Updated README and CHANGELOG for 1.0.3 release --- README.md | 4 ++-- composer.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e8823ce..ee87be8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.0.2 -- Date: May 23 2019 +- Version: v1.0.3 +- Date: May 24 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index 9bfb571..a9f6972 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.0.2", + "version": "1.0.3", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", From b49ee5559d59dd58a6b7939a23a7682d9c570c28 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 17:13:24 +1000 Subject: [PATCH 08/39] Expanded input types to include Flag, IncrementingFlag, and LongOption. Refactored Option and Argument types. --- src/Input/Types/Argument.php | 15 ++++++ src/Input/Types/Flag.php | 21 ++++++++ src/Input/Types/IncrementingFlag.php | 21 ++++++++ src/Input/Types/LongOption.php | 81 ++++++++++++++++++++++++++++ src/Input/Types/Option.php | 22 +------- 5 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 src/Input/Types/Flag.php create mode 100644 src/Input/Types/IncrementingFlag.php create mode 100644 src/Input/Types/LongOption.php diff --git a/src/Input/Types/Argument.php b/src/Input/Types/Argument.php index 1d589e6..3ada5b9 100644 --- a/src/Input/Types/Argument.php +++ b/src/Input/Types/Argument.php @@ -10,6 +10,21 @@ use pointybeard\Helpers\Functions\Cli; class Argument extends Input\AbstractInputType { + + public function __construct(string $name = null, int $flags = null, string $description = null, object $validator = null, $default=null) + { + if(null === $validator) { + $validator = function (Input\AbstractInputType $input, Input\AbstractInputHandler $context) { + // This dummy validator is necessary otherwise the argument + // value is ALWAYS set to default (most often NULL) regardless + // of if the argument was set or not + return $context->find($input->name()); + }; + } + + parent::__construct($name, $flags, $description, $validator, $default); + } + public function __toString() { // MAGIC VALUES!!! OH MY..... diff --git a/src/Input/Types/Flag.php b/src/Input/Types/Flag.php new file mode 100644 index 0000000..fba5f55 --- /dev/null +++ b/src/Input/Types/Flag.php @@ -0,0 +1,21 @@ +short = $short; + parent::__construct($name, $flags, $description, $validator, $default); + } + + public function respondsTo(string $name): bool + { + return ($name == $this->name || $name == $this->short); + } + + public function __toString() + { + // MAGIC VALUES!!! OH MY..... + $padCharacter = ' '; + $paddingBufferSize = 0.15; // 15% + $optionNamePaddedWidth = 30; + $minimumWindowWidth = 80; + $secondaryLineIndentlength = 2; + + // Get the window dimensions but restrict width to minimum + // of $minimumWindowWidth + $window = Cli\get_window_size(); + $window['cols'] = max($minimumWindowWidth, $window['cols']); + + // This shrinks the total line length (derived by the window width) by + // $paddingBufferSize + $paddingBuffer = (int) ceil($window['cols'] * $paddingBufferSize); + + // Create a string of $padCharacter which is prepended to each secondary + // line + $secondaryLineLeadPadding = str_pad( + '', + $optionNamePaddedWidth, + $padCharacter, + STR_PAD_LEFT + ); + + $short = null !== $this->short() ? '-'.$this->short() : null; + $long = null; + + $long = '--'.$this->name(); + if (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_REQUIRED)) { + $long .= '=VALUE'; + } elseif (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_OPTIONAL)) { + $long .= '[=VALUE]'; + } + + $first = Strings\mb_str_pad( + (null !== $short ? "{$short}, " : '').$long, // -O, --LONG, + $optionNamePaddedWidth, + $padCharacter + ); + + $second = Strings\utf8_wordwrap_array( + $this->description(), + $window['cols'] - $optionNamePaddedWidth - $paddingBuffer + ); + + for ($ii = 1; $ii < count($second); ++$ii) { + $second[$ii] = $secondaryLineLeadPadding.$second[$ii]; + } + + return $first.implode($second, PHP_EOL); + } +} diff --git a/src/Input/Types/Option.php b/src/Input/Types/Option.php index c3ef0d0..951caf4 100644 --- a/src/Input/Types/Option.php +++ b/src/Input/Types/Option.php @@ -11,16 +11,6 @@ use pointybeard\Helpers\Cli\Input; class Option extends Input\AbstractInputType { - protected $long; - protected $default; - - public function __construct(string $name, string $long = null, int $flags = null, string $description = null, object $validator = null, $default = false) - { - $this->default = $default; - $this->long = $long; - parent::__construct($name, $flags, $description, $validator); - } - public function __toString() { // MAGIC VALUES!!! OH MY..... @@ -49,19 +39,9 @@ class Option extends Input\AbstractInputType ); $short = '-'.$this->name(); - $long = null; - - if (null !== $this->long()) { - $long = '--'.$this->long(); - if (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_REQUIRED)) { - $long .= '=VALUE'; - } elseif (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_OPTIONAL)) { - $long .= '[=VALUE]'; - } - } $first = Strings\mb_str_pad( - $short.(null !== $long ? ", {$long}" : ''), // -O, --LONG, + $short, $optionNamePaddedWidth, $padCharacter ); From 9e27b52991d66da6b3f10e823fdc6d19ef549098 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 17:16:49 +1000 Subject: [PATCH 09/39] Updated to work with more than just Argument and Option input types. Makes use of InputTypeFactory to allow addition of new types as needed. Added InputTypeFactory to help with loading input type classes --- src/Input/AbstractInputHandler.php | 95 +++++++-------- src/Input/AbstractInputType.php | 22 +++- .../Exceptions/InputNotFoundException.php | 6 +- src/Input/Handlers/Argv.php | 20 ++-- src/Input/InputCollection.php | 110 +++++++----------- src/Input/InputTypeFactory.php | 23 ++++ .../Interfaces/InputHandlerInterface.php | 10 +- src/Input/Interfaces/InputTypeInterface.php | 1 + 8 files changed, 144 insertions(+), 143 deletions(-) create mode 100644 src/Input/InputTypeFactory.php diff --git a/src/Input/AbstractInputHandler.php b/src/Input/AbstractInputHandler.php index d35eb47..89d4c00 100644 --- a/src/Input/AbstractInputHandler.php +++ b/src/Input/AbstractInputHandler.php @@ -8,8 +8,7 @@ use pointybeard\Helpers\Functions\Flags; abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface { - protected $options = []; - protected $arguments = []; + protected $input = []; protected $collection = null; abstract protected function parse(): bool; @@ -17,8 +16,7 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface public function bind(InputCollection $inputCollection, bool $skipValidation = false): bool { // Do the binding stuff here - $this->options = []; - $this->arguments = []; + $this->input = []; $this->collection = $inputCollection; $this->parse(); @@ -43,71 +41,56 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface public function validate(): void { - // Do basic missing option and value checking here - foreach ($this->collection->getOptions() as $input) { - self::checkRequiredAndRequiredValue($input, $this->options); - } + foreach ($this->collection->getItems() as $type => $items) { + foreach($items as $input) { + self::checkRequiredAndRequiredValue($input, $this->input); - // Option validation. - foreach ($this->collection->getoptions() as $o) { - $result = false; + if( + null !== $input->default() && + null === $this->find($input->name()) && + null === $input->validator() + ) { + $result = $input->default(); + } elseif(null !== $input->validator()) { + $validator = $input->validator(); - if (!array_key_exists($o->name(), $this->options)) { - $result = $o->default(); - } else { - if (null === $o->validator()) { - $result = $o->default(); - continue; - } elseif ($o->validator() instanceof \Closure) { - $validator = new Validator($o->validator()); - } elseif ($o->validator() instanceof Validator) { - $validator = $o->validator(); + if ($validator instanceof \Closure) { + $validator = new Validator($validator); + } elseif (!($validator instanceof Validator)) { + throw new \Exception("Validator for '{$input->name()}' must be NULL or an instance of either Closure or Input\Validator."); + } + + $result = $validator->validate($input, $this); } else { - throw new \Exception("Validator for option {$o->name()} must be NULL or an instance of either Closure or Input\Validator."); + $result = $this->find($input->name()); } - $result = $validator->validate($o, $this); - } - - $this->options[$o->name()] = $result; - } - - // Argument validation. - foreach ($this->collection->getArguments() as $a) { - self::checkRequiredAndRequiredValue($a, $this->arguments); - - if (isset($this->arguments[$a->name()]) && null !== $a->validator()) { - if ($a->validator() instanceof \Closure) { - $validator = new Validator($a->validator()); - } elseif ($a->validator() instanceof Validator) { - $validator = $a->validator(); - } else { - throw new \Exception("Validator for argument {$a->name()} must be NULL or an instance of either Closure or Input\Validator."); - } - - $validator->validate($a, $this); + $this->input[$input->name()] = $result; } } } - public function getArgument(string $name): ?string + public function find(string $name) { - return $this->arguments[$name] ?? null; + if(isset($this->input[$name])) { + return $this->input[$name]; + } + + // Check the collection to see if anything responds to $name + foreach($this->collection->getItems() as $type => $items) { + foreach($items as $ii) { + if($ii->respondsTo($name) && isset($this->input[$ii->name()])) { + return $this->input[$ii->name()]; + } + } + } + + throw new Exceptions\InputNotFoundException($name); } - public function getOption(string $name) + public function getInput(): array { - return $this->options[$name] ?? null; - } - - public function getArguments(): array - { - return $this->arguments; - } - - public function getOptions(): array - { - return $this->options; + return $this->input; } public function getCollection(): ?InputCollection diff --git a/src/Input/AbstractInputType.php b/src/Input/AbstractInputType.php index 9fadc5e..be3999c 100644 --- a/src/Input/AbstractInputType.php +++ b/src/Input/AbstractInputType.php @@ -12,22 +12,40 @@ abstract class AbstractInputType implements Interfaces\InputTypeInterface protected $flags; protected $description; protected $validator; + protected $default; protected $value; - public function __construct($name, int $flags = null, string $description = null, object $validator = null) + public function __construct(string $name = null, int $flags = null, string $description = null, object $validator = null, $default = null) { $this->name = $name; $this->flags = $flags; $this->description = $description; $this->validator = $validator; + $this->default = $default; } - public function __call($name, array $args = []) + public function __call($name, array $args=[]) + { + if (empty($args)) { + return $this->$name; + } + + $this->$name = $args[0]; + + return $this; + } + + public function __get($name) { return $this->$name; } + public function respondsTo(string $name): bool + { + return ($name == $this->name); + } + public function getType(): string { return strtolower((new \ReflectionClass(static::class))->getShortName()); diff --git a/src/Input/Exceptions/InputNotFoundException.php b/src/Input/Exceptions/InputNotFoundException.php index 475cc66..f262aaa 100644 --- a/src/Input/Exceptions/InputNotFoundException.php +++ b/src/Input/Exceptions/InputNotFoundException.php @@ -4,10 +4,10 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input\Exceptions; -class InputHandlerNotFoundException extends \Exception +class InputNotFoundException extends \Exception { - public function __construct(string $handler, string $command, $code = 0, \Exception $previous = null) + public function __construct(string $name, $code = 0, \Exception $previous = null) { - return parent::__construct(sprintf('The input handler %s could not be located.', $handler), $code, $previous); + return parent::__construct(sprintf('Input %s could not be found.', $name), $code, $previous); } } diff --git a/src/Input/Handlers/Argv.php b/src/Input/Handlers/Argv.php index 75f30dd..536284c 100644 --- a/src/Input/Handlers/Argv.php +++ b/src/Input/Handlers/Argv.php @@ -67,6 +67,7 @@ class Argv extends Input\AbstractInputHandler $it = new \ArrayIterator($this->argv); $position = 0; + $argumentCount = 0; while ($it->valid()) { $token = $it->current(); @@ -82,9 +83,9 @@ class Argv extends Input\AbstractInputHandler $value = true; } - $o = $this->collection->findOption($name); + $o = $this->collection->find($name); - $this->options[ + $this->input[ $o instanceof Input\AbstractInputType ? $o->name() : $name @@ -98,14 +99,14 @@ class Argv extends Input\AbstractInputHandler // Determine if we're expecting a value. // It also might have a long option equivalent, so we need // to look for that too. - $o = $this->collection->findOption($name); + $o = $this->collection->find($name); // This could also be an incrementing value // and needs to be added up. E.g. e.g. -vvv or -v -v -v // would be -v => 3 if ($o instanceof Input\AbstractInputType && Flags\is_flag_set($o->flags(), Input\AbstractInputType::FLAG_TYPE_INCREMENTING)) { - $value = isset($this->options[$name]) - ? $this->options[$name] + 1 + $value = isset($this->input[$name]) + ? $this->input[$name] + 1 : 1 ; @@ -128,7 +129,7 @@ class Argv extends Input\AbstractInputHandler } } - $this->options[ + $this->input[ $o instanceof Input\AbstractInputType ? $o->name() : $name @@ -141,12 +142,13 @@ class Argv extends Input\AbstractInputHandler // Arguments are positional, so we need to keep a track // of the index and look at the collection for an argument // with the same index - $a = $this->collection->getArgumentsByIndex(count($this->arguments)); - $this->arguments[ + $a = $this->collection->getItemByIndex('Argument', $argumentCount); + $this->input[ $a instanceof Input\AbstractInputType ? $a->name() - : count($this->arguments) + : $argumentCount ] = $token; + $argumentCount++; break; } $it->next(); diff --git a/src/Input/InputCollection.php b/src/Input/InputCollection.php index ddf99ba..d307217 100644 --- a/src/Input/InputCollection.php +++ b/src/Input/InputCollection.php @@ -6,8 +6,7 @@ namespace pointybeard\Helpers\Cli\Input; class InputCollection { - private $arguments = []; - private $options = []; + private $items = []; // Prevents the class from being instanciated public function __construct() @@ -17,96 +16,77 @@ class InputCollection public function append(Interfaces\InputTypeInterface $input, bool $replace = false): self { $class = new \ReflectionClass($input); - $this->{'append'.$class->getShortName()}($input, $replace); + + $index = null; + $type = null; + + if (!$replace && null !== $this->find($input->name(), null, null, $index, $type)) { + throw new \Exception("{$class->getShortName()} '{$input->name()}' already exists in this collection"); + } + + if (true == $replace && null !== $index) { + $this->items[$class->getShortName()][$index] = $argument; + } else { + $this->items[$class->getShortName()][] = $input; + } return $this; } - public function findArgument(string $name, ?int &$index = null): ?AbstractInputType + public function find(string $name, array $restrictToType=null, array $excludeType=null, &$type = null, &$index = null): ?AbstractInputType { - foreach ($this->arguments as $index => $a) { - if ($a->name() == $name) { - return $a; + foreach($this->items as $type => $items) { + + // Check if we're restricting to or excluding specific types + if(null !== $restrictToType && !in_array($type, $restrictToType)) { + continue; + + } elseif(null !== $excludeType && in_array($type, $excludeType)) { + continue; + } + + foreach($items as $index => $item) { + if($item->respondsTo($name)) { + return $item; + } } } - + $type = null; $index = null; - return null; } - public function findOption(string $name, ?int &$index = null): ?AbstractInputType - { - $type = 1 == strlen($name) ? 'name' : 'long'; - - foreach ($this->options as $index => $o) { - if ($o->$type() == $name) { - return $o; - } - } - - $index = null; - - return null; + public function getTypes(): array { + return array_keys($this->items); } - private function appendArgument(Interfaces\InputTypeInterface $argument, bool $replace = false): void - { - if (null !== $this->findArgument($argument->name(), $index) && !$replace) { - throw new \Exception("Argument {$argument->name()} already exists in collection"); - } - - if (true == $replace && null !== $index) { - $this->arguments[$index] = $argument; - } else { - $this->arguments[] = $argument; - } + public function getItems(): array { + return $this->items; } - private function appendOption(Interfaces\InputTypeInterface $option, bool $replace = false): void - { - if (null !== $this->findOption($option->name(), $index) && !$replace) { - throw new \Exception("Option -{$option->name()} already exists in collection"); - } - if (true == $replace && null !== $index) { - $this->options[$index] = $option; - } else { - $this->options[] = $option; - } + public function getItemsByType(string $type): array { + return $this->items[$type] ?? []; } - public function getArgumentsByIndex(int $index): ?AbstractInputType - { - return $this->arguments[$index] ?? null; - } - - public function getArguments(): array - { - return $this->arguments; - } - - public function getOptions(): array - { - return $this->options; + public function getItemByIndex(string $type, int $index): ?AbstractInputType { + return $this->items[$type][$index] ?? null; } public static function merge(self ...$collections): self { - $arguments = []; - $options = []; + $items = []; foreach ($collections as $c) { - $arguments = array_merge($arguments, $c->getArguments()); - $options = array_merge($options, $c->getOptions()); + foreach($c->items() as $type => $items) { + foreach($items as $item) { + $items[] = $item; + } + } } $mergedCollection = new self(); - $it = new \AppendIterator(); - $it->append(new \ArrayIterator($arguments)); - $it->append(new \ArrayIterator($options)); - - foreach ($it as $input) { + foreach ($items as $input) { try { $mergedCollection->append($input, true); } catch (\Exception $ex) { diff --git a/src/Input/InputTypeFactory.php b/src/Input/InputTypeFactory.php new file mode 100644 index 0000000..6d942dc --- /dev/null +++ b/src/Input/InputTypeFactory.php @@ -0,0 +1,23 @@ + Date: Fri, 24 May 2019 17:20:50 +1000 Subject: [PATCH 10/39] Updated README, CHANGELOG, example code, and composer.json for 1.1.0 --- CHANGELOG.md | 17 +++++- README.md | 6 +-- composer.json | 2 +- example/example.php | 124 ++++++++++++++++++++++++++------------------ 4 files changed, 93 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98c1193..d1fac78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.1.0][] +#### Added +- Expanded input types to include `Flag`, `IncrementingFlag`, and `LongOption`. +- Added `InputTypeFactory` to help with loading input type classes + +#### Changed +- Updated to work with more than just `Argument` and `Option` input types. Makes use of `InputTypeFactory` to allow addition of new types as needed. + +## [1.0.2][] +#### Changed +- Updated example to reflect changes to `manpage()` function in `pointybeard/helpers-functions-cli` package +- Refactoring and improvemnts to `Argument::__toString()` and `Option::__toString()` + ## [1.0.2][] #### Fixed - Fixed `InputCollection::getArgumentsByIndex()` so it returns NULL if the index does not exist instead of throwing an E_NOTICE message @@ -17,6 +30,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.2...integration +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.0...integration +[1.1.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.3...1.1.0 +[1.0.3]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.0...1.0.1 diff --git a/README.md b/README.md index ee87be8..5a592d4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.0.3 +- Version: v1.1.0 - Date: May 24 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) @@ -9,7 +9,7 @@ Collection of classes for handling argv (and other) input when calling command-l ## Installation -This library is installed via [Composer](http://getcomposer.org/). To install, use `composer require pointybeard/helpers-cli-input` or add `"pointybeard/helpers-cli-input": "~1.0"` to your `composer.json` file. +This library is installed via [Composer](http://getcomposer.org/). To install, use `composer require pointybeard/helpers-cli-input` or add `"pointybeard/helpers-cli-input": "~1.1"` to your `composer.json` file. And run composer to update your dependencies: @@ -26,7 +26,7 @@ To include all the [PHP Helpers](https://github.com/pointybeard/helpers) package Include this library in your PHP files with `use pointybeard\Helpers\Cli`. See example code in `example/example.php`. The example code can be run with the following command: - php -f example/example.php -- -vvv -d example/example.json import + php -f example/example.php -- -vvvs -d example/example.json import ## Support diff --git a/composer.json b/composer.json index a9f6972..b88f0d1 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.0.3", + "version": "1.1.0", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", diff --git a/example/example.php b/example/example.php index 6af92e1..f0b0002 100644 --- a/example/example.php +++ b/example/example.php @@ -9,47 +9,60 @@ use pointybeard\Helpers\Functions\Cli; // Define what we are expecting to get from the command line $collection = (new Input\InputCollection()) - ->append(new Input\Types\Argument( - 'action', - Input\AbstractInputType::FLAG_REQUIRED, - 'The name of the action to perform' - )) - ->append(new Input\Types\Option( - 'v', - null, - Input\AbstractInputType::FLAG_OPTIONAL | Input\AbstractInputType::FLAG_TYPE_INCREMENTING, - 'verbosity level. -v (errors only), -vv (warnings and errors), -vvv (everything).', - null, - 0 - )) - ->append(new Input\Types\Option( - 'd', - 'data', - Input\AbstractInputType::FLAG_OPTIONAL | Input\AbstractInputType::FLAG_VALUE_REQUIRED, - 'Path to the input JSON data', - function (Input\AbstractInputType $input, Input\AbstractInputHandler $context) { - // Make sure -d (--data) is a valid file that can be read - $file = $context->getOption('d'); + ->append( + Input\InputTypeFactory::build('Argument') + ->name('action') + ->flags(Input\AbstractInputType::FLAG_REQUIRED) + ->description('The name of the action to perform') + ) + ->append( + Input\InputTypeFactory::build('IncrementingFlag') + ->name('v') + ->flags(Input\AbstractInputType::FLAG_OPTIONAL | Input\AbstractInputType::FLAG_TYPE_INCREMENTING) + ->description('verbosity level. -v (errors only), -vv (warnings and errors), -vvv (everything).') + ->validator(new Input\Validator( + function (Input\AbstractInputType $input, Input\AbstractInputHandler $context) { + // Make sure verbosity level never goes above 3 + return min(3, (int)$context->find('v')); + } + )) + ) + ->append( + Input\InputTypeFactory::build('LongOption') + ->name('data') + ->short('d') + ->flags(Input\AbstractInputType::FLAG_OPTIONAL | Input\AbstractInputType::FLAG_VALUE_REQUIRED) + ->description('Path to the input JSON data') + ->validator(new Input\Validator( + function (Input\AbstractInputType $input, Input\AbstractInputHandler $context) { + // Make sure -d (--data) is a valid file that can be read + $file = $context->find('data'); - if (!is_readable($file)) { - throw new \Exception('The file specified via option -d (--data) does not exist or is not readable.'); - } + if (!is_readable($file)) { + throw new \Exception('The file specified via option --data does not exist or is not readable.'); + } - // Now make sure it is valid JSON - try { - $json = json_decode(file_get_contents($file), false, 512, JSON_THROW_ON_ERROR); - } catch (JsonException $ex) { - throw new \Exception(sprintf('The file specified via option -d (--data) does not appear to be a valid JSON ddocument. Returned: %s: %s', $ex->getCode(), $ex->getMessage())); - } + // Now make sure it is valid JSON + try { + $json = json_decode(file_get_contents($file), false, 512, JSON_THROW_ON_ERROR); + } catch (JsonException $ex) { + throw new \Exception(sprintf('The file specified via option --data does not appear to be a valid JSON ddocument. Returned: %s: %s', $ex->getCode(), $ex->getMessage())); + } - return $json; - } - )) + return $json; + } + )) + ) ; // Get the supplied input. Passing the collection will make the handler bind values // and validate the input according to our collection -$argv = Input\InputHandlerFactory::build('Argv', $collection); +try{ + $argv = Input\InputHandlerFactory::build('Argv', $collection); +} catch(\Exception $ex) { + echo "Error when attempting to bind values to collection. Returned: " . $ex->getMessage() . PHP_EOL; + exit; +} // Display the manual in green text echo Cli\manpage( @@ -77,24 +90,33 @@ echo Cli\manpage( // -d, --data=VALUE Path to the input JSON data // // Examples: -// php -f example/example.php -- -vvv -d example/example.json import +// php -f example/example.php -- -vvvs -d example/example.json import -var_dump($argv->getArgument('action')); -// string(6) "import" +try{ -var_dump($argv->getOption('v')); -//int(3) + var_dump($argv->find('action')); + // string(6) "import" -var_dump($argv->getOption('s')); -//bool(true) + var_dump($argv->find('v')); + //int(3) -var_dump($argv->getOption('d')); -// class stdClass#11 (1) { -// public $fruit => -// array(2) { -// [0] => -// string(5) "apple" -// [1] => -// string(6) "banana" -// } -// } + var_dump($argv->find('s')); + //bool(true) + + var_dump($argv->find('data')); + // class stdClass#11 (1) { + // public $fruit => + // array(2) { + // [0] => + // string(5) "apple" + // [1] => + // string(6) "banana" + // } + // } + + var_dump($argv->find('nope-doesnt-exist')); + +} catch(\Exception $ex) { + echo "Error: " . $ex->getMessage() . PHP_EOL; +} +//Error trying to access input. Returned: Input nope-doesnt-exist could not be found. From 96bf279a700381887c50ca61edeb29a1acfef6a0 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 18:04:00 +1000 Subject: [PATCH 11/39] AbstractInputHandler::find() returns NULL if it cannot find any input with the supplied name. It is easier to test for NULL than it is to catch an exception. --- src/Input/AbstractInputHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Input/AbstractInputHandler.php b/src/Input/AbstractInputHandler.php index 89d4c00..4861a68 100644 --- a/src/Input/AbstractInputHandler.php +++ b/src/Input/AbstractInputHandler.php @@ -85,7 +85,7 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface } } - throw new Exceptions\InputNotFoundException($name); + return null; } public function getInput(): array From b89f2a60084f2ba4601414f343294bd87a233c40 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Fri, 24 May 2019 18:06:57 +1000 Subject: [PATCH 12/39] Updated README, CHANGELOG, example/example.php, and composer.json for 1.1.1 release --- CHANGELOG.md | 7 ++++++- README.md | 2 +- composer.json | 2 +- example/example.php | 41 ++++++++++++++++++----------------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1fac78..62f9b4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.1.1][] +#### Changed +- `AbstractInputHandler::find()` returns NULL if it cannot find any input with the supplied name. It is easier to test for NULL than it is to catch an exception. + ## [1.1.0][] #### Added - Expanded input types to include `Flag`, `IncrementingFlag`, and `LongOption`. @@ -30,7 +34,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.0...integration +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.1...integration +[1.1.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.3...1.1.0 [1.0.3]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.1...1.0.2 diff --git a/README.md b/README.md index 5a592d4..9d398ef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.1.0 +- Version: v1.1.1 - Date: May 24 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index b88f0d1..14a54f0 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.1.0", + "version": "1.1.1", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", diff --git a/example/example.php b/example/example.php index f0b0002..6f2ac71 100644 --- a/example/example.php +++ b/example/example.php @@ -92,31 +92,26 @@ echo Cli\manpage( // Examples: // php -f example/example.php -- -vvvs -d example/example.json import -try{ - var_dump($argv->find('action')); - // string(6) "import" +var_dump($argv->find('action')); +// string(6) "import" - var_dump($argv->find('v')); - //int(3) +var_dump($argv->find('v')); +//int(3) - var_dump($argv->find('s')); - //bool(true) +var_dump($argv->find('s')); +//bool(true) - var_dump($argv->find('data')); - // class stdClass#11 (1) { - // public $fruit => - // array(2) { - // [0] => - // string(5) "apple" - // [1] => - // string(6) "banana" - // } - // } +var_dump($argv->find('data')); +// class stdClass#11 (1) { +// public $fruit => +// array(2) { +// [0] => +// string(5) "apple" +// [1] => +// string(6) "banana" +// } +// } - var_dump($argv->find('nope-doesnt-exist')); - -} catch(\Exception $ex) { - echo "Error: " . $ex->getMessage() . PHP_EOL; -} -//Error trying to access input. Returned: Input nope-doesnt-exist could not be found. +var_dump($argv->find('nope-doesnt-exist')); +// NULL From 4117ed266c72d408442846e978d7722d3577bd89 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 11:56:47 +1000 Subject: [PATCH 13/39] Added getDisplayName() method to standardise how the name of an InputTypeInterface class wants to display it's name --- src/Input/Interfaces/InputTypeInterface.php | 2 ++ src/Input/Types/Argument.php | 8 ++++++-- src/Input/Types/LongOption.php | 20 ++++++++++++++------ src/Input/Types/Option.php | 10 ++++++---- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Input/Interfaces/InputTypeInterface.php b/src/Input/Interfaces/InputTypeInterface.php index e61d304..92efb34 100644 --- a/src/Input/Interfaces/InputTypeInterface.php +++ b/src/Input/Interfaces/InputTypeInterface.php @@ -17,4 +17,6 @@ interface InputTypeInterface public function getType(): string; public function respondsTo(string $name): bool; + public function __toString(): string; + public function getDisplayName(): string; } diff --git a/src/Input/Types/Argument.php b/src/Input/Types/Argument.php index 3ada5b9..21a9a5d 100644 --- a/src/Input/Types/Argument.php +++ b/src/Input/Types/Argument.php @@ -25,7 +25,11 @@ class Argument extends Input\AbstractInputType parent::__construct($name, $flags, $description, $validator, $default); } - public function __toString() + public function getDisplayName(): string { + return strtoupper($this->name()); + } + + public function __toString(): string { // MAGIC VALUES!!! OH MY..... $padCharacter = ' '; @@ -53,7 +57,7 @@ class Argument extends Input\AbstractInputType ); $first = Strings\mb_str_pad( - strtoupper($this->name()).str_repeat($padCharacter, $argumentNameMinimumPaddingWidth), + $this->getDisplayName().str_repeat($padCharacter, $argumentNameMinimumPaddingWidth), $argumentNamePaddedWidth, $padCharacter ); diff --git a/src/Input/Types/LongOption.php b/src/Input/Types/LongOption.php index 8aae031..7d9af5b 100644 --- a/src/Input/Types/LongOption.php +++ b/src/Input/Types/LongOption.php @@ -24,7 +24,18 @@ class LongOption extends Input\AbstractInputType return ($name == $this->name || $name == $this->short); } - public function __toString() + public function getDisplayName(): string { + + $short = + null !== $this->short() + ? '-'.$this->short().', ' + : null + ; + + return sprintf("%s--%s", $short, $this->name()); + } + + public function __toString(): string { // MAGIC VALUES!!! OH MY..... $padCharacter = ' '; @@ -51,10 +62,7 @@ class LongOption extends Input\AbstractInputType STR_PAD_LEFT ); - $short = null !== $this->short() ? '-'.$this->short() : null; - $long = null; - - $long = '--'.$this->name(); + $long = $this->getDisplayName(); if (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_REQUIRED)) { $long .= '=VALUE'; } elseif (Flags\is_flag_set($this->flags(), self::FLAG_VALUE_OPTIONAL)) { @@ -62,7 +70,7 @@ class LongOption extends Input\AbstractInputType } $first = Strings\mb_str_pad( - (null !== $short ? "{$short}, " : '').$long, // -O, --LONG, + $long, // -O, --LONG, $optionNamePaddedWidth, $padCharacter ); diff --git a/src/Input/Types/Option.php b/src/Input/Types/Option.php index 951caf4..2a193e3 100644 --- a/src/Input/Types/Option.php +++ b/src/Input/Types/Option.php @@ -11,7 +11,11 @@ use pointybeard\Helpers\Cli\Input; class Option extends Input\AbstractInputType { - public function __toString() + public function getDisplayName(): string { + return '-'.$this->name(); + } + + public function __toString(): string { // MAGIC VALUES!!! OH MY..... $padCharacter = ' '; @@ -38,10 +42,8 @@ class Option extends Input\AbstractInputType STR_PAD_LEFT ); - $short = '-'.$this->name(); - $first = Strings\mb_str_pad( - $short, + $this->getDisplayName(), $optionNamePaddedWidth, $padCharacter ); From e71ea40616665be80f22955a2f41fcd112b52dd5 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 11:57:16 +1000 Subject: [PATCH 14/39] Removed unused RequiredArgumentMissingException exception --- .../RequiredArgumentMissingException.php | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/Input/Exceptions/RequiredArgumentMissingException.php diff --git a/src/Input/Exceptions/RequiredArgumentMissingException.php b/src/Input/Exceptions/RequiredArgumentMissingException.php deleted file mode 100644 index d2f6c7a..0000000 --- a/src/Input/Exceptions/RequiredArgumentMissingException.php +++ /dev/null @@ -1,22 +0,0 @@ -argument = strtoupper($argument); - - return parent::__construct("missing argument {$this->argument}.", $code, $previous); - } - - public function getArgumentName(): string - { - return $this->argument; - } -} From 50e56a86492bb837c52010a8696530aa584c4c60 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 11:57:32 +1000 Subject: [PATCH 15/39] Added InputValidationFailedException exception --- .../Exceptions/InputValidationFailedException.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/Input/Exceptions/InputValidationFailedException.php diff --git a/src/Input/Exceptions/InputValidationFailedException.php b/src/Input/Exceptions/InputValidationFailedException.php new file mode 100644 index 0000000..fe3fe81 --- /dev/null +++ b/src/Input/Exceptions/InputValidationFailedException.php @@ -0,0 +1,14 @@ +getDisplayName(), $previous->getMessage()), $code, $previous); + } +} From c5aa26b19db7a13c3e0c6314637c193d0f14bcfd Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 11:58:33 +1000 Subject: [PATCH 16/39] Updated RequiredInputMissingException and RequiredInputMissingValueException exceptions to use getDisplayName() when producing their message --- src/Input/Exceptions/RequiredInputMissingException.php | 6 ++---- .../Exceptions/RequiredInputMissingValueException.php | 7 +++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Input/Exceptions/RequiredInputMissingException.php b/src/Input/Exceptions/RequiredInputMissingException.php index c13bfd4..d7c4b43 100644 --- a/src/Input/Exceptions/RequiredInputMissingException.php +++ b/src/Input/Exceptions/RequiredInputMissingException.php @@ -15,10 +15,8 @@ class RequiredInputMissingException extends \Exception $this->input = $input; return parent::__construct(sprintf( - 'missing %s %s%s', - $input->getType(), - 'option' == $input->getType() ? '-' : '', - 'option' == $input->getType() ? $input->name() : strtoupper($input->name()) + 'missing %s', + $input->getDisplayName() ), $code, $previous); } diff --git a/src/Input/Exceptions/RequiredInputMissingValueException.php b/src/Input/Exceptions/RequiredInputMissingValueException.php index b04c292..03f97a8 100644 --- a/src/Input/Exceptions/RequiredInputMissingValueException.php +++ b/src/Input/Exceptions/RequiredInputMissingValueException.php @@ -15,11 +15,10 @@ class RequiredInputMissingValueException extends \Exception $this->input = $input; return parent::__construct(sprintf( - '%s %s%s is missing a value', - $input->getType(), - 'option' == $input->getType() ? '-' : '', - 'option' == $input->getType() ? $input->name() : strtoupper($input->name()) + 'a value is required for %s', + $input->getDisplayName() ), $code, $previous); + } public function getInput(): Input\AbstractInputType From 695b4ac75a8f0bf3dbdeecd38305f68ce1f403c6 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 11:59:29 +1000 Subject: [PATCH 17/39] Updated validation logic for inputs that have a validator, no default, and are not set. Using InputValidationFailedException exception when validation fails --- src/Input/AbstractInputHandler.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Input/AbstractInputHandler.php b/src/Input/AbstractInputHandler.php index 4861a68..cb1a799 100644 --- a/src/Input/AbstractInputHandler.php +++ b/src/Input/AbstractInputHandler.php @@ -45,13 +45,17 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface foreach($items as $input) { self::checkRequiredAndRequiredValue($input, $this->input); + // There is a default value, input has not been set, and there + // is no validator if( null !== $input->default() && null === $this->find($input->name()) && null === $input->validator() ) { $result = $input->default(); - } elseif(null !== $input->validator()) { + + // Input has been set and it has a validator + } elseif(null !== $this->find($input->name()) && null !== $input->validator()) { $validator = $input->validator(); if ($validator instanceof \Closure) { @@ -60,7 +64,13 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface throw new \Exception("Validator for '{$input->name()}' must be NULL or an instance of either Closure or Input\Validator."); } - $result = $validator->validate($input, $this); + try { + $result = $validator->validate($input, $this); + } catch(\Exception $ex) { + throw new Exceptions\InputValidationFailedException($input, 0, $ex); + } + + // No default, no validator, but may or may not have been set } else { $result = $this->find($input->name()); } From 32ed646220d72dea858850a785d429aa512a8860 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 12:02:35 +1000 Subject: [PATCH 18/39] Updated README, CHANGELOG, and compose.json for 1.1.2 release --- CHANGELOG.md | 14 +++++++++++++- README.md | 4 ++-- composer.json | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f9b4b..9a53497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.1.2][] +#### Added +- Added `InputValidationFailedException` exception +- Added `InputTypeInterface::getDisplayName()` method to standardise how the name of an `InputTypeInterface` class wants to display it's name + +#### Changed +- Updated validation logic for inputs that have a validator, no default, and are not set. +- Throwing `InputValidationFailedException` exception when validation fails +- Updated `RequiredInputMissingException` and `RequiredInputMissingValueException` exceptions to use `InputTypeInterface::getDisplayName()` when producing their message +- Removed unused `RequiredArgumentMissingException` exception + ## [1.1.1][] #### Changed - `AbstractInputHandler::find()` returns NULL if it cannot find any input with the supplied name. It is easier to test for NULL than it is to catch an exception. @@ -34,7 +45,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.1...integration +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...integration +[1.1.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.1...1.1.2 [1.1.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.3...1.1.0 [1.0.3]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.2...1.0.3 diff --git a/README.md b/README.md index 9d398ef..d76ca83 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.1.1 -- Date: May 24 2019 +- Version: v1.1.2 +- Date: May 25 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index 14a54f0..b7cf29b 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.1.1", + "version": "1.1.2", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", From 866a2e1c9e57d7eebaae68819a5f4da3c3f7e109 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 27 May 2019 00:22:01 +1000 Subject: [PATCH 19/39] Fixed logic bug that prevented $index and $type from getting set when InputCollection::append() is called. --- src/Input/InputCollection.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Input/InputCollection.php b/src/Input/InputCollection.php index d307217..bf45252 100644 --- a/src/Input/InputCollection.php +++ b/src/Input/InputCollection.php @@ -17,15 +17,12 @@ class InputCollection { $class = new \ReflectionClass($input); - $index = null; - $type = null; - - if (!$replace && null !== $this->find($input->name(), null, null, $index, $type)) { + if (null !== $this->find($input->name(), null, null, $type, $index) && !$replace) { throw new \Exception("{$class->getShortName()} '{$input->name()}' already exists in this collection"); } if (true == $replace && null !== $index) { - $this->items[$class->getShortName()][$index] = $argument; + $this->items[$class->getShortName()][$index] = $input; } else { $this->items[$class->getShortName()][] = $input; } From 419a4a9f7934c76ed3fa07070ec5fb10cfa9ac51 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 27 May 2019 00:22:25 +1000 Subject: [PATCH 20/39] Code tidy --- example/example.php | 11 +++---- src/Input/AbstractInputHandler.php | 18 +++++------ src/Input/AbstractInputType.php | 4 +-- .../InputValidationFailedException.php | 3 +- .../RequiredInputMissingValueException.php | 1 - src/Input/Handlers/Argv.php | 2 +- src/Input/InputCollection.php | 31 ++++++++++--------- src/Input/InputTypeFactory.php | 3 +- src/Input/Interfaces/InputTypeInterface.php | 3 ++ src/Input/Types/Argument.php | 8 ++--- src/Input/Types/Flag.php | 7 ++--- src/Input/Types/IncrementingFlag.php | 5 +-- src/Input/Types/LongOption.php | 8 ++--- src/Input/Types/Option.php | 4 +-- 14 files changed, 53 insertions(+), 55 deletions(-) diff --git a/example/example.php b/example/example.php index 6f2ac71..77feffa 100644 --- a/example/example.php +++ b/example/example.php @@ -23,7 +23,7 @@ $collection = (new Input\InputCollection()) ->validator(new Input\Validator( function (Input\AbstractInputType $input, Input\AbstractInputHandler $context) { // Make sure verbosity level never goes above 3 - return min(3, (int)$context->find('v')); + return min(3, (int) $context->find('v')); } )) ) @@ -57,10 +57,10 @@ $collection = (new Input\InputCollection()) // Get the supplied input. Passing the collection will make the handler bind values // and validate the input according to our collection -try{ +try { $argv = Input\InputHandlerFactory::build('Argv', $collection); -} catch(\Exception $ex) { - echo "Error when attempting to bind values to collection. Returned: " . $ex->getMessage() . PHP_EOL; +} catch (\Exception $ex) { + echo 'Error when attempting to bind values to collection. Returned: '.$ex->getMessage().PHP_EOL; exit; } @@ -73,7 +73,7 @@ echo Cli\manpage( Colour::FG_GREEN, Colour::FG_WHITE, [ - 'Examples' => 'php -f example/example.php -- -vvv -d example/example.json import' + 'Examples' => 'php -f example/example.php -- -vvv -d example/example.json import', ] ).PHP_EOL.PHP_EOL; @@ -92,7 +92,6 @@ echo Cli\manpage( // Examples: // php -f example/example.php -- -vvvs -d example/example.json import - var_dump($argv->find('action')); // string(6) "import" diff --git a/src/Input/AbstractInputHandler.php b/src/Input/AbstractInputHandler.php index cb1a799..65dbeac 100644 --- a/src/Input/AbstractInputHandler.php +++ b/src/Input/AbstractInputHandler.php @@ -42,12 +42,12 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface public function validate(): void { foreach ($this->collection->getItems() as $type => $items) { - foreach($items as $input) { + foreach ($items as $input) { self::checkRequiredAndRequiredValue($input, $this->input); // There is a default value, input has not been set, and there // is no validator - if( + if ( null !== $input->default() && null === $this->find($input->name()) && null === $input->validator() @@ -55,7 +55,7 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface $result = $input->default(); // Input has been set and it has a validator - } elseif(null !== $this->find($input->name()) && null !== $input->validator()) { + } elseif (null !== $this->find($input->name()) && null !== $input->validator()) { $validator = $input->validator(); if ($validator instanceof \Closure) { @@ -66,11 +66,11 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface try { $result = $validator->validate($input, $this); - } catch(\Exception $ex) { + } catch (\Exception $ex) { throw new Exceptions\InputValidationFailedException($input, 0, $ex); } - // No default, no validator, but may or may not have been set + // No default, no validator, but may or may not have been set } else { $result = $this->find($input->name()); } @@ -82,14 +82,14 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface public function find(string $name) { - if(isset($this->input[$name])) { + if (isset($this->input[$name])) { return $this->input[$name]; } // Check the collection to see if anything responds to $name - foreach($this->collection->getItems() as $type => $items) { - foreach($items as $ii) { - if($ii->respondsTo($name) && isset($this->input[$ii->name()])) { + foreach ($this->collection->getItems() as $type => $items) { + foreach ($items as $ii) { + if ($ii->respondsTo($name) && isset($this->input[$ii->name()])) { return $this->input[$ii->name()]; } } diff --git a/src/Input/AbstractInputType.php b/src/Input/AbstractInputType.php index be3999c..0d5f1af 100644 --- a/src/Input/AbstractInputType.php +++ b/src/Input/AbstractInputType.php @@ -25,7 +25,7 @@ abstract class AbstractInputType implements Interfaces\InputTypeInterface $this->default = $default; } - public function __call($name, array $args=[]) + public function __call($name, array $args = []) { if (empty($args)) { return $this->$name; @@ -43,7 +43,7 @@ abstract class AbstractInputType implements Interfaces\InputTypeInterface public function respondsTo(string $name): bool { - return ($name == $this->name); + return $name == $this->name; } public function getType(): string diff --git a/src/Input/Exceptions/InputValidationFailedException.php b/src/Input/Exceptions/InputValidationFailedException.php index fe3fe81..6c3414c 100644 --- a/src/Input/Exceptions/InputValidationFailedException.php +++ b/src/Input/Exceptions/InputValidationFailedException.php @@ -3,12 +3,13 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input\Exceptions; + use pointybeard\Helpers\Cli\Input\AbstractInputType; class InputValidationFailedException extends \Exception { public function __construct(AbstractInputType $input, $code = 0, \Exception $previous = null) { - return parent::__construct(sprintf("Validation failed for %s. Returned: %s", $input->getDisplayName(), $previous->getMessage()), $code, $previous); + return parent::__construct(sprintf('Validation failed for %s. Returned: %s', $input->getDisplayName(), $previous->getMessage()), $code, $previous); } } diff --git a/src/Input/Exceptions/RequiredInputMissingValueException.php b/src/Input/Exceptions/RequiredInputMissingValueException.php index 03f97a8..62be79b 100644 --- a/src/Input/Exceptions/RequiredInputMissingValueException.php +++ b/src/Input/Exceptions/RequiredInputMissingValueException.php @@ -18,7 +18,6 @@ class RequiredInputMissingValueException extends \Exception 'a value is required for %s', $input->getDisplayName() ), $code, $previous); - } public function getInput(): Input\AbstractInputType diff --git a/src/Input/Handlers/Argv.php b/src/Input/Handlers/Argv.php index 536284c..e97bea9 100644 --- a/src/Input/Handlers/Argv.php +++ b/src/Input/Handlers/Argv.php @@ -148,7 +148,7 @@ class Argv extends Input\AbstractInputHandler ? $a->name() : $argumentCount ] = $token; - $argumentCount++; + ++$argumentCount; break; } $it->next(); diff --git a/src/Input/InputCollection.php b/src/Input/InputCollection.php index bf45252..744de0b 100644 --- a/src/Input/InputCollection.php +++ b/src/Input/InputCollection.php @@ -30,42 +30,45 @@ class InputCollection return $this; } - public function find(string $name, array $restrictToType=null, array $excludeType=null, &$type = null, &$index = null): ?AbstractInputType + public function find(string $name, array $restrictToType = null, array $excludeType = null, &$type = null, &$index = null): ?AbstractInputType { - foreach($this->items as $type => $items) { - + foreach ($this->items as $type => $items) { // Check if we're restricting to or excluding specific types - if(null !== $restrictToType && !in_array($type, $restrictToType)) { + if (null !== $restrictToType && !in_array($type, $restrictToType)) { continue; - - } elseif(null !== $excludeType && in_array($type, $excludeType)) { + } elseif (null !== $excludeType && in_array($type, $excludeType)) { continue; } - foreach($items as $index => $item) { - if($item->respondsTo($name)) { + foreach ($items as $index => $item) { + if ($item->respondsTo($name)) { return $item; } } } $type = null; $index = null; + return null; } - public function getTypes(): array { + public function getTypes(): array + { return array_keys($this->items); } - public function getItems(): array { + public function getItems(): array + { return $this->items; } - public function getItemsByType(string $type): array { + public function getItemsByType(string $type): array + { return $this->items[$type] ?? []; } - public function getItemByIndex(string $type, int $index): ?AbstractInputType { + public function getItemByIndex(string $type, int $index): ?AbstractInputType + { return $this->items[$type][$index] ?? null; } @@ -74,8 +77,8 @@ class InputCollection $items = []; foreach ($collections as $c) { - foreach($c->items() as $type => $items) { - foreach($items as $item) { + foreach ($c->items() as $type => $items) { + foreach ($items as $item) { $items[] = $item; } } diff --git a/src/Input/InputTypeFactory.php b/src/Input/InputTypeFactory.php index 6d942dc..dda8115 100644 --- a/src/Input/InputTypeFactory.php +++ b/src/Input/InputTypeFactory.php @@ -4,13 +4,12 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input; -use pointybeard\Helpers\Functions\Flags; use pointybeard\Helpers\Foundation\Factory; final class InputTypeFactory extends Factory\AbstractFactory { use Factory\Traits\hasSimpleFactoryBuildMethodTrait; - + public static function getTemplateNamespace(): string { return __NAMESPACE__.'\\Types\\%s'; diff --git a/src/Input/Interfaces/InputTypeInterface.php b/src/Input/Interfaces/InputTypeInterface.php index 92efb34..3a6bc13 100644 --- a/src/Input/Interfaces/InputTypeInterface.php +++ b/src/Input/Interfaces/InputTypeInterface.php @@ -16,7 +16,10 @@ interface InputTypeInterface const FLAG_TYPE_INCREMENTING = 0x0400; public function getType(): string; + public function respondsTo(string $name): bool; + public function __toString(): string; + public function getDisplayName(): string; } diff --git a/src/Input/Types/Argument.php b/src/Input/Types/Argument.php index 21a9a5d..52faec1 100644 --- a/src/Input/Types/Argument.php +++ b/src/Input/Types/Argument.php @@ -10,10 +10,9 @@ use pointybeard\Helpers\Functions\Cli; class Argument extends Input\AbstractInputType { - - public function __construct(string $name = null, int $flags = null, string $description = null, object $validator = null, $default=null) + public function __construct(string $name = null, int $flags = null, string $description = null, object $validator = null, $default = null) { - if(null === $validator) { + if (null === $validator) { $validator = function (Input\AbstractInputType $input, Input\AbstractInputHandler $context) { // This dummy validator is necessary otherwise the argument // value is ALWAYS set to default (most often NULL) regardless @@ -25,7 +24,8 @@ class Argument extends Input\AbstractInputType parent::__construct($name, $flags, $description, $validator, $default); } - public function getDisplayName(): string { + public function getDisplayName(): string + { return strtoupper($this->name()); } diff --git a/src/Input/Types/Flag.php b/src/Input/Types/Flag.php index fba5f55..a3f2329 100644 --- a/src/Input/Types/Flag.php +++ b/src/Input/Types/Flag.php @@ -5,16 +5,13 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input\Types; use pointybeard\Helpers\Functions\Flags; -use pointybeard\Helpers\Functions\Strings; -use pointybeard\Helpers\Functions\Cli; -use pointybeard\Helpers\Cli\Input; class Flag extends Option { public function __construct(string $name = null, int $flags = null, string $description = null, object $validator = null, $default = false) { - if(Flags\is_flag_set($flags, self::FLAG_VALUE_REQUIRED) || Flags\is_flag_set($flags, self::FLAG_VALUE_OPTIONAL)) { - throw new \Exception("The flags FLAG_VALUE_REQUIRED and FLAG_VALUE_OPTIONAL cannot be used on an input of type Flag"); + if (Flags\is_flag_set($flags, self::FLAG_VALUE_REQUIRED) || Flags\is_flag_set($flags, self::FLAG_VALUE_OPTIONAL)) { + throw new \Exception('The flags FLAG_VALUE_REQUIRED and FLAG_VALUE_OPTIONAL cannot be used on an input of type Flag'); } parent::__construct($name, null, $flags, $description, $validator, $default); } diff --git a/src/Input/Types/IncrementingFlag.php b/src/Input/Types/IncrementingFlag.php index 33df708..8d850a1 100644 --- a/src/Input/Types/IncrementingFlag.php +++ b/src/Input/Types/IncrementingFlag.php @@ -5,15 +5,12 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input\Types; use pointybeard\Helpers\Functions\Flags; -use pointybeard\Helpers\Functions\Strings; -use pointybeard\Helpers\Functions\Cli; -use pointybeard\Helpers\Cli\Input; class IncrementingFlag extends Flag { public function __construct(string $name = null, int $flags = null, string $description = null, object $validator = null, $default = 0) { - if(Flags\is_flag_set($flags, self::FLAG_TYPE_INCREMENTING)) { + if (Flags\is_flag_set($flags, self::FLAG_TYPE_INCREMENTING)) { $flags = $flags | self::FLAG_TYPE_INCREMENTING; } parent::__construct($name, null, $flags, $description, $validator, $default); diff --git a/src/Input/Types/LongOption.php b/src/Input/Types/LongOption.php index 7d9af5b..5961768 100644 --- a/src/Input/Types/LongOption.php +++ b/src/Input/Types/LongOption.php @@ -21,18 +21,18 @@ class LongOption extends Input\AbstractInputType public function respondsTo(string $name): bool { - return ($name == $this->name || $name == $this->short); + return $name == $this->name || $name == $this->short; } - public function getDisplayName(): string { - + public function getDisplayName(): string + { $short = null !== $this->short() ? '-'.$this->short().', ' : null ; - return sprintf("%s--%s", $short, $this->name()); + return sprintf('%s--%s', $short, $this->name()); } public function __toString(): string diff --git a/src/Input/Types/Option.php b/src/Input/Types/Option.php index 2a193e3..ab081ab 100644 --- a/src/Input/Types/Option.php +++ b/src/Input/Types/Option.php @@ -4,14 +4,14 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input\Types; -use pointybeard\Helpers\Functions\Flags; use pointybeard\Helpers\Functions\Strings; use pointybeard\Helpers\Functions\Cli; use pointybeard\Helpers\Cli\Input; class Option extends Input\AbstractInputType { - public function getDisplayName(): string { + public function getDisplayName(): string + { return '-'.$this->name(); } From ad21e667c3e157fd65c73dc5861b40e80c7c3823 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 27 May 2019 00:24:35 +1000 Subject: [PATCH 21/39] Updated README, CHANGELOG, and composer.json for 1.1.3 release --- CHANGELOG.md | 7 ++++++- README.md | 4 ++-- composer.json | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a53497..eb48e7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.1.3][] +#### Fixed +- Fixed logic bug that prevented `$index` and `$type` from being set in `InputCollection::append()`. This means replaceing items in an `InputCollection` now works as expected. + ## [1.1.2][] #### Added - Added `InputValidationFailedException` exception @@ -45,7 +49,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...integration +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.3...integration +[1.1.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...1.1.3 [1.1.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.1...1.1.2 [1.1.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.3...1.1.0 diff --git a/README.md b/README.md index d76ca83..a503a5b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.1.2 -- Date: May 25 2019 +- Version: v1.1.3 +- Date: May 26 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index b7cf29b..ee51397 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.1.2", + "version": "1.1.3", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", From 900f9f28853589588ae3f80c2ad7e848150bc8ac Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 27 May 2019 00:57:09 +1000 Subject: [PATCH 22/39] Fixed misnamed variable in InputCollection::merge() --- src/Input/InputCollection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Input/InputCollection.php b/src/Input/InputCollection.php index 744de0b..1db3357 100644 --- a/src/Input/InputCollection.php +++ b/src/Input/InputCollection.php @@ -74,19 +74,19 @@ class InputCollection public static function merge(self ...$collections): self { - $items = []; + $inputs = []; foreach ($collections as $c) { - foreach ($c->items() as $type => $items) { + foreach ($c->getItems() as $type => $items) { foreach ($items as $item) { - $items[] = $item; + $inputs[] = $item; } } } $mergedCollection = new self(); - foreach ($items as $input) { + foreach ($inputs as $input) { try { $mergedCollection->append($input, true); } catch (\Exception $ex) { From 302e4378fb99518c6bdbd340122faf69a4f24a72 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Mon, 27 May 2019 00:58:51 +1000 Subject: [PATCH 23/39] Updated README, CHANGELOG, and composer.json for 1.1.4 release --- CHANGELOG.md | 9 +++++++-- README.md | 4 ++-- composer.json | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb48e7e..38999ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). **View all [Unreleased][] changes here** +## [1.1.4][] +#### Fixed +- Fixed misnamed variable in `InputCollection::merge()` + ## [1.1.3][] #### Fixed - Fixed logic bug that prevented `$index` and `$type` from being set in `InputCollection::append()`. This means replaceing items in an `InputCollection` now works as expected. @@ -49,8 +53,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.3...integration -[1.1.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...1.1.3 +[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.4...integration +[1.1.4]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.3...1.1.4 +[1.1.3]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...1.1.3 [1.1.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.1...1.1.2 [1.1.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.0.3...1.1.0 diff --git a/README.md b/README.md index a503a5b..8cc2e4b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.1.3 -- Date: May 26 2019 +- Version: v1.1.4 +- Date: May 27 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index ee51397..8604f6f 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.1.3", + "version": "1.1.4", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", From 7069019301bb110839e55b461594971bef01b011 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 15:09:02 +1000 Subject: [PATCH 24/39] Added UnrecognisedInputException exception --- src/Input/Exceptions/UnrecognisedInputException.php | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Input/Exceptions/UnrecognisedInputException.php diff --git a/src/Input/Exceptions/UnrecognisedInputException.php b/src/Input/Exceptions/UnrecognisedInputException.php new file mode 100644 index 0000000..22258f4 --- /dev/null +++ b/src/Input/Exceptions/UnrecognisedInputException.php @@ -0,0 +1,9 @@ + Date: Sat, 1 Jun 2019 22:27:18 +1000 Subject: [PATCH 25/39] Updated InputHandlerInterface bind() and validate() methods to support flags --- src/Input/Interfaces/InputHandlerInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Input/Interfaces/InputHandlerInterface.php b/src/Input/Interfaces/InputHandlerInterface.php index 87a33ac..8345b30 100644 --- a/src/Input/Interfaces/InputHandlerInterface.php +++ b/src/Input/Interfaces/InputHandlerInterface.php @@ -8,9 +8,9 @@ use pointybeard\Helpers\Cli\Input; interface InputHandlerInterface { - public function bind(Input\InputCollection $inputCollection, bool $skipValidation = false): bool; + public function bind(Input\InputCollection $inputCollection, ?int $flags = null): bool; - public function validate(): void; + public function validate(?int $flags = null): void; public function find(string $name); From 1100d5d95986545b0b1301dd374e2009484f56c3 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:28:20 +1000 Subject: [PATCH 26/39] Removed InputHandlerFactory::FLAG_SKIP_VALIDATION. Passing flags in call to bind() --- src/Input/InputHandlerFactory.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Input/InputHandlerFactory.php b/src/Input/InputHandlerFactory.php index a899812..2b06ecf 100644 --- a/src/Input/InputHandlerFactory.php +++ b/src/Input/InputHandlerFactory.php @@ -9,8 +9,6 @@ use pointybeard\Helpers\Foundation\Factory; final class InputHandlerFactory extends Factory\AbstractFactory { - const FLAG_SKIP_VALIDATION = 0x0001; - public static function getTemplateNamespace(): string { return __NAMESPACE__.'\\Handlers\\%s'; @@ -34,7 +32,7 @@ final class InputHandlerFactory extends Factory\AbstractFactory if ($collection instanceof InputCollection) { $handler->bind( $collection, - Flags\is_flag_set($flags, self::FLAG_SKIP_VALIDATION) + $flags ); } From 9f5c5c7d4dbec06f201c92a113e2c6c302883e48 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:31:59 +1000 Subject: [PATCH 27/39] Made getCollection(), getInput(), find(), and validate() in AbstractInputHandler final. Removed categorising input by type. Abstracted most of validate() into it's own protected method called validateInput(). Removed $skipValidation argument from bind() and relaced with $flags. Added FLAG_BIND_SKIP_VALIDATION, FLAG_VALIDATION_SKIP_REQUIRED, FLAG_VALIDATION_SKIP_CUSTOM, and FLAG_VALIDATION_SKIP_UNRECOGNISED flags. Added check in validate() to look for unrecognised options and arguments. --- src/Input/AbstractInputHandler.php | 131 +++++++++++++++++++---------- 1 file changed, 85 insertions(+), 46 deletions(-) diff --git a/src/Input/AbstractInputHandler.php b/src/Input/AbstractInputHandler.php index 65dbeac..97413e0 100644 --- a/src/Input/AbstractInputHandler.php +++ b/src/Input/AbstractInputHandler.php @@ -5,15 +5,40 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input; use pointybeard\Helpers\Functions\Flags; +use pointybeard\Helpers\Functions\Debug; abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface { + /** + * Will skip all validation when bind() is executed. Ignores all other flags + * @var integer + */ + const FLAG_BIND_SKIP_VALIDATION = 0x0001; + + /** + * Will skip the required input and required values check + * @var integer + */ + const FLAG_VALIDATION_SKIP_REQUIRED = 0x0002; + + /** + * Will skip running custom validators + * @var integer + */ + const FLAG_VALIDATION_SKIP_CUSTOM = 0x0004; + + /** + * Will skip checking if an input is in the collection + * @var integer + */ + const FLAG_VALIDATION_SKIP_UNRECOGNISED = 0x0008; + protected $input = []; protected $collection = null; abstract protected function parse(): bool; - public function bind(InputCollection $inputCollection, bool $skipValidation = false): bool + final public function bind(InputCollection $inputCollection, ?int $flags = null): bool { // Do the binding stuff here $this->input = []; @@ -21,8 +46,8 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface $this->parse(); - if (true !== $skipValidation) { - $this->validate(); + if (!Flags\is_flag_set($flags, self::FLAG_BIND_SKIP_VALIDATION)) { + $this->validate($flags); } return true; @@ -39,71 +64,85 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface } } - public function validate(): void - { - foreach ($this->collection->getItems() as $type => $items) { - foreach ($items as $input) { - self::checkRequiredAndRequiredValue($input, $this->input); + protected function validateInput(AbstractInputType $input, ?int $flags) { + if(!Flags\is_flag_set($flags, self::FLAG_VALIDATION_SKIP_REQUIRED)) { + self::checkRequiredAndRequiredValue($input, $this->input); + } + // There is a default value, input has not been set, and there + // is no validator + if ( + null !== $input->default() && + null === $this->find($input->name()) && + null === $input->validator() + ) { + $result = $input->default(); - // There is a default value, input has not been set, and there - // is no validator - if ( - null !== $input->default() && - null === $this->find($input->name()) && - null === $input->validator() - ) { - $result = $input->default(); + // Input has been set and it has a validator. Skip this if + // FLAG_VALIDATION_SKIP_CUSTOM is set + } elseif (null !== $this->find($input->name()) && null !== $input->validator() && !Flags\is_flag_set($flags, self::FLAG_VALIDATION_SKIP_CUSTOM)) { + $validator = $input->validator(); - // Input has been set and it has a validator - } elseif (null !== $this->find($input->name()) && null !== $input->validator()) { - $validator = $input->validator(); - - if ($validator instanceof \Closure) { - $validator = new Validator($validator); - } elseif (!($validator instanceof Validator)) { - throw new \Exception("Validator for '{$input->name()}' must be NULL or an instance of either Closure or Input\Validator."); - } - - try { - $result = $validator->validate($input, $this); - } catch (\Exception $ex) { - throw new Exceptions\InputValidationFailedException($input, 0, $ex); - } - - // No default, no validator, but may or may not have been set - } else { - $result = $this->find($input->name()); - } - - $this->input[$input->name()] = $result; + if ($validator instanceof \Closure) { + $validator = new Validator($validator); + } elseif (!($validator instanceof Validator)) { + throw new \Exception("Validator for '{$input->name()}' must be NULL or an instance of either Closure or Input\Validator."); } + + try { + $result = $validator->validate($input, $this); + } catch (\Exception $ex) { + throw new Exceptions\InputValidationFailedException($input, 0, $ex); + } + + // No default, no validator, but may or may not have been set + } else { + $result = $this->find($input->name()); + } + + return $result; + } + + protected function isInputRecognised(string $name): bool { + return null === $this->collection->find($name) ? false : true; + } + + final public function validate(?int $flags = null): void + { + if(!Flags\is_flag_set($flags, self::FLAG_VALIDATION_SKIP_UNRECOGNISED)) { + foreach($this->input as $name => $value) { + if(false == static::isInputRecognised((string)$name)) { + throw new Exceptions\UnrecognisedInputException("'{$name}' is not recognised"); + } + } + } + + foreach ($this->collection->getItems() as $input) { + $this->input[$input->name()] = static::validateInput($input, $flags); } } - public function find(string $name) + final public function find(string $name) { if (isset($this->input[$name])) { return $this->input[$name]; } // Check the collection to see if anything responds to $name - foreach ($this->collection->getItems() as $type => $items) { - foreach ($items as $ii) { - if ($ii->respondsTo($name) && isset($this->input[$ii->name()])) { - return $this->input[$ii->name()]; - } + foreach ($this->collection->getItems() as $item) { + if ($item->respondsTo($name) && isset($this->input[$item->name()])) { + return $this->input[$item->name()]; } } return null; } - public function getInput(): array + final public function getInput(): array { return $this->input; } - public function getCollection(): ?InputCollection + final public function getCollection(): ?InputCollection { return $this->collection; } From 90db5c2047898f37a92799dd6ba498c8570d59c9 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:34:32 +1000 Subject: [PATCH 28/39] Added InputTypeFilterIterator class --- src/Input/InputTypeFilterIterator.php | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/Input/InputTypeFilterIterator.php diff --git a/src/Input/InputTypeFilterIterator.php b/src/Input/InputTypeFilterIterator.php new file mode 100644 index 0000000..e46e231 --- /dev/null +++ b/src/Input/InputTypeFilterIterator.php @@ -0,0 +1,39 @@ +types = array_map('strtolower', $types); + $this->mode = $mode; + + } + public function accept() + { + $input = $this->getInnerIterator()->current(); + + switch($this->mode) { + case self::FILTER_EXCLUDE: + return !in_array($input->getType(), $this->types); + break; + + case self::FILTER_INCLUDE: + default: + return in_array($input->getType(), $this->types); + break; + + } + } +} From 05d283b6d25d6271c59a57d019242c74e42d1b9b Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:43:19 +1000 Subject: [PATCH 29/39] InputCollection now implements Iterator and Countable (implementing required methods). Removed use of $type. Added getItemsExcludeByType(). getItemsByType() and getItems() now returns an Iterator. Renamed append() to add() and added $position flag. Added POSITION_APPEND and POSITION_PREPEND flags. --- src/Input/InputCollection.php | 130 ++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 38 deletions(-) diff --git a/src/Input/InputCollection.php b/src/Input/InputCollection.php index 1db3357..49db36f 100644 --- a/src/Input/InputCollection.php +++ b/src/Input/InputCollection.php @@ -4,96 +4,150 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input; -class InputCollection +class InputCollection implements \Iterator, \Countable { private $items = []; + private $position = 0; + + public const POSITION_APPEND = 0x0001; + public const POSITION_PREPEND = 0x0002; // Prevents the class from being instanciated public function __construct() { + $this->position = 0; } - public function append(Interfaces\InputTypeInterface $input, bool $replace = false): self + public function current(): mixed { - $class = new \ReflectionClass($input); + return $this->items[$this->position]; + } - if (null !== $this->find($input->name(), null, null, $type, $index) && !$replace) { - throw new \Exception("{$class->getShortName()} '{$input->name()}' already exists in this collection"); + public function key(): scalar + { + return $this->position; + } + + public function next(): void + { + ++$this->position; + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return isset($this->items[$this->position]); + } + + public function count() : int { + return count($this->items); + } + + public function exists(string $name, &$index=null): bool { + return (null !== $this->find($name, null, null, $index)); + } + + public function remove(string $name): self { + if(!$this->exists($name, $index)) { + throw new \Exception("Input '{$name}' does not exist in this collection"); + } + unset($this->items[$index]); + return $this; + } + + public function add(Interfaces\InputTypeInterface $input, bool $replace = false, int $position=self::POSITION_APPEND): self + { + if($this->exists($input->name(), $index) && !$replace) { + throw new \Exception( + (new \ReflectionClass($input))->getShortName()." '{$input->name()}' already exists in this collection" + ); } if (true == $replace && null !== $index) { - $this->items[$class->getShortName()][$index] = $input; + $this->items[$index] = $input; } else { - $this->items[$class->getShortName()][] = $input; + if($position == self::POSITION_PREPEND) { + array_unshift($this->items, $input); + } else { + array_push($this->items, $input); + } } return $this; } - public function find(string $name, array $restrictToType = null, array $excludeType = null, &$type = null, &$index = null): ?AbstractInputType + public function find(string $name, array $restrictToType = null, array $excludeType = null, &$index = null): ?AbstractInputType { - foreach ($this->items as $type => $items) { + foreach ($this->items as $index => $input) { // Check if we're restricting to or excluding specific types - if (null !== $restrictToType && !in_array($type, $restrictToType)) { + if (null !== $restrictToType && !in_array($input->getType(), $restrictToType)) { continue; - } elseif (null !== $excludeType && in_array($type, $excludeType)) { + } elseif (null !== $excludeType && in_array($input->getType(), $excludeType)) { continue; } - foreach ($items as $index => $item) { - if ($item->respondsTo($name)) { - return $item; - } + if ($input->respondsTo($name)) { + return $input; } + } - $type = null; $index = null; - return null; } public function getTypes(): array { - return array_keys($this->items); + $types = []; + foreach($this->items as $input) { + $types[] = $input->getType(); + } + return array_unique($types); } - public function getItems(): array + public function getItems(): \Iterator { - return $this->items; + return (new \ArrayObject($this->items))->getIterator(); } - public function getItemsByType(string $type): array + public function getItemsByType(string $type): \Iterator { - return $this->items[$type] ?? []; + return new InputTypeFilterIterator( + $this->getItems(), + [$type], + InputTypeFilterIterator::FILTER_INCLUDE + ); } - public function getItemByIndex(string $type, int $index): ?AbstractInputType + public function getItemsExcludeByType(string $type): \Iterator { - return $this->items[$type][$index] ?? null; + return new InputTypeFilterIterator( + $this->getItems(), + [$type], + InputTypeFilterIterator::FILTER_EXCLUDE + ); + } + + public function getItemByIndex(int $index): ?AbstractInputType + { + return $this->items[$index] ?? null; } public static function merge(self ...$collections): self { - $inputs = []; + $iterator = new \AppendIterator; foreach ($collections as $c) { - foreach ($c->getItems() as $type => $items) { - foreach ($items as $item) { - $inputs[] = $item; - } - } + $iterator->append($c->getItems()); } $mergedCollection = new self(); - - foreach ($inputs as $input) { - try { - $mergedCollection->append($input, true); - } catch (\Exception $ex) { - // Already exists, so skip it. - } + foreach ($iterator as $input) { + $mergedCollection->add($input, true); } - return $mergedCollection; } } From f7a9b66590cdac573404b89fcb9cf3938265e4d2 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:44:09 +1000 Subject: [PATCH 30/39] Added Argv::findOptionInCollection() and Argv::findArgumentInCollection() wrapper method, which are used in Argv::parse() --- src/Input/Handlers/Argv.php | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Input/Handlers/Argv.php b/src/Input/Handlers/Argv.php index e97bea9..5b79b6c 100644 --- a/src/Input/Handlers/Argv.php +++ b/src/Input/Handlers/Argv.php @@ -3,9 +3,10 @@ declare(strict_types=1); namespace pointybeard\Helpers\Cli\Input\Handlers; - +use pointybeard\Helpers\Cli\Input\Exceptions; use pointybeard\Helpers\Cli\Input; use pointybeard\Helpers\Functions\Flags; +use pointybeard\Helpers\Functions\Debug; class Argv extends Input\AbstractInputHandler { @@ -61,9 +62,31 @@ class Argv extends Input\AbstractInputHandler return $result; } + protected function findOptionInCollection(string $name): ?Input\AbstractInputType + { + $option = $this->collection->find($name); + if(!($option instanceof Input\AbstractInputType)) { + return null; + } + + return $option; + } + + protected function findArgumentInCollection(int $index, string $token): ?Input\AbstractInputType + { + $arguments = $this->collection->getItemsByType('Argument'); + $position = 0; + foreach($arguments as $a) { + if($position == $index) { + return $a; + } + $position++; + } + return null; + } + protected function parse(): bool { - // So some parsing here. $it = new \ArrayIterator($this->argv); $position = 0; @@ -83,7 +106,7 @@ class Argv extends Input\AbstractInputHandler $value = true; } - $o = $this->collection->find($name); + $o = $this->findOptionInCollection($name); $this->input[ $o instanceof Input\AbstractInputType @@ -99,7 +122,7 @@ class Argv extends Input\AbstractInputHandler // Determine if we're expecting a value. // It also might have a long option equivalent, so we need // to look for that too. - $o = $this->collection->find($name); + $o = $this->findOptionInCollection($name); // This could also be an incrementing value // and needs to be added up. E.g. e.g. -vvv or -v -v -v @@ -142,7 +165,8 @@ class Argv extends Input\AbstractInputHandler // Arguments are positional, so we need to keep a track // of the index and look at the collection for an argument // with the same index - $a = $this->collection->getItemByIndex('Argument', $argumentCount); + $a = $this->findArgumentInCollection($argumentCount, $token); + $this->input[ $a instanceof Input\AbstractInputType ? $a->name() From 27c04d1d43855cc1a6fa20d71a820b8ba4255f84 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:49:10 +1000 Subject: [PATCH 31/39] Updated example --- example/example.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/example/example.php b/example/example.php index 77feffa..76b67e5 100644 --- a/example/example.php +++ b/example/example.php @@ -9,13 +9,13 @@ use pointybeard\Helpers\Functions\Cli; // Define what we are expecting to get from the command line $collection = (new Input\InputCollection()) - ->append( + ->add( Input\InputTypeFactory::build('Argument') ->name('action') ->flags(Input\AbstractInputType::FLAG_REQUIRED) ->description('The name of the action to perform') ) - ->append( + ->add( Input\InputTypeFactory::build('IncrementingFlag') ->name('v') ->flags(Input\AbstractInputType::FLAG_OPTIONAL | Input\AbstractInputType::FLAG_TYPE_INCREMENTING) @@ -27,7 +27,7 @@ $collection = (new Input\InputCollection()) } )) ) - ->append( + ->add( Input\InputTypeFactory::build('LongOption') ->name('data') ->short('d') @@ -90,7 +90,7 @@ echo Cli\manpage( // -d, --data=VALUE Path to the input JSON data // // Examples: -// php -f example/example.php -- -vvvs -d example/example.json import +// php -f example/example.php -- -vvv -d example/example.json import var_dump($argv->find('action')); // string(6) "import" @@ -98,9 +98,6 @@ var_dump($argv->find('action')); var_dump($argv->find('v')); //int(3) -var_dump($argv->find('s')); -//bool(true) - var_dump($argv->find('data')); // class stdClass#11 (1) { // public $fruit => From 46b87d3d62572e914b6997ee2765c5527e1e6fcf Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 22:57:42 +1000 Subject: [PATCH 32/39] Updated README, CHANGELOG, and composer.json for 1.2.0 release --- CHANGELOG.md | 34 +++++++++++++++++++++++++++------- README.md | 8 ++++---- composer.json | 12 ++++++------ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38999ce..ebd641e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,27 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -**View all [Unreleased][] changes here** +## [1.2.0][] +#### Added +- Added `InputTypeFilterIterator` class +- Added `UnrecognisedInputException` exception + +#### Changed +- `InputCollection` now implements `Iterator` and `Countable` (implementing required methods) +- Removed use of `$type` in `InputCollection` +- Added `InputCollection::getItemsExcludeByType()` +- `InputCollection::getItemsByType()` and `InputCollection::getItems()` now returns an `Iterator` +- Renamed `InputCollection::append()` to `add()` and added `$position` flag +- Added `POSITION_APPEND` and `POSITION_PREPEND` flags to `InputCollection` +- Made `getCollection()`, `getInput()`, `find()`, and `validate()` in `AbstractInputHandler` final +- Removed all categorisation of items by type in `AbstractInputHandler::$input` +- Abstracted most of `AbstractInputHandler::validate()` into it's own protected method called `validateInput()` +- Removed `$skipValidation` argument from `AbstractInputHandler::bind()` and relaced with `$flags` +- Added `FLAG_BIND_SKIP_VALIDATION`, `FLAG_VALIDATION_SKIP_REQUIRED`, `FLAG_VALIDATION_SKIP_CUSTOM`, and `FLAG_VALIDATION_SKIP_UNRECOGNISED` flags to `AbstractInputHandler` +- Added check in `AbstractInputHandler::validate()` to look for unrecognised options and arguments +- Removed `InputHandlerFactory::FLAG_SKIP_VALIDATION` from `InputHandlerFactory` +- Passing flags in call from `InputHandlerFactory::build()` to `AbstractInputHandler::bind()` +- Updated `InputHandlerInterface::bind()` and `validate()` methods to support flags ## [1.1.4][] #### Fixed @@ -11,7 +31,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [1.1.3][] #### Fixed -- Fixed logic bug that prevented `$index` and `$type` from being set in `InputCollection::append()`. This means replaceing items in an `InputCollection` now works as expected. +- Fixed logic bug that prevented `$index` and `$type` from being set in `InputCollection::append()`. This means replaceing items in an `InputCollection` now works as expected ## [1.1.2][] #### Added @@ -19,22 +39,22 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `InputTypeInterface::getDisplayName()` method to standardise how the name of an `InputTypeInterface` class wants to display it's name #### Changed -- Updated validation logic for inputs that have a validator, no default, and are not set. +- Updated validation logic for inputs that have a validator, no default, and are not set - Throwing `InputValidationFailedException` exception when validation fails - Updated `RequiredInputMissingException` and `RequiredInputMissingValueException` exceptions to use `InputTypeInterface::getDisplayName()` when producing their message - Removed unused `RequiredArgumentMissingException` exception ## [1.1.1][] #### Changed -- `AbstractInputHandler::find()` returns NULL if it cannot find any input with the supplied name. It is easier to test for NULL than it is to catch an exception. +- `AbstractInputHandler::find()` returns NULL if it cannot find any input with the supplied name. It is easier to test for NULL than it is to catch an exception ## [1.1.0][] #### Added -- Expanded input types to include `Flag`, `IncrementingFlag`, and `LongOption`. +- Expanded input types to include `Flag`, `IncrementingFlag`, and `LongOption` - Added `InputTypeFactory` to help with loading input type classes #### Changed -- Updated to work with more than just `Argument` and `Option` input types. Makes use of `InputTypeFactory` to allow addition of new types as needed. +- Updated to work with more than just `Argument` and `Option` input types. Makes use of `InputTypeFactory` to allow addition of new types as needed ## [1.0.2][] #### Changed @@ -53,7 +73,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release -[Unreleased]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.4...integration +[1.2.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.4...1.2.0 [1.1.4]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.3...1.1.4 [1.1.3]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...1.1.3 [1.1.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.1...1.1.2 diff --git a/README.md b/README.md index 8cc2e4b..e58ef69 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.1.4 -- Date: May 27 2019 +- Version: v1.2.0 +- Date: June 01 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) @@ -9,7 +9,7 @@ Collection of classes for handling argv (and other) input when calling command-l ## Installation -This library is installed via [Composer](http://getcomposer.org/). To install, use `composer require pointybeard/helpers-cli-input` or add `"pointybeard/helpers-cli-input": "~1.1"` to your `composer.json` file. +This library is installed via [Composer](http://getcomposer.org/). To install, use `composer require pointybeard/helpers-cli-input` or add `"pointybeard/helpers-cli-input": "~1.2.0"` to your `composer.json` file. And run composer to update your dependencies: @@ -26,7 +26,7 @@ To include all the [PHP Helpers](https://github.com/pointybeard/helpers) package Include this library in your PHP files with `use pointybeard\Helpers\Cli`. See example code in `example/example.php`. The example code can be run with the following command: - php -f example/example.php -- -vvvs -d example/example.json import + php -f example/example.php -- -vvv -d example/example.json import ## Support diff --git a/composer.json b/composer.json index 8604f6f..094ef88 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.1.4", + "version": "1.2.0", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", @@ -14,14 +14,14 @@ ], "require": { "php": ">=7.2", - "pointybeard/helpers-foundation-factory": "~1", - "pointybeard/helpers-functions-flags": "~1" + "pointybeard/helpers-foundation-factory": "~1.0", + "pointybeard/helpers-functions-flags": "~1.0" }, "require-dev": { "phpunit/phpunit": "^8", - "pointybeard/helpers-functions-strings": "^1", - "pointybeard/helpers-cli-colour": "^1", - "pointybeard/helpers-functions-cli": "^1" + "pointybeard/helpers-functions-strings": "~1.1.0", + "pointybeard/helpers-cli-colour": "~1.0", + "pointybeard/helpers-functions-cli": "~1.1.0" }, "support": { "issues": "https://github.com/pointybeard/helpers-cli-input/issues", From e542f6fd945c6533d6004fd77a45d7c98a13b925 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Tue, 4 Jun 2019 23:22:15 +1000 Subject: [PATCH 33/39] Updated InputHandlerFactory and InputTypeFactory to work with changes in pointybeard/helpers-foundation-factory 1.0.2 --- src/Input/InputHandlerFactory.php | 19 +++++++++++++------ src/Input/InputTypeFactory.php | 6 ++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Input/InputHandlerFactory.php b/src/Input/InputHandlerFactory.php index 2b06ecf..2ae425c 100644 --- a/src/Input/InputHandlerFactory.php +++ b/src/Input/InputHandlerFactory.php @@ -9,27 +9,34 @@ use pointybeard\Helpers\Foundation\Factory; final class InputHandlerFactory extends Factory\AbstractFactory { - public static function getTemplateNamespace(): string + public function getTemplateNamespace(): string { return __NAMESPACE__.'\\Handlers\\%s'; } - public static function getExpectedClassType(): ?string + public function getExpectedClassType(): ?string { return __NAMESPACE__.'\\Interfaces\\InputHandlerInterface'; } - public static function build(string $name, InputCollection $collection = null, int $flags = null): Interfaces\InputHandlerInterface + public static function build(string $name, ...$arguments): object { + + // Since passing flags is optional, we can use array_pad + // to ensure there are always at least 2 elements in $arguments + [$collection, $flags] = array_pad($arguments, 2, null); + + $factory = new self; + try { - $handler = self::instanciate( - self::generateTargetClassName($name) + $handler = $factory->instanciate( + $factory->generateTargetClassName($name) ); } catch (\Exception $ex) { throw new Exceptions\UnableToLoadInputHandlerException($name, 0, $ex); } - if ($collection instanceof InputCollection) { + if (null !== $collection) { $handler->bind( $collection, $flags diff --git a/src/Input/InputTypeFactory.php b/src/Input/InputTypeFactory.php index dda8115..82b1115 100644 --- a/src/Input/InputTypeFactory.php +++ b/src/Input/InputTypeFactory.php @@ -8,14 +8,12 @@ use pointybeard\Helpers\Foundation\Factory; final class InputTypeFactory extends Factory\AbstractFactory { - use Factory\Traits\hasSimpleFactoryBuildMethodTrait; - - public static function getTemplateNamespace(): string + public function getTemplateNamespace(): string { return __NAMESPACE__.'\\Types\\%s'; } - public static function getExpectedClassType(): ?string + public function getExpectedClassType(): ?string { return __NAMESPACE__.'\\Interfaces\\InputTypeInterface'; } From d501a680ff8a842785a270769d6afffd0d992c3f Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Tue, 4 Jun 2019 23:23:35 +1000 Subject: [PATCH 34/39] Updated README, CHANGELOG, and composer.json for 1.2.1 release --- CHANGELOG.md | 5 +++++ README.md | 4 ++-- composer.json | 3 +-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebd641e..8f8a058 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [1.2.1][] +#### Changed +- Updated `InputHandlerFactory` and `InputTypeFactory` to work with changes in `pointybeard/helpers-foundation-factory` 1.0.2 + ## [1.2.0][] #### Added - Added `InputTypeFilterIterator` class @@ -73,6 +77,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release +[1.2.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.2.0...1.2.1 [1.2.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.4...1.2.0 [1.1.4]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.3...1.1.4 [1.1.3]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.2...1.1.3 diff --git a/README.md b/README.md index e58ef69..b4a1f90 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.2.0 -- Date: June 01 2019 +- Version: v1.2.1 +- Date: June 04 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) diff --git a/composer.json b/composer.json index 094ef88..7191478 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.2.0", + "version": "1.2.1", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", @@ -18,7 +18,6 @@ "pointybeard/helpers-functions-flags": "~1.0" }, "require-dev": { - "phpunit/phpunit": "^8", "pointybeard/helpers-functions-strings": "~1.1.0", "pointybeard/helpers-cli-colour": "~1.0", "pointybeard/helpers-functions-cli": "~1.1.0" From 326a9793028d537bf8575bea1e04d94a67679874 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Tue, 6 Aug 2019 09:02:03 +1000 Subject: [PATCH 35/39] Minor improvement to logic in AbstractInputHandler::validateInput(). Ensures that an input with a validator, but with a default value and no user suplied input, will have the default value used. --- src/Input/AbstractInputHandler.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Input/AbstractInputHandler.php b/src/Input/AbstractInputHandler.php index 97413e0..e0c5e13 100644 --- a/src/Input/AbstractInputHandler.php +++ b/src/Input/AbstractInputHandler.php @@ -68,17 +68,17 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface if(!Flags\is_flag_set($flags, self::FLAG_VALIDATION_SKIP_REQUIRED)) { self::checkRequiredAndRequiredValue($input, $this->input); } - // There is a default value, input has not been set, and there - // is no validator + // There is a default value and input has not been set. Assign the + // default value to the result. if ( null !== $input->default() && - null === $this->find($input->name()) && - null === $input->validator() + null === $this->find($input->name()) ) { $result = $input->default(); - // Input has been set and it has a validator. Skip this if - // FLAG_VALIDATION_SKIP_CUSTOM is set + // Input has been set AND it has a validator. Run the validator over the + // input. Note, this will be skipped if FLAG_VALIDATION_SKIP_CUSTOM is + // set } elseif (null !== $this->find($input->name()) && null !== $input->validator() && !Flags\is_flag_set($flags, self::FLAG_VALIDATION_SKIP_CUSTOM)) { $validator = $input->validator(); @@ -94,7 +94,8 @@ abstract class AbstractInputHandler implements Interfaces\InputHandlerInterface throw new Exceptions\InputValidationFailedException($input, 0, $ex); } - // No default, no validator, but may or may not have been set + // No default, but may or may not have been set so assign whatever value + // it might have to the result } else { $result = $this->find($input->name()); } From 1e903ea6e1ec01b9f6e1e2763cab730af7b5273c Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Tue, 6 Aug 2019 09:03:28 +1000 Subject: [PATCH 36/39] Updated README and CHANGELOG for 1.2.2 release --- CHANGELOG.md | 5 +++++ README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8a058..dc1ac0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [1.2.2][] +#### Changed +- Minor improvement to logic in `AbstractInputHandler::validateInput()`. Ensures that an input with a validator, but with a default value and no user suplied input, will have the default value used. + ## [1.2.1][] #### Changed - Updated `InputHandlerFactory` and `InputTypeFactory` to work with changes in `pointybeard/helpers-foundation-factory` 1.0.2 @@ -77,6 +81,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added - Initial release +[1.2.2]: https://github.com/pointybeard/helpers-functions-cli/compare/1.2.1...1.2.2 [1.2.1]: https://github.com/pointybeard/helpers-functions-cli/compare/1.2.0...1.2.1 [1.2.0]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.4...1.2.0 [1.1.4]: https://github.com/pointybeard/helpers-functions-cli/compare/1.1.3...1.1.4 diff --git a/README.md b/README.md index b4a1f90..be26831 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PHP Helpers: Command-line Input and Input Type Handlers -- Version: v1.2.1 -- Date: June 04 2019 +- Version: v1.2.2 +- Date: Aug 06 2019 - [Release notes](https://github.com/pointybeard/helpers-cli-input/blob/master/CHANGELOG.md) - [GitHub repository](https://github.com/pointybeard/helpers-cli-input) From 2d87f04dffa793e32839d32ef0cb153a506671b2 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Tue, 6 Aug 2019 09:23:59 +1000 Subject: [PATCH 37/39] Removed version information from composer.json --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 7191478..eddd6ad 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,5 @@ { "name": "pointybeard/helpers-cli-input", - "version": "1.2.1", "description": "Collection of classes for handling argv (and other) input when calling command-line scripts. Helps with parsing, collecting and validating arguments, options, and flags.", "homepage": "https://github.com/pointybeard/helpers-cli-input", "license": "MIT", From 9622c9825868cf4ad429ed7cd531175c02bdff94 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Thu, 28 Nov 2019 03:33:52 +0000 Subject: [PATCH 38/39] Removed dev packages from composer.json to avoid circular package dependency version issues and removed example for manpage() method. --- composer.json | 5 ----- example/example.php | 29 ----------------------------- 2 files changed, 34 deletions(-) diff --git a/composer.json b/composer.json index eddd6ad..8eea99b 100644 --- a/composer.json +++ b/composer.json @@ -16,11 +16,6 @@ "pointybeard/helpers-foundation-factory": "~1.0", "pointybeard/helpers-functions-flags": "~1.0" }, - "require-dev": { - "pointybeard/helpers-functions-strings": "~1.1.0", - "pointybeard/helpers-cli-colour": "~1.0", - "pointybeard/helpers-functions-cli": "~1.1.0" - }, "support": { "issues": "https://github.com/pointybeard/helpers-cli-input/issues", "wiki": "https://github.com/pointybeard/helpers-cli-input/wiki" diff --git a/example/example.php b/example/example.php index 76b67e5..1695bf1 100644 --- a/example/example.php +++ b/example/example.php @@ -4,7 +4,6 @@ declare(strict_types=1); include __DIR__.'/../vendor/autoload.php'; use pointybeard\Helpers\Cli\Input; -use pointybeard\Helpers\Cli\Colour\Colour; use pointybeard\Helpers\Functions\Cli; // Define what we are expecting to get from the command line @@ -64,34 +63,6 @@ try { exit; } -// Display the manual in green text -echo Cli\manpage( - basename(__FILE__), - '1.0.2', - 'An example script for the PHP Helpers: Command-line Input and Input Type Handlers composer library (pointybeard/helpers-cli-input).', - $collection, - Colour::FG_GREEN, - Colour::FG_WHITE, - [ - 'Examples' => 'php -f example/example.php -- -vvv -d example/example.json import', - ] -).PHP_EOL.PHP_EOL; - -// example.php 1.0.2, An example script for the PHP Helpers: Command-line Input -// and Input Type Handlers composer library (pointybeard/helpers-cli-input). -// Usage: example.php [OPTIONS]... ACTION... -// -// Arguments: -// ACTION The name of the action to perform -// -// Options: -// -v verbosity level. -v (errors only), -vv -// (warnings and errors), -vvv (everything). -// -d, --data=VALUE Path to the input JSON data -// -// Examples: -// php -f example/example.php -- -vvv -d example/example.json import - var_dump($argv->find('action')); // string(6) "import" From c6fe64321ef06633c89bc055252f22d6ff676d52 Mon Sep 17 00:00:00 2001 From: Norbert Wagner <5166607+n3w@users.noreply.github.com> Date: Thu, 23 Mar 2023 08:47:59 +0100 Subject: [PATCH 39/39] Passing the separator after the array is no longer supported --- src/Input/Types/Argument.php | 2 +- src/Input/Types/LongOption.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Input/Types/Argument.php b/src/Input/Types/Argument.php index 52faec1..4550781 100644 --- a/src/Input/Types/Argument.php +++ b/src/Input/Types/Argument.php @@ -72,6 +72,6 @@ class Argument extends Input\AbstractInputType $second[$ii] = $secondaryLineLeadPadding.$second[$ii]; } - return $first.implode($second, PHP_EOL); + return $first.implode(PHP_EOL, $second); } } diff --git a/src/Input/Types/LongOption.php b/src/Input/Types/LongOption.php index 5961768..17d73de 100644 --- a/src/Input/Types/LongOption.php +++ b/src/Input/Types/LongOption.php @@ -84,6 +84,6 @@ class LongOption extends Input\AbstractInputType $second[$ii] = $secondaryLineLeadPadding.$second[$ii]; } - return $first.implode($second, PHP_EOL); + return $first.implode(PHP_EOL, $second); } }