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; }