diff --git a/composer.json b/composer.json index cd624f0a..ceaf56dd 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,9 @@ "zendframework/zend-validator": "self.version", "zendframework/zend-stdlib": "self.version" }, + "suggest": { + "zendframework/zend-servicemanager": "To support plugin manager support" + }, "extra": { "branch-alias": { "dev-master": "2.1-dev", diff --git a/src/ArrayInput.php b/src/ArrayInput.php new file mode 100644 index 00000000..5dec0151 --- /dev/null +++ b/src/ArrayInput.php @@ -0,0 +1,69 @@ +getFilterChain(); + $result = array(); + foreach ($this->value as $key => $value) { + $result[$key] = $filter->filter($value); + } + return $result; + } + + /** + * @param mixed $context Extra "context" to provide the validator + * @return bool + */ + public function isValid($context = null) + { + $this->injectNotEmptyValidator(); + $validator = $this->getValidatorChain(); + $values = $this->getValue(); + $result = true; + foreach ($values as $value) { + $result = $validator->isValid($value, $context); + if (!$result) { + if ($fallbackValue = $this->getFallbackValue()) { + $this->setValue($fallbackValue); + $result = true; + } + break; + } + } + + return $result; + } +} diff --git a/src/BaseInputFilter.php b/src/BaseInputFilter.php index 47560e4c..5416276a 100644 --- a/src/BaseInputFilter.php +++ b/src/BaseInputFilter.php @@ -12,12 +12,13 @@ use ArrayAccess; use Traversable; use Zend\Stdlib\ArrayUtils; +use Zend\Stdlib\InitializableInterface; /** * @todo How should we deal with required input when data is missing? * should a message be returned? if so, what message? */ -class BaseInputFilter implements InputFilterInterface, UnknownInputsCapableInterface +class BaseInputFilter implements InputFilterInterface, UnknownInputsCapableInterface, InitializableInterface { protected $data; protected $inputs = array(); @@ -25,6 +26,16 @@ class BaseInputFilter implements InputFilterInterface, UnknownInputsCapableInter protected $validationGroup; protected $validInputs; + /** + * This function is automatically called when creating element with factory. It + * allows to perform various operations (add elements...) + * + * @return void + */ + public function init() + { + } + /** * Countable: number of inputs in this input filter * @@ -152,42 +163,119 @@ public function isValid() )); } + $inputs = $this->validationGroup ?: array_keys($this->inputs); + return $this->validateInputs($inputs); + } + + /** + * Validate a set of inputs against the current data + * + * @param array $inputs + * @return bool + */ + protected function validateInputs(array $inputs) + { $this->validInputs = array(); $this->invalidInputs = array(); $valid = true; - $inputs = $this->validationGroup ?: array_keys($this->inputs); foreach ($inputs as $name) { - $input = $this->inputs[$name]; - if (!array_key_exists($name, $this->data) - || (null === $this->data[$name]) - || (is_string($this->data[$name]) && strlen($this->data[$name]) === 0) - // Single and Multi File Uploads - || (is_array($this->data[$name]) - && isset($this->data[$name]['error']) && $this->data[$name]['error'] === UPLOAD_ERR_NO_FILE) - || (is_array($this->data[$name]) && count($this->data[$name]) === 1 - && isset($this->data[$name][0]) && is_array($this->data[$name][0]) - && isset($this->data[$name][0]['error']) && $this->data[$name][0]['error'] === UPLOAD_ERR_NO_FILE) + $input = $this->inputs[$name]; + $dataExists = array_key_exists($name, $this->data); + + // key doesn't exist, but input is not required; valid + if (!$dataExists + && $input instanceof InputInterface + && !$input->isRequired() ) { - if ($input instanceof InputInterface) { - // - test if input is required - if (!$input->isRequired() - // "Not required" should not apply to empty strings (#3983) - && !(array_key_exists($name, $this->data) && is_string($this->data[$name])) - ) { - $this->validInputs[$name] = $input; - continue; - } - // - test if input allows empty - if ($input->allowEmpty()) { - $this->validInputs[$name] = $input; - continue; - } + $this->validInputs[$name] = $input; + continue; + } + + // key doesn't exist, input is required, allows empty; valid + if (!$dataExists + && $input instanceof InputInterface + && $input->isRequired() + && $input->allowEmpty() + ) { + if (!$input->allowEmpty()) { + $this->validInputs[$name] = $input; + continue; + } + } + + // key exists, is null, input is not required; valid + if ($dataExists + && null === $this->data[$name] + && $input instanceof InputInterface + && !$input->isRequired() + ) { + $this->validInputs[$name] = $input; + continue; + } + + // key exists, is null, input is required, allows empty; valid + if ($dataExists + && null === $this->data[$name] + && $input instanceof InputInterface + && $input->isRequired() + && $input->allowEmpty() + ) { + $this->validInputs[$name] = $input; + continue; + } + + // key exists, empty string, input is not required, allows empty; valid + if ($dataExists + && '' === $this->data[$name] + && $input instanceof InputInterface + && !$input->isRequired() + ) { + $this->validInputs[$name] = $input; + continue; + } + + // key exists, empty string, input is required, allows empty; valid + // if continueIfEmpty is false, otherwise validation continues + if ($dataExists + && '' === $this->data[$name] + && $input instanceof InputInterface + && $input instanceof EmptyContextInterface + && $input->isRequired() + && $input->allowEmpty() + ) { + if (!$input->continueIfEmpty()) { + $this->validInputs[$name] = $input; + continue; } - // make sure we have a value (empty) for validation + } + + // key exists, is array representing file, no file present, input not + // required or allows empty; valid + if ($dataExists + && is_array($this->data[$name]) + && ( + (isset($this->data[$name]['error']) + && $this->data[$name]['error'] === UPLOAD_ERR_NO_FILE) + || (count($this->data[$name]) === 1 + && isset($this->data[$name][0]) + && is_array($this->data[$name][0]) + && isset($this->data[$name][0]['error']) + && $this->data[$name][0]['error'] === UPLOAD_ERR_NO_FILE) + ) + && $input instanceof InputInterface + && (!$input->isRequired() || $input->allowEmpty()) + ) { + $this->validInputs[$name] = $input; + continue; + } + + // make sure we have a value (empty) for validation + if (!$dataExists) { $this->data[$name] = null; } + // Validate an input filter if ($input instanceof InputFilterInterface) { if (!$input->isValid()) { $this->invalidInputs[$name] = $input; @@ -197,6 +285,8 @@ public function isValid() $this->validInputs[$name] = $input; continue; } + + // Validate an input if ($input instanceof InputInterface) { if (!$input->isValid($this->data)) { // Validation failure @@ -390,6 +480,7 @@ public function getMessages() foreach ($this->getInvalidInput() as $name => $input) { $messages[$name] = $input->getMessages(); } + return $messages; } @@ -498,4 +589,14 @@ public function getUnknown() return $unknownInputs; } + + /** + * Get an array of all inputs + * + * @return array + */ + public function getInputs() + { + return $this->inputs; + } } diff --git a/src/CollectionInputFilter.php b/src/CollectionInputFilter.php new file mode 100644 index 00000000..6adc990e --- /dev/null +++ b/src/CollectionInputFilter.php @@ -0,0 +1,236 @@ +getFactory()->createInputFilter($inputFilter); + } + + if (!$inputFilter instanceof BaseInputFilter) { + throw new Exception\RuntimeException(sprintf( + '%s expects an instance of %s; received "%s"', + __METHOD__, + 'Zend\InputFilter\BaseInputFilter', + (is_object($inputFilter) ? get_class($inputFilter) : gettype($inputFilter)) + )); + } + + $this->inputFilter = $inputFilter; + $this->inputs = $inputFilter->getInputs(); + return $this; + } + + /** + * Get the input filter used when looping the data + * + * @return BaseInputFilter + */ + public function getInputFilter() + { + if (null === $this->inputFilter) { + $this->setInputFilter(new InputFilter()); + } + return $this->inputFilter; + } + + /** + * Set the count of data to validate + * + * @param int $count + * @return CollectionInputFilter + */ + public function setCount($count) + { + $this->count = $count > 0 ? $count : 0; + return $this; + } + + /** + * Get the count of data to validate, use the count of data by default + * + * @return int + */ + public function getCount() + { + if (null === $this->count) { + $this->count = count($this->collectionData); + } + return $this->count; + } + + /** + * {@inheritdoc} + */ + public function setData($data) + { + $this->collectionData = array_values($data); + } + + /** + * {@inheritdoc} + */ + public function isValid() + { + $valid = true; + + if ($this->getCount() < 1) { + return $valid; + } + + $inputCollection = array_fill(0, $this->getCount(), $this->validationGroup ?: array_keys($this->inputs)); + + foreach ($inputCollection as $key => $inputs) { + $this->data = array(); + if (isset($this->collectionData[$key])) { + $this->data = $this->collectionData[$key]; + } + $this->populate(); + + if ($this->validateInputs($inputs)) { + $this->collectionValidInputs[$key] = $this->validInputs; + } else { + $this->collectionInvalidInputs[$key] = $this->invalidInputs; + $valid = false; + } + + $values = array(); + $rawValues = array(); + foreach ($inputs as $name) { + $input = $this->inputs[$name]; + + if ($input instanceof InputFilterInterface) { + $values[$name] = $input->getValues(); + $rawValues[$name] = $input->getRawValues(); + continue; + } + $values[$name] = $input->getValue($this->data); + $rawValues[$name] = $input->getRawValue(); + } + $this->collectionValues[$key] = $values; + $this->collectionRawValues[$key] = $rawValues; + } + + return $valid; + } + + /** + * {@inheritdoc} + */ + public function setValidationGroup($name) + { + if ($name === self::VALIDATE_ALL) { + $this->validationGroup = null; + return $this; + } + + if (is_array($name)) { + // Best effort check if the validation group was set by a form for BC + if (count($name) == count($this->collectionData) && is_array(reset($name))) { + return parent::setValidationGroup(reset($name)); + } + return parent::setValidationGroup($name); + } + + return parent::setValidationGroup(func_get_args()); + } + + /** + * {@inheritdoc} + */ + public function getInvalidInput() + { + return (is_array($this->collectionInvalidInputs) ? $this->collectionInvalidInputs : array()); + } + + /** + * {@inheritdoc} + */ + public function getValidInput() + { + return (is_array($this->collectionValidInputs) ? $this->collectionValidInputs : array()); + } + + /** + * {@inheritdoc} + */ + public function getValues() + { + return $this->collectionValues; + } + + /** + * {@inheritdoc} + */ + public function getRawValues() + { + return $this->collectionRawValues; + } + + /** + * {@inheritdoc} + */ + public function getMessages() + { + $messages = array(); + foreach ($this->getInvalidInput() as $key => $inputs) { + foreach ($inputs as $name => $input) { + $messages[$key][$name] = $input->getMessages(); + } + } + return $messages; + } +} diff --git a/src/EmptyContextInterface.php b/src/EmptyContextInterface.php new file mode 100644 index 00000000..72933b18 --- /dev/null +++ b/src/EmptyContextInterface.php @@ -0,0 +1,17 @@ +setInputFilterManager($inputFilterManager); + } + + $this->defaultFilterChain = new FilterChain(); + $this->defaultValidatorChain = new ValidatorChain(); + } + /** * Set default filter chain to use * @@ -84,6 +109,29 @@ public function clearDefaultValidatorChain() $this->defaultValidatorChain = null; } + /** + * @param InputFilterPluginManager $inputFilterManager + * @return self + */ + public function setInputFilterManager(InputFilterPluginManager $inputFilterManager) + { + $this->inputFilterManager = $inputFilterManager; + + return $this; + } + + /** + * @return InputFilterPluginManager + */ + public function getInputFilterManager() + { + if (null === $this->inputFilterManager) { + $this->inputFilterManager = new InputFilterPluginManager; + } + + return $this->inputFilterManager; + } + /** * Factory for input objects * @@ -106,8 +154,14 @@ public function createInput($inputSpecification) } $class = 'Zend\InputFilter\Input'; + if (isset($inputSpecification['type'])) { $class = $inputSpecification['type']; + + if ($this->getInputFilterManager()->has($class)) { + return $this->createInputFilter($inputSpecification); + } + if (!class_exists($class)) { throw new Exception\RuntimeException(sprintf( 'Input factory expects the "type" to be a valid class; received "%s"', @@ -153,9 +207,11 @@ public function createInput($inputSpecification) $input->setRequired(!$value); } break; + case 'continue_if_empty': + $input->setContinueIfEmpty($inputSpecification['continue_if_empty']); + break; case 'error_message': $input->setErrorMessage($value); - break; case 'fallback_value': $input->setFallbackValue($value); break; @@ -217,23 +273,23 @@ public function createInputFilter($inputFilterSpecification) $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 - )); - } + $type = 'Zend\InputFilter\InputFilter'; + + if (isset($inputFilterSpecification['type'])) { + $type = $inputFilterSpecification['type']; 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)); + $inputFilter = $this->getInputFilterManager()->get($type); + + 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) { @@ -252,6 +308,11 @@ public function createInputFilter($inputFilterSpecification) return $inputFilter; } + /** + * @param FilterChain $chain + * @param array|Traversable $filters + * @return void + */ protected function populateFilters(FilterChain $chain, $filters) { foreach ($filters as $filter) { @@ -282,6 +343,11 @@ protected function populateFilters(FilterChain $chain, $filters) } } + /** + * @param ValidatorChain $chain + * @param array|Traversable $validators + * @return void + */ protected function populateValidators(ValidatorChain $chain, $validators) { foreach ($validators as $validator) { diff --git a/src/FileInput.php b/src/FileInput.php index 110f4f58..76a8bd4d 100644 --- a/src/FileInput.php +++ b/src/FileInput.php @@ -28,17 +28,17 @@ class FileInput extends Input { /** - * @var boolean + * @var bool */ protected $isValid = false; /** - * @var boolean + * @var bool */ protected $autoPrependUploadValidator = true; /** - * @param boolean $value Enable/Disable automatically prepending an Upload validator + * @param bool $value Enable/Disable automatically prepending an Upload validator * @return FileInput */ public function setAutoPrependUploadValidator($value) @@ -48,7 +48,7 @@ public function setAutoPrependUploadValidator($value) } /** - * @return boolean + * @return bool */ public function getAutoPrependUploadValidator() { @@ -85,7 +85,7 @@ public function getValue() /** * @param mixed $context Extra "context" to provide the validator - * @return boolean + * @return bool */ public function isValid($context = null) { diff --git a/src/Input.php b/src/Input.php index 277340be..e4cf2bf0 100644 --- a/src/Input.php +++ b/src/Input.php @@ -10,16 +10,21 @@ namespace Zend\InputFilter; use Zend\Filter\FilterChain; -use Zend\Validator\ValidatorChain; use Zend\Validator\NotEmpty; +use Zend\Validator\ValidatorChain; -class Input implements InputInterface +class Input implements InputInterface, EmptyContextInterface { /** * @var bool */ protected $allowEmpty = false; + /** + * @var bool + */ + protected $continueIfEmpty = false; + /** * @var bool */ @@ -90,6 +95,16 @@ public function setBreakOnFailure($breakOnFailure) return $this; } + /** + * @param bool $continueIfEmpty + * @return \Zend\InputFilter\Input + */ + public function setContinueIfEmpty($continueIfEmpty) + { + $this->continueIfEmpty = (bool) $continueIfEmpty; + return $this; + } + /** * @param string|null $errorMessage * @return Input @@ -176,6 +191,14 @@ public function breakOnFailure() return $this->breakOnFailure; } + /** + * @return bool + */ + public function continueIfEmpty() + { + return $this->continueIfEmpty; + } + /** * @return string|null */ @@ -274,7 +297,12 @@ public function merge(InputInterface $input) */ public function isValid($context = null) { - $this->injectNotEmptyValidator(); + // Empty value needs further validation if continueIfEmpty is set + // so don't inject NotEmpty validator which would always + // mark that as false + if (!$this->continueIfEmpty()) { + $this->injectNotEmptyValidator(); + } $validator = $this->getValidatorChain(); $value = $this->getValue(); $result = $validator->isValid($value, $context); diff --git a/src/InputFilterPluginManager.php b/src/InputFilterPluginManager.php new file mode 100644 index 00000000..757e3dc2 --- /dev/null +++ b/src/InputFilterPluginManager.php @@ -0,0 +1,89 @@ + 'Zend\InputFilter\InputFilter', + 'collection' => 'Zend\InputFilter\CollectionInputFilter', + ); + + /** + * Whether or not to share by default + * + * @var bool + */ + protected $shareByDefault = false; + + /** + * @param ConfigInterface $configuration + */ + public function __construct(ConfigInterface $configuration = null) + { + parent::__construct($configuration); + + $this->addInitializer(array($this, 'populateFactory')); + } + + /** + * Inject this and populate the factory with filter chain and validator chain + * + * @param $inputfilter + */ + public function populateFactory($inputfilter) + { + if ($inputfilter instanceof InputFilter) { + $factory = $inputfilter->getFactory(); + + $factory->setInputFilterManager($this); + + if ($this->serviceLocator instanceof ServiceLocatorInterface) { + $factory->getDefaultFilterChain()->setPluginManager($this->serviceLocator->get('FilterManager')); + $factory->getDefaultValidatorChain()->setPluginManager($this->serviceLocator->get('ValidatorManager')); + } + } + } + + /** + * {@inheritDoc} + */ + public function validatePlugin($plugin) + { + if ($plugin instanceof InputFilterInterface) { + // Hook to perform various initialization, when the inputfilter is not created through the factory + if ($plugin instanceof InitializableInterface) { + $plugin->init(); + } + + // we're okay + return; + } + + throw new Exception\RuntimeException(sprintf( + 'Plugin of type %s is invalid; must implement Zend\InputFilter\InputFilterInterface', + (is_object($plugin) ? get_class($plugin) : gettype($plugin)) + )); + } +} diff --git a/test/ArrayInputTest.php b/test/ArrayInputTest.php new file mode 100644 index 00000000..fb7403ef --- /dev/null +++ b/test/ArrayInputTest.php @@ -0,0 +1,190 @@ +input = new ArrayInput('foo'); + } + + public function testValueIsNullByDefault() + { + $this->markTestSkipped('Test is not enabled in ArrayInputTest'); + } + + public function testValueIsEmptyArrayByDefault() + { + $this->assertCount(0, $this->input->getValue()); + } + + public function testNotArrayValueCannotBeInjected() + { + $this->setExpectedException('Zend\InputFilter\Exception\InvalidArgumentException'); + $this->input->setValue('bar'); + } + + public function testValueMayBeInjected() + { + $this->input->setValue(array('bar')); + $this->assertEquals(array('bar'), $this->input->getValue()); + } + + public function testRetrievingValueFiltersTheValue() + { + $this->input->setValue(array('bar')); + $filter = new Filter\StringToUpper(); + $this->input->getFilterChain()->attach($filter); + $this->assertEquals(array('BAR'), $this->input->getValue()); + } + + public function testCanRetrieveRawValue() + { + $this->input->setValue(array('bar')); + $filter = new Filter\StringToUpper(); + $this->input->getFilterChain()->attach($filter); + $this->assertEquals(array('bar'), $this->input->getRawValue()); + } + + public function testIsValidReturnsFalseIfValidationChainFails() + { + $this->input->setValue(array('123', 'bar')); + $validator = new Validator\Digits(); + $this->input->getValidatorChain()->attach($validator); + $this->assertFalse($this->input->isValid()); + } + + public function testIsValidReturnsTrueIfValidationChainSucceeds() + { + $this->input->setValue(array('123', '123')); + $validator = new Validator\Digits(); + $this->input->getValidatorChain()->attach($validator); + $this->assertTrue($this->input->isValid()); + } + + public function testValidationOperatesOnFilteredValue() + { + $this->input->setValue(array(' 123 ', ' 123')); + $filter = new Filter\StringTrim(); + $this->input->getFilterChain()->attach($filter); + $validator = new Validator\Digits(); + $this->input->getValidatorChain()->attach($validator); + $this->assertTrue($this->input->isValid()); + } + + public function testGetMessagesReturnsValidationMessages() + { + $this->input->setValue(array('bar')); + $validator = new Validator\Digits(); + $this->input->getValidatorChain()->attach($validator); + $this->assertFalse($this->input->isValid()); + $messages = $this->input->getMessages(); + $this->assertArrayHasKey(Validator\Digits::NOT_DIGITS, $messages); + } + + public function testSpecifyingMessagesToInputReturnsThoseOnFailedValidation() + { + $this->input->setValue(array('bar')); + $validator = new Validator\Digits(); + $this->input->getValidatorChain()->attach($validator); + $this->input->setErrorMessage('Please enter only digits'); + $this->assertFalse($this->input->isValid()); + $messages = $this->input->getMessages(); + $this->assertArrayNotHasKey(Validator\Digits::NOT_DIGITS, $messages); + $this->assertContains('Please enter only digits', $messages); + } + + public function testNotEmptyValidatorAddedWhenIsValidIsCalled() + { + $this->assertTrue($this->input->isRequired()); + $this->input->setValue(array('bar', '')); + $validatorChain = $this->input->getValidatorChain(); + $this->assertEquals(0, count($validatorChain->getValidators())); + + $this->assertFalse($this->input->isValid()); + $messages = $this->input->getMessages(); + $this->assertArrayHasKey('isEmpty', $messages); + $this->assertEquals(1, count($validatorChain->getValidators())); + + // Assert that NotEmpty validator wasn't added again + $this->assertFalse($this->input->isValid()); + $this->assertEquals(1, count($validatorChain->getValidators())); + } + + public function testRequiredNotEmptyValidatorNotAddedWhenOneExists() + { + $this->assertTrue($this->input->isRequired()); + $this->input->setValue(array('bar', '')); + + $notEmptyMock = $this->getMock('Zend\Validator\NotEmpty', array('isValid')); + $notEmptyMock->expects($this->exactly(1)) + ->method('isValid') + ->will($this->returnValue(false)); + + $validatorChain = $this->input->getValidatorChain(); + $validatorChain->prependValidator($notEmptyMock); + $this->assertFalse($this->input->isValid()); + + $validators = $validatorChain->getValidators(); + $this->assertEquals(1, count($validators)); + $this->assertEquals($notEmptyMock, $validators[0]['instance']); + } + + public function testMerge() + { + $input = new ArrayInput('foo'); + $input->setValue(array(' 123 ')); + $filter = new Filter\StringTrim(); + $input->getFilterChain()->attach($filter); + $validator = new Validator\Digits(); + $input->getValidatorChain()->attach($validator); + + $input2 = new ArrayInput('bar'); + $input2->merge($input); + $validatorChain = $input->getValidatorChain(); + $filterChain = $input->getFilterChain(); + + $this->assertEquals(array(' 123 '), $input2->getRawValue()); + $this->assertEquals(1, $validatorChain->count()); + $this->assertEquals(1, $filterChain->count()); + + $validators = $validatorChain->getValidators(); + $this->assertInstanceOf('Zend\Validator\Digits', $validators[0]['instance']); + + $filters = $filterChain->getFilters()->toArray(); + $this->assertInstanceOf('Zend\Filter\StringTrim', $filters[0]); + } + + public function testDoNotInjectNotEmptyValidatorIfAnywhereInChain() + { + $this->assertTrue($this->input->isRequired()); + $this->input->setValue(array('bar', '')); + + $notEmptyMock = $this->getMock('Zend\Validator\NotEmpty', array('isValid')); + $notEmptyMock->expects($this->exactly(1)) + ->method('isValid') + ->will($this->returnValue(false)); + + $validatorChain = $this->input->getValidatorChain(); + $validatorChain->attach(new Validator\Digits()); + $validatorChain->attach($notEmptyMock); + $this->assertFalse($this->input->isValid()); + + $validators = $validatorChain->getValidators(); + $this->assertEquals(2, count($validators)); + $this->assertEquals($notEmptyMock, $validators[1]['instance']); + } +} diff --git a/test/BaseInputFilterTest.php b/test/BaseInputFilterTest.php index 8506e3d7..9a7909c5 100644 --- a/test/BaseInputFilterTest.php +++ b/test/BaseInputFilterTest.php @@ -123,62 +123,74 @@ public function getChildInputFilter() return $filter; } - public function testCanValidateEntireDataset() + public function dataSets() { - $filter = $this->getInputFilter(); - $validData = array( - 'foo' => ' bazbat ', - 'bar' => '12345', - 'baz' => null, - 'qux' => '', - 'nest' => array( - 'foo' => ' bazbat ', - 'bar' => '12345', - 'baz' => null, + return array( + 'valid-with-empty-and-null' => array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => null, + 'qux' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => null, + ), + ), + true, ), - ); - $filter->setData($validData); - $this->assertTrue($filter->isValid()); - - $filter = $this->getInputFilter(); - $validData = array( - 'foo' => ' bazbat ', - 'bar' => '12345', - 'qux' => '', - 'nest' => array( - 'foo' => ' bazbat ', - 'bar' => '12345', + 'valid-with-empty' => array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'qux' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + ), + ), + true, ), - ); - $filter->setData($validData); - $this->assertTrue($filter->isValid()); - - $invalidData = array( - 'foo' => ' bazbat ', - 'bar' => '12345', - 'baz' => '', - 'nest' => array( - 'foo' => ' bazbat ', - 'bar' => '12345', - 'baz' => '', + 'invalid-with-empty-and-missing' => array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => 'thisistoolong', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => 'thisistoolong', + ), + ), + false, ), - ); - $filter->setData($invalidData); - $this->assertFalse($filter->isValid()); - - $invalidData = array( - 'foo' => ' baz bat ', - 'bar' => 'abc45', - 'baz' => ' ', - 'qux' => ' ', - 'nest' => array( - 'foo' => ' baz bat ', - 'bar' => '123ab', - 'baz' => ' ', + 'invalid-with-empty' => array( + array( + 'foo' => ' baz bat ', + 'bar' => 'abc45', + 'baz' => ' ', + 'qux' => ' ', + 'nest' => array( + 'foo' => ' baz bat ', + 'bar' => '123ab', + 'baz' => ' ', + ), + ), + false, ), ); - $filter->setData($invalidData); - $this->assertFalse($filter->isValid()); + } + + /** + * @dataProvider dataSets + * @group fmlife + */ + public function testCanValidateEntireDataset($dataset, $expected) + { + $filter = $this->getInputFilter(); + $filter->setData($dataset); + $this->assertSame($expected, $filter->isValid()); } public function testCanValidatePartialDataset() @@ -519,7 +531,11 @@ public function testValidationAllowsEmptyValuesToRequiredInputWhenAllowEmptyFlag $filter->add($foo, '') ->add($bar, 'bar'); - $data = array('bar' => 124); + $data = array( + 'bar' => 124, + 'foo' => '', + ); + $filter->setData($data); $this->assertTrue($filter->isValid()); @@ -548,6 +564,49 @@ public function testValidationMarksInputInvalidWhenRequiredAndAllowEmptyFlagIsFa $this->assertFalse($filter->isValid()); } + public static function contextDataProvider() + { + return array( + array('', 'y', true), + array('', 'n', false), + ); + } + + /** + * Idea here is that an empty field may or may not be valid based on + * context. + */ + /** + * @dataProvider 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'); + $filter->setData($data); +// die(var_dump($filter->get('blankIsValid'))); + + $this->assertSame($valid, $filter->isValid()); + } + public function testCanRetrieveRawValuesIndividuallyWithoutValidating() { $filter = $this->getInputFilter(); @@ -675,6 +734,22 @@ public function testValidateUseExplodeAndInstanceOf() $filter->setData($data); $this->assertTrue($filter->isValid()); + } + + public function testGetInputs() + { + $filter = new InputFilter(); + + $foo = new Input('foo'); + $bar = new Input('bar'); + + $filter->add($foo); + $filter->add($bar); + + $filters = $filter->getInputs(); + $this->assertCount(2, $filters); + $this->assertEquals('foo', $filters['foo']->getName()); + $this->assertEquals('bar', $filters['bar']->getName()); } } diff --git a/test/CollectionInputFilterTest.php b/test/CollectionInputFilterTest.php new file mode 100644 index 00000000..1cf5159f --- /dev/null +++ b/test/CollectionInputFilterTest.php @@ -0,0 +1,357 @@ +filter = new CollectionInputFilter(); + } + + public function getBaseInputFilter() + { + $filter = new BaseInputFilter(); + + $foo = new Input(); + $foo->getFilterChain()->attachByName('stringtrim') + ->attachByName('alpha'); + $foo->getValidatorChain()->attach(new Validator\StringLength(3, 6)); + + $bar = new Input(); + $bar->getFilterChain()->attachByName('stringtrim'); + $bar->getValidatorChain()->attach(new Validator\Digits()); + + $baz = new Input(); + $baz->setRequired(false); + $baz->getFilterChain()->attachByName('stringtrim'); + $baz->getValidatorChain()->attach(new Validator\StringLength(1, 6)); + + $filter->add($foo, 'foo') + ->add($bar, 'bar') + ->add($baz, 'baz') + ->add($this->getChildInputFilter(), 'nest'); + + return $filter; + } + + public function getChildInputFilter() + { + $filter = new BaseInputFilter(); + + $foo = new Input(); + $foo->getFilterChain()->attachByName('stringtrim') + ->attachByName('alpha'); + $foo->getValidatorChain()->attach(new Validator\StringLength(3, 6)); + + $bar = new Input(); + $bar->getFilterChain()->attachByName('stringtrim'); + $bar->getValidatorChain()->attach(new Validator\Digits()); + + $baz = new Input(); + $baz->setRequired(false); + $baz->getFilterChain()->attachByName('stringtrim'); + $baz->getValidatorChain()->attach(new Validator\StringLength(1, 6)); + + $filter->add($foo, 'foo') + ->add($bar, 'bar') + ->add($baz, 'baz'); + return $filter; + } + + public function getValidCollectionData() + { + return array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + ), + ), + array( + 'foo' => ' batbaz ', + 'bar' => '54321', + 'baz' => '', + 'nest' => array( + 'foo' => ' batbaz ', + 'bar' => '54321', + 'baz' => '', + ), + ) + ); + } + + public function testSetInputFilter() + { + $this->filter->setInputFilter(new BaseInputFilter()); + $this->assertInstanceOf('Zend\InputFilter\BaseInputFilter', $this->filter->getInputFilter()); + } + + public function testInputFilterInputsAppliedToCollection() + { + $this->filter->setInputFilter($this->getBaseInputFilter()); + + $this->assertCount(4, $this->filter->getInputs()); + } + + public function testGetDefaultInputFilter() + { + $this->assertInstanceOf('Zend\InputFilter\BaseInputFilter', $this->filter->getInputFilter()); + } + + public function testSetCount() + { + $this->filter->setCount(5); + $this->assertEquals(5, $this->filter->getCount()); + } + + public function testSetCountBelowZero() + { + $this->filter->setCount(-1); + $this->assertEquals(0, $this->filter->getCount()); + } + + public function testGetCountUsesCountOfCollectionDataWhenNotSet() + { + $collectionData = array( + array('foo' => 'bar'), + array('foo' => 'baz') + ); + + $this->filter->setData($collectionData); + $this->assertEquals(2, $this->filter->getCount()); + } + + public function testGetCountUsesSpecifiedCount() + { + $collectionData = array( + array('foo' => 'bar'), + array('foo' => 'baz') + ); + + $this->filter->setCount(3); + $this->filter->setData($collectionData); + $this->assertEquals(3, $this->filter->getCount()); + } + + public function testCanValidateValidData() + { + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($this->getValidCollectionData()); + $this->assertTrue($this->filter->isValid()); + } + + public function testInvalidDataReturnsFalse() + { + $invalidCollectionData = array( + array( + 'foo' => ' bazbatlong ', + 'bar' => '12345', + 'baz' => '', + ), + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + ) + ); + + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($invalidCollectionData); + $this->assertFalse($this->filter->isValid()); + } + + public function testDataLessThanCountIsInvalid() + { + $invalidCollectionData = array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + ), + ), + ); + + $this->filter->setCount(2); + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($invalidCollectionData); + $this->assertFalse($this->filter->isValid()); + } + + public function testGetValues() + { + $expectedData = array( + array( + 'foo' => 'bazbat', + 'bar' => '12345', + 'baz' => '', + 'nest' => array( + 'foo' => 'bazbat', + 'bar' => '12345', + 'baz' => '', + ), + ), + array( + 'foo' => 'batbaz', + 'bar' => '54321', + 'baz' => '', + 'nest' => array( + 'foo' => 'batbaz', + 'bar' => '54321', + 'baz' => '', + ), + ) + ); + + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($this->getValidCollectionData()); + + $this->assertTrue($this->filter->isValid()); + $this->assertEquals($expectedData, $this->filter->getValues()); + + $this->assertCount(2, $this->filter->getValidInput()); + foreach ($this->filter->getValidInput() as $validInputs) { + $this->assertCount(4, $validInputs); + } + } + + public function testGetRawValues() + { + $expectedData = array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + ), + ), + array( + 'foo' => ' batbaz ', + 'bar' => '54321', + 'baz' => '', + 'nest' => array( + 'foo' => ' batbaz ', + 'bar' => '54321', + 'baz' => '', + ), + ) + ); + + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($this->getValidCollectionData()); + + $this->assertTrue($this->filter->isValid()); + $this->assertEquals($expectedData, $this->filter->getRawValues()); + } + + public function testGetMessagesForInvalidInputs() + { + $invalidCollectionData = array( + array( + 'foo' => ' bazbattoolong ', + 'bar' => '12345', + 'baz' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + ), + ), + array( + 'foo' => ' bazbat ', + 'bar' => 'notstring', + 'baz' => '', + 'nest' => array( + 'foo' => ' bazbat ', + 'bar' => '12345', + 'baz' => '', + ), + ), + ); + + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($invalidCollectionData); + + $this->assertFalse($this->filter->isValid()); + + $this->assertCount(2, $this->filter->getInvalidInput()); + foreach ($this->filter->getInvalidInput() as $invalidInputs) { + $this->assertCount(1, $invalidInputs); + } + + $messages = $this->filter->getMessages(); + + $this->assertCount(2, $messages); + $this->assertArrayHasKey('foo', $messages[0]); + $this->assertArrayHasKey('bar', $messages[1]); + } + + public function testSetValidationGroupUsingFormStyle() + { + // forms set an array of identical validation groups for each set of data + $formValidationGroup = array( + array( + 'foo', + 'bar', + ), + array( + 'foo', + 'bar', + ), + array( + 'foo', + 'bar', + ) + ); + + $data = array( + array( + 'foo' => ' bazbat ', + 'bar' => '12345' + ), + array( + 'foo' => ' batbaz ', + 'bar' => '54321' + ), + array( + 'foo' => ' batbaz ', + 'bar' => '54321' + ) + ); + + $this->filter->setInputFilter($this->getBaseInputFilter()); + $this->filter->setData($data); + $this->filter->setValidationGroup($formValidationGroup); + + $this->assertTrue($this->filter->isValid()); + } +} diff --git a/test/FactoryTest.php b/test/FactoryTest.php index 9e94ee00..8c590bba 100644 --- a/test/FactoryTest.php +++ b/test/FactoryTest.php @@ -19,16 +19,16 @@ class FactoryTest extends TestCase { - public function testFactoryDoesNotComposeFilterChainByDefault() + public function testFactoryComposesFilterChainByDefault() { $factory = new Factory(); - $this->assertNull($factory->getDefaultFilterChain()); + $this->assertInstanceOf('Zend\Filter\FilterChain', $factory->getDefaultFilterChain()); } - public function testFactoryDoesNotComposeValidatorChainByDefault() + public function testFactoryComposesValidatorChainByDefault() { $factory = new Factory(); - $this->assertNull($factory->getDefaultValidatorChain()); + $this->assertInstanceOf('Zend\Validator\ValidatorChain', $factory->getDefaultValidatorChain()); } public function testFactoryAllowsInjectingFilterChain() @@ -240,6 +240,17 @@ public function testFactoryWillCreateInputWithSuggestedName() $this->assertEquals('foo', $input->getName()); } + public function testFactoryWillCreateInputWithContinueIfEmptyFlag() + { + $factory = new Factory(); + $input = $factory->createInput(array( + 'name' => 'foo', + 'continue_if_empty' => true, + )); + $this->assertInstanceOf('Zend\InputFilter\InputInterface', $input); + $this->assertTrue($input->continueIfEmpty()); + } + public function testFactoryAcceptsInputInterface() { $factory = new Factory(); @@ -339,11 +350,15 @@ public function testFactoryWillCreateInputFilterAndAllInputObjectsFromGivenConfi 'type' => 'ZendTest\InputFilter\TestAsset\CustomInput', 'name' => 'bat', ), + 'zomg' => array( + 'name' => 'zomg', + 'continue_if_empty' => true, + ), )); $this->assertInstanceOf('Zend\InputFilter\InputFilter', $inputFilter); - $this->assertEquals(4, count($inputFilter)); + $this->assertEquals(5, count($inputFilter)); - foreach (array('foo', 'bar', 'baz', 'bat') as $name) { + foreach (array('foo', 'bar', 'baz', 'bat', 'zomg') as $name) { $input = $inputFilter->get($name); switch ($name) { @@ -373,6 +388,9 @@ public function testFactoryWillCreateInputFilterAndAllInputObjectsFromGivenConfi $this->assertInstanceOf('ZendTest\InputFilter\TestAsset\CustomInput', $input); $this->assertEquals('bat', $input->getName()); break; + case 'zomg': + $this->assertInstanceOf('Zend\InputFilter\Input', $input); + $this->assertTrue($input->continueIfEmpty()); } } } @@ -414,6 +432,21 @@ public function testFactoryAllowsPassingFilterChainsInInputSpec() $this->assertSame($chain, $test); } + public function testFactoryAcceptsCollectionInputFilter() + { + $factory = new Factory(); + + $inputFilter = $factory->createInputFilter(array( + 'type' => 'Zend\InputFilter\CollectionInputFilter', + 'inputfilter' => new InputFilter(), + 'count' => 3 + )); + + $this->assertInstanceOf('Zend\InputFilter\CollectionInputFilter', $inputFilter); + $this->assertInstanceOf('Zend\InputFilter\InputFilter', $inputFilter->getInputFilter()); + $this->assertEquals(3, $inputFilter->getCount()); + } + public function testFactoryWillCreateInputWithErrorMessage() { $factory = new Factory(); diff --git a/test/FileInputTest.php b/test/FileInputTest.php index de0221da..22d18c40 100644 --- a/test/FileInputTest.php +++ b/test/FileInputTest.php @@ -10,12 +10,11 @@ namespace ZendTest\InputFilter; -use PHPUnit_Framework_TestCase as TestCase; use Zend\InputFilter\FileInput; use Zend\Filter; use Zend\Validator; -class FileInputTest extends TestCase +class FileInputTest extends InputTest { public function setUp() { @@ -24,66 +23,6 @@ public function setUp() $this->input->setAutoPrependUploadValidator(false); } - public function testConstructorRequiresAName() - { - $this->assertEquals('foo', $this->input->getName()); - } - - public function testInputHasEmptyFilterChainByDefault() - { - $filters = $this->input->getFilterChain(); - $this->assertInstanceOf('Zend\Filter\FilterChain', $filters); - $this->assertEquals(0, count($filters)); - } - - public function testInputHasEmptyValidatorChainByDefault() - { - $validators = $this->input->getValidatorChain(); - $this->assertInstanceOf('Zend\Validator\ValidatorChain', $validators); - $this->assertEquals(0, count($validators)); - } - - public function testCanInjectFilterChain() - { - $chain = new Filter\FilterChain(); - $this->input->setFilterChain($chain); - $this->assertSame($chain, $this->input->getFilterChain()); - } - - public function testCanInjectValidatorChain() - { - $chain = new Validator\ValidatorChain(); - $this->input->setValidatorChain($chain); - $this->assertSame($chain, $this->input->getValidatorChain()); - } - - public function testInputIsMarkedAsRequiredByDefault() - { - $this->assertTrue($this->input->isRequired()); - } - - public function testRequiredFlagIsMutable() - { - $this->input->setRequired(false); - $this->assertFalse($this->input->isRequired()); - } - - public function testInputDoesNotAllowEmptyValuesByDefault() - { - $this->assertFalse($this->input->allowEmpty()); - } - - public function testAllowEmptyFlagIsMutable() - { - $this->input->setAllowEmpty(true); - $this->assertTrue($this->input->allowEmpty()); - } - - public function testValueIsNullByDefault() - { - $this->assertNull($this->input->getValue()); - } - public function testValueMayBeInjected() { $value = array('tmp_name' => 'bar'); @@ -91,6 +30,11 @@ public function testValueMayBeInjected() $this->assertEquals($value, $this->input->getValue()); } + public function testRetrievingValueFiltersTheValue() + { + $this->markTestSkipped('Test are not enabled in FileInputTest'); + } + public function testRetrievingValueFiltersTheValueOnlyAfterValidating() { $value = array('tmp_name' => 'bar'); @@ -177,6 +121,11 @@ public function testIsValidReturnsTrueIfValidationChainSucceeds() $this->assertTrue($this->input->isValid()); } + public function testValidationOperatesOnFilteredValue() + { + $this->markTestSkipped('Test is not enabled in FileInputTest'); + } + public function testValidationOperatesBeforeFiltering() { $badValue = array( @@ -273,17 +222,6 @@ public function testSpecifyingMessagesToInputReturnsThoseOnFailedValidation() $this->assertContains('Please enter only digits', $messages); } - public function testBreakOnFailureFlagIsOffByDefault() - { - $this->assertFalse($this->input->breakOnFailure()); - } - - public function testBreakOnFailureFlagIsMutable() - { - $this->input->setBreakOnFailure(true); - $this->assertTrue($this->input->breakOnFailure()); - } - public function testAutoPrependUploadValidatorIsOnByDefault() { $input = new FileInput('foo'); @@ -364,6 +302,16 @@ public function testValidationsRunWithoutFileArrayDueToAjaxPost() $this->assertEquals($uploadMock, $validators[0]['instance']); } + public function testNotEmptyValidatorAddedWhenIsValidIsCalled() + { + $this->markTestSkipped('Test is not enabled in FileInputTest'); + } + + public function testRequiredNotEmptyValidatorNotAddedWhenOneExists() + { + $this->markTestSkipped('Test is not enabled in FileInputTest'); + } + public function testMerge() { $value = array('tmp_name' => 'bar'); diff --git a/test/InputFilterManagerTest.php b/test/InputFilterManagerTest.php new file mode 100644 index 00000000..5993bc6c --- /dev/null +++ b/test/InputFilterManagerTest.php @@ -0,0 +1,42 @@ +manager = new InputFilterPluginManager(); + } + + public function testRegisteringInvalidElementRaisesException() + { + $this->setExpectedException('Zend\InputFilter\Exception\RuntimeException'); + $this->manager->setService('test', $this); + } + + public function testLoadingInvalidElementRaisesException() + { + $this->manager->setInvokableClass('test', get_class($this)); + $this->setExpectedException('Zend\InputFilter\Exception\RuntimeException'); + $this->manager->get('test'); + } +} diff --git a/test/InputTest.php b/test/InputTest.php index 937b3e55..f2c2caa0 100644 --- a/test/InputTest.php +++ b/test/InputTest.php @@ -17,199 +17,211 @@ class InputTest extends TestCase { + /** + * @var Input + */ + protected $input; + + public function setUp() + { + $this->input = new Input('foo'); + } + public function testConstructorRequiresAName() { - $input = new Input('foo'); - $this->assertEquals('foo', $input->getName()); + $this->assertEquals('foo', $this->input->getName()); } public function testInputHasEmptyFilterChainByDefault() { - $input = new Input('foo'); - $filters = $input->getFilterChain(); + $filters = $this->input->getFilterChain(); $this->assertInstanceOf('Zend\Filter\FilterChain', $filters); $this->assertEquals(0, count($filters)); } public function testInputHasEmptyValidatorChainByDefault() { - $input = new Input('foo'); - $validators = $input->getValidatorChain(); + $validators = $this->input->getValidatorChain(); $this->assertInstanceOf('Zend\Validator\ValidatorChain', $validators); $this->assertEquals(0, count($validators)); } public function testCanInjectFilterChain() { - $input = new Input('foo'); $chain = new Filter\FilterChain(); - $input->setFilterChain($chain); - $this->assertSame($chain, $input->getFilterChain()); + $this->input->setFilterChain($chain); + $this->assertSame($chain, $this->input->getFilterChain()); } public function testCanInjectValidatorChain() { - $input = new Input('foo'); $chain = new Validator\ValidatorChain(); - $input->setValidatorChain($chain); - $this->assertSame($chain, $input->getValidatorChain()); + $this->input->setValidatorChain($chain); + $this->assertSame($chain, $this->input->getValidatorChain()); } public function testInputIsMarkedAsRequiredByDefault() { - $input = new Input('foo'); - $this->assertTrue($input->isRequired()); + $this->assertTrue($this->input->isRequired()); } public function testRequiredFlagIsMutable() { - $input = new Input('foo'); - $input->setRequired(false); - $this->assertFalse($input->isRequired()); + $this->input->setRequired(false); + $this->assertFalse($this->input->isRequired()); } public function testInputDoesNotAllowEmptyValuesByDefault() { - $input = new Input('foo'); - $this->assertFalse($input->allowEmpty()); + $this->assertFalse($this->input->allowEmpty()); } public function testAllowEmptyFlagIsMutable() + { + $this->input->setAllowEmpty(true); + $this->assertTrue($this->input->allowEmpty()); + } + + public function testContinueIfEmptyFlagIsFalseByDefault() { $input = new Input('foo'); - $input->setAllowEmpty(true); - $this->assertTrue($input->allowEmpty()); + $this->assertFalse($input->continueIfEmpty()); } - public function testValueIsNullByDefault() + public function testContinueIfEmptyFlagIsMutable() { $input = new Input('foo'); - $this->assertNull($input->getValue()); + $input->setContinueIfEmpty(true); + $this->assertTrue($input->continueIfEmpty()); } - public function testValueMayBeInjected() + public function testNotEmptyValidatorNotInjectedIfContinueIfEmptyIsTrue() { $input = new Input('foo'); - $input->setValue('bar'); - $this->assertEquals('bar', $input->getValue()); + $input->setContinueIfEmpty(true); + $input->setValue(''); + $input->isValid(); + $validators = $input->getValidatorChain() + ->getValidators(); + $this->assertTrue(0 == count($validators)); + } + + public function testValueIsNullByDefault() + { + $this->assertNull($this->input->getValue()); + } + + public function testValueMayBeInjected() + { + $this->input->setValue('bar'); + $this->assertEquals('bar', $this->input->getValue()); } public function testRetrievingValueFiltersTheValue() { - $input = new Input('foo'); - $input->setValue('bar'); + $this->input->setValue('bar'); $filter = new Filter\StringToUpper(); - $input->getFilterChain()->attach($filter); - $this->assertEquals('BAR', $input->getValue()); + $this->input->getFilterChain()->attach($filter); + $this->assertEquals('BAR', $this->input->getValue()); } public function testCanRetrieveRawValue() { - $input = new Input('foo'); - $input->setValue('bar'); + $this->input->setValue('bar'); $filter = new Filter\StringToUpper(); - $input->getFilterChain()->attach($filter); - $this->assertEquals('bar', $input->getRawValue()); + $this->input->getFilterChain()->attach($filter); + $this->assertEquals('bar', $this->input->getRawValue()); } public function testIsValidReturnsFalseIfValidationChainFails() { - $input = new Input('foo'); - $input->setValue('bar'); + $this->input->setValue('bar'); $validator = new Validator\Digits(); - $input->getValidatorChain()->attach($validator); - $this->assertFalse($input->isValid()); + $this->input->getValidatorChain()->attach($validator); + $this->assertFalse($this->input->isValid()); } public function testIsValidReturnsTrueIfValidationChainSucceeds() { - $input = new Input('foo'); - $input->setValue('123'); + $this->input->setValue('123'); $validator = new Validator\Digits(); - $input->getValidatorChain()->attach($validator); - $this->assertTrue($input->isValid()); + $this->input->getValidatorChain()->attach($validator); + $this->assertTrue($this->input->isValid()); } public function testValidationOperatesOnFilteredValue() { - $input = new Input('foo'); - $input->setValue(' 123 '); + $this->input->setValue(' 123 '); $filter = new Filter\StringTrim(); - $input->getFilterChain()->attach($filter); + $this->input->getFilterChain()->attach($filter); $validator = new Validator\Digits(); - $input->getValidatorChain()->attach($validator); - $this->assertTrue($input->isValid()); + $this->input->getValidatorChain()->attach($validator); + $this->assertTrue($this->input->isValid()); } public function testGetMessagesReturnsValidationMessages() { - $input = new Input('foo'); - $input->setValue('bar'); + $this->input->setValue('bar'); $validator = new Validator\Digits(); - $input->getValidatorChain()->attach($validator); - $this->assertFalse($input->isValid()); - $messages = $input->getMessages(); + $this->input->getValidatorChain()->attach($validator); + $this->assertFalse($this->input->isValid()); + $messages = $this->input->getMessages(); $this->assertArrayHasKey(Validator\Digits::NOT_DIGITS, $messages); } public function testSpecifyingMessagesToInputReturnsThoseOnFailedValidation() { - $input = new Input('foo'); - $input->setValue('bar'); + $this->input->setValue('bar'); $validator = new Validator\Digits(); - $input->getValidatorChain()->attach($validator); - $input->setErrorMessage('Please enter only digits'); - $this->assertFalse($input->isValid()); - $messages = $input->getMessages(); + $this->input->getValidatorChain()->attach($validator); + $this->input->setErrorMessage('Please enter only digits'); + $this->assertFalse($this->input->isValid()); + $messages = $this->input->getMessages(); $this->assertArrayNotHasKey(Validator\Digits::NOT_DIGITS, $messages); $this->assertContains('Please enter only digits', $messages); } public function testBreakOnFailureFlagIsOffByDefault() { - $input = new Input('foo'); - $this->assertFalse($input->breakOnFailure()); + $this->assertFalse($this->input->breakOnFailure()); } public function testBreakOnFailureFlagIsMutable() { - $input = new Input('foo'); - $input->setBreakOnFailure(true); - $this->assertTrue($input->breakOnFailure()); + $this->input->setBreakOnFailure(true); + $this->assertTrue($this->input->breakOnFailure()); } public function testNotEmptyValidatorAddedWhenIsValidIsCalled() { - $input = new Input('foo'); - $this->assertTrue($input->isRequired()); - $input->setValue(''); - $validatorChain = $input->getValidatorChain(); + $this->assertTrue($this->input->isRequired()); + $this->input->setValue(''); + $validatorChain = $this->input->getValidatorChain(); $this->assertEquals(0, count($validatorChain->getValidators())); - $this->assertFalse($input->isValid()); - $messages = $input->getMessages(); + $this->assertFalse($this->input->isValid()); + $messages = $this->input->getMessages(); $this->assertArrayHasKey('isEmpty', $messages); $this->assertEquals(1, count($validatorChain->getValidators())); // Assert that NotEmpty validator wasn't added again - $this->assertFalse($input->isValid()); + $this->assertFalse($this->input->isValid()); $this->assertEquals(1, count($validatorChain->getValidators())); } public function testRequiredNotEmptyValidatorNotAddedWhenOneExists() { - $input = new Input('foo'); - $this->assertTrue($input->isRequired()); - $input->setValue(''); + $this->assertTrue($this->input->isRequired()); + $this->input->setValue(''); $notEmptyMock = $this->getMock('Zend\Validator\NotEmpty', array('isValid')); $notEmptyMock->expects($this->exactly(1)) ->method('isValid') ->will($this->returnValue(false)); - $validatorChain = $input->getValidatorChain(); + $validatorChain = $this->input->getValidatorChain(); $validatorChain->prependValidator($notEmptyMock); - $this->assertFalse($input->isValid()); + $this->assertFalse($this->input->isValid()); $validators = $validatorChain->getValidators(); $this->assertEquals(1, count($validators)); @@ -218,7 +230,7 @@ public function testRequiredNotEmptyValidatorNotAddedWhenOneExists() public function testMerge() { - $input = new Input('foo'); + $input = new Input('foo'); $input->setValue(' 123 '); $filter = new Filter\StringTrim(); $input->getFilterChain()->attach($filter); @@ -243,19 +255,18 @@ public function testMerge() public function testDoNotInjectNotEmptyValidatorIfAnywhereInChain() { - $input = new Input('foo'); - $this->assertTrue($input->isRequired()); - $input->setValue(''); + $this->assertTrue($this->input->isRequired()); + $this->input->setValue(''); $notEmptyMock = $this->getMock('Zend\Validator\NotEmpty', array('isValid')); $notEmptyMock->expects($this->exactly(1)) ->method('isValid') ->will($this->returnValue(false)); - $validatorChain = $input->getValidatorChain(); - $validatorChain->addValidator(new Validator\Digits()); - $validatorChain->addValidator($notEmptyMock); - $this->assertFalse($input->isValid()); + $validatorChain = $this->input->getValidatorChain(); + $validatorChain->attach(new Validator\Digits()); + $validatorChain->attach($notEmptyMock); + $this->assertFalse($this->input->isValid()); $validators = $validatorChain->getValidators(); $this->assertEquals(2, count($validators));