From 7069019301bb110839e55b461594971bef01b011 Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 1 Jun 2019 15:09:02 +1000 Subject: [PATCH 01/16] 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 02/16] 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 03/16] 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 04/16] 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 05/16] 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 06/16] 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 07/16] 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 08/16] 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 09/16] 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 10/16] 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 11/16] 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 12/16] 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 13/16] 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 14/16] 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 15/16] 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 16/16] 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); } }