diff --git a/src/EmptyContextInterface.php b/src/EmptyContextInterface.php index ed4cf0fd..72933b18 100644 --- a/src/EmptyContextInterface.php +++ b/src/EmptyContextInterface.php @@ -12,6 +12,6 @@ interface EmptyContextInterface { public function setContinueIfEmpty($continueIfEmpty); - + public function continueIfEmpty(); -} \ No newline at end of file +} diff --git a/src/Factory.php.orig b/src/Factory.php.orig new file mode 100644 index 00000000..f1199abe --- /dev/null +++ b/src/Factory.php.orig @@ -0,0 +1,331 @@ +defaultFilterChain = $filterChain; + return $this; + } + + /** + * Get default filter chain, if any + * + * @return null|FilterChain + */ + public function getDefaultFilterChain() + { + return $this->defaultFilterChain; + } + + /** + * Clear the default filter chain (i.e., don't inject one into new inputs) + * + * @return void + */ + public function clearDefaultFilterChain() + { + $this->defaultFilterChain = null; + } + + /** + * Set default validator chain to use + * + * @param ValidatorChain $validatorChain + * @return Factory + */ + public function setDefaultValidatorChain(ValidatorChain $validatorChain) + { + $this->defaultValidatorChain = $validatorChain; + return $this; + } + + /** + * Get default validator chain, if any + * + * @return null|ValidatorChain + */ + public function getDefaultValidatorChain() + { + return $this->defaultValidatorChain; + } + + /** + * Clear the default validator chain (i.e., don't inject one into new inputs) + * + * @return void + */ + public function clearDefaultValidatorChain() + { + $this->defaultValidatorChain = null; + } + + /** + * Factory for input objects + * + * @param array|Traversable $inputSpecification + * @throws Exception\InvalidArgumentException + * @throws Exception\RuntimeException + * @return InputInterface|InputFilterInterface + */ + public function createInput($inputSpecification) + { + if (!is_array($inputSpecification) && !$inputSpecification instanceof Traversable) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects an array or Traversable; received "%s"', + __METHOD__, + (is_object($inputSpecification) ? get_class($inputSpecification) : gettype($inputSpecification)) + )); + } + if ($inputSpecification instanceof Traversable) { + $inputSpecification = ArrayUtils::iteratorToArray($inputSpecification); + } + + $class = 'Zend\InputFilter\Input'; + if (isset($inputSpecification['type'])) { + $class = $inputSpecification['type']; + if (!class_exists($class)) { + throw new Exception\RuntimeException(sprintf( + 'Input factory expects the "type" to be a valid class; received "%s"', + $class + )); + } + } + $input = new $class(); + + if ($input instanceof InputFilterInterface) { + return $this->createInputFilter($inputSpecification); + } + + if (!$input instanceof InputInterface) { + throw new Exception\RuntimeException(sprintf( + 'Input factory expects the "type" to be a class implementing %s; received "%s"', + 'Zend\InputFilter\InputInterface', + $class + )); + } + + if ($this->defaultFilterChain) { + $input->setFilterChain(clone $this->defaultFilterChain); + } + if ($this->defaultValidatorChain) { + $input->setValidatorChain(clone $this->defaultValidatorChain); + } + + foreach ($inputSpecification as $key => $value) { + switch ($key) { + case 'name': + $input->setName($value); + break; + case 'required': + $input->setRequired($value); + if (!isset($inputSpecification['allow_empty'])) { + $input->setAllowEmpty(!$value); + } + break; + case 'allow_empty': + $input->setAllowEmpty($value); + if (!isset($inputSpecification['required'])) { + $input->setRequired(!$value); + } + break; +<<<<<<< HEAD + case 'error_message': + $input->setErrorMessage($value); +======= + case 'continue_if_empty': + $input->setContinueIfEmpty($inputSpecification['continue_if_empty']); +>>>>>>> zburnham/validate_empty_with_context + break; + case 'fallback_value': + $input->setFallbackValue($value); + break; + case 'filters': + if ($value instanceof FilterChain) { + $input->setFilterChain($value); + break; + } + if (!is_array($value) && !$value instanceof Traversable) { + throw new Exception\RuntimeException(sprintf( + '%s expects the value associated with "filters" to be an array/Traversable of filters or filter specifications, or a FilterChain; received "%s"', + __METHOD__, + (is_object($value) ? get_class($value) : gettype($value)) + )); + } + $this->populateFilters($input->getFilterChain(), $value); + break; + case 'validators': + if ($value instanceof ValidatorChain) { + $input->setValidatorChain($value); + break; + } + if (!is_array($value) && !$value instanceof Traversable) { + throw new Exception\RuntimeException(sprintf( + '%s expects the value associated with "validators" to be an array/Traversable of validators or validator specifications, or a ValidatorChain; received "%s"', + __METHOD__, + (is_object($value) ? get_class($value) : gettype($value)) + )); + } + $this->populateValidators($input->getValidatorChain(), $value); + break; + default: + // ignore unknown keys + break; + } + } + + return $input; + } + + /** + * Factory for input filters + * + * @param array|Traversable $inputFilterSpecification + * @throws Exception\InvalidArgumentException + * @throws Exception\RuntimeException + * @return InputFilterInterface + */ + public function createInputFilter($inputFilterSpecification) + { + if (!is_array($inputFilterSpecification) && !$inputFilterSpecification instanceof Traversable) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects an array or Traversable; received "%s"', + __METHOD__, + (is_object($inputFilterSpecification) ? get_class($inputFilterSpecification) : gettype($inputFilterSpecification)) + )); + } + if ($inputFilterSpecification instanceof Traversable) { + $inputFilterSpecification = ArrayUtils::iteratorToArray($inputFilterSpecification); + } + + $class = 'Zend\InputFilter\InputFilter'; + if (isset($inputFilterSpecification['type']) && is_string($inputFilterSpecification['type'])) { + $class = $inputFilterSpecification['type']; + if (!class_exists($class)) { + throw new Exception\RuntimeException(sprintf( + 'Input factory expects the "type" to be a valid class; received "%s"', + $class + )); + } + unset($inputFilterSpecification['type']); + } + $inputFilter = new $class(); + + if (!$inputFilter instanceof InputFilterInterface) { + throw new Exception\RuntimeException(sprintf( + 'InputFilter factory expects the "type" to be a class implementing %s; received "%s"', + 'Zend\InputFilter\InputFilterInterface', $class)); + } + + if ($inputFilter instanceof CollectionInputFilter) { + if (isset($inputFilterSpecification['input_filter'])) { + $inputFilter->setInputFilter($inputFilterSpecification['input_filter']); + } + if (isset($inputFilterSpecification['count'])) { + $inputFilter->setCount($inputFilterSpecification['count']); + } + return $inputFilter; + } + + foreach ($inputFilterSpecification as $key => $value) { + + if (($value instanceof InputInterface) + || ($value instanceof InputFilterInterface) + ) { + $input = $value; + } else { + $input = $this->createInput($value); + } + + $inputFilter->add($input, $key); + } + + return $inputFilter; + } + + protected function populateFilters(FilterChain $chain, $filters) + { + foreach ($filters as $filter) { + if (is_object($filter) || is_callable($filter)) { + $chain->attach($filter); + continue; + } + + if (is_array($filter)) { + if (!isset($filter['name'])) { + throw new Exception\RuntimeException( + 'Invalid filter specification provided; does not include "name" key' + ); + } + $name = $filter['name']; + $options = array(); + if (isset($filter['options'])) { + $options = $filter['options']; + } + $chain->attachByName($name, $options); + continue; + } + + throw new Exception\RuntimeException( + 'Invalid filter specification provided; was neither a filter instance nor an array specification' + ); + } + } + + protected function populateValidators(ValidatorChain $chain, $validators) + { + foreach ($validators as $validator) { + if ($validator instanceof ValidatorInterface) { + $chain->attach($validator); + continue; + } + + if (is_array($validator)) { + if (!isset($validator['name'])) { + throw new Exception\RuntimeException( + 'Invalid validator specification provided; does not include "name" key' + ); + } + $name = $validator['name']; + $options = array(); + if (isset($validator['options'])) { + $options = $validator['options']; + } + $breakChainOnFailure = false; + if (isset($validator['break_chain_on_failure'])) { + $breakChainOnFailure = $validator['break_chain_on_failure']; + } + $chain->attachByName($name, $options, $breakChainOnFailure); + continue; + } + + throw new Exception\RuntimeException( + 'Invalid validator specification provided; was neither a validator instance nor an array specification' + ); + } + } +} diff --git a/src/Input.php b/src/Input.php index ea992313..759e44b1 100644 --- a/src/Input.php +++ b/src/Input.php @@ -19,7 +19,7 @@ class Input implements InputInterface, EmptyContextInterface * @var bool */ protected $allowEmpty = false; - + /** * @var bool */ @@ -94,7 +94,7 @@ public function setBreakOnFailure($breakOnFailure) $this->breakOnFailure = (bool) $breakOnFailure; return $this; } - + /** * @param bool $continueIfEmpty * @return \Zend\InputFilter\Input @@ -190,7 +190,7 @@ public function breakOnFailure() { return $this->breakOnFailure; } - + /** * @return bool */ diff --git a/test/BaseInputFilterTest.php b/test/BaseInputFilterTest.php index 3a26efb6..4af65579 100644 --- a/test/BaseInputFilterTest.php +++ b/test/BaseInputFilterTest.php @@ -535,7 +535,7 @@ public function testValidationAllowsEmptyValuesToRequiredInputWhenAllowEmptyFlag 'bar' => 124, 'foo' => '', ); - + $filter->setData($data); $this->assertTrue($filter->isValid()); @@ -563,7 +563,7 @@ public function testValidationMarksInputInvalidWhenRequiredAndAllowEmptyFlagIsFa $this->assertFalse($filter->isValid()); } - + public static function contextDataProvider() { return array( @@ -571,9 +571,9 @@ public static function contextDataProvider() array('', 'n', false), ); } - + /** - * Idea here is that an empty field may or may not be valid based on + * Idea here is that an empty field may or may not be valid based on * context. */ /** @@ -582,28 +582,28 @@ public static function contextDataProvider() public function testValidationMarksInputValidWhenAllowEmptyFlagIsTrueAndContinueIfEmptyIsTrueAndContextValidatesEmptyField($allowEmpty, $blankIsValid, $valid) { // $this->markTestSkipped(); - + $filter = new InputFilter(); - + $data = array ( 'allowEmpty' => $allowEmpty, 'blankIsValid' => $blankIsValid, ); - + $allowEmpty = new Input(); $allowEmpty->setAllowEmpty(true) ->setContinueIfEmpty(true); - + $blankIsValid = new Input(); $blankIsValid->getValidatorChain()->attach(new Validator\Callback(function($value, $context) { return ('y' === $value && empty($context['allowEmpty'])); })); - + $filter->add($allowEmpty, 'allowEmpty') - ->add($blankIsValid, 'blankIsValid'); + ->add($blankIsValid, 'blankIsValid'); $filter->setData($data); // die(var_dump($filter->get('blankIsValid'))); - + $this->assertSame($valid, $filter->isValid()); } diff --git a/test/FactoryTest.php b/test/FactoryTest.php index e93fa496..eebcb71b 100644 --- a/test/FactoryTest.php +++ b/test/FactoryTest.php @@ -239,7 +239,7 @@ public function testFactoryWillCreateInputWithSuggestedName() $this->assertInstanceOf('Zend\InputFilter\InputInterface', $input); $this->assertEquals('foo', $input->getName()); } - + public function testFactoryWillCreateInputWithContinueIfEmptyFlag() { $factory = new Factory(); diff --git a/test/InputTest.php b/test/InputTest.php index d86e96c2..f2c2caa0 100644 --- a/test/InputTest.php +++ b/test/InputTest.php @@ -81,20 +81,20 @@ public function testAllowEmptyFlagIsMutable() $this->input->setAllowEmpty(true); $this->assertTrue($this->input->allowEmpty()); } - + public function testContinueIfEmptyFlagIsFalseByDefault() { $input = new Input('foo'); $this->assertFalse($input->continueIfEmpty()); } - + public function testContinueIfEmptyFlagIsMutable() { $input = new Input('foo'); $input->setContinueIfEmpty(true); $this->assertTrue($input->continueIfEmpty()); } - + public function testNotEmptyValidatorNotInjectedIfContinueIfEmptyIsTrue() { $input = new Input('foo');