Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Commit

Permalink
Required Validator
Browse files Browse the repository at this point in the history
  • Loading branch information
Maks3w committed Oct 10, 2015
1 parent a46714e commit f770d2d
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 77 deletions.
8 changes: 3 additions & 5 deletions src/ArrayInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,22 @@ public function isValid($context = null)
$hasValue = $this->hasValue();
$required = $this->isRequired();
$hasFallback = $this->hasFallback();
$values = $this->getValue();

if (! $hasValue && $hasFallback) {
$this->setValue($this->getFallbackValue());
return true;
}

if (! $hasValue && $required) {
if ($this->errorMessage === null) {
$this->errorMessage = $this->prepareRequiredValidationFailureMessage();
}
return false;
$this->injectRequiredValidator();
$values = [$this];
}

if (!$this->continueIfEmpty() && !$this->allowEmpty()) {
$this->injectNotEmptyValidator();
}
$validator = $this->getValidatorChain();
$values = $this->getValue();
$result = true;
foreach ($values as $value) {
$empty = ($value === null || $value === '' || $value === []);
Expand Down
8 changes: 3 additions & 5 deletions src/FileInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,15 @@ public function isValid($context = null)
$required = $this->isRequired();
$allowEmpty = $this->allowEmpty();
$continueIfEmpty = $this->continueIfEmpty();
$validator = $this->getValidatorChain();

if (! $hasValue && ! $required) {
return true;
}

if (! $hasValue && $required && ! $this->hasFallback()) {
if ($this->errorMessage === null) {
$this->errorMessage = $this->prepareRequiredValidationFailureMessage();
}
return false;
$this->injectRequiredValidator();
return $validator->isValid($this);
}

if ($empty && ! $required && ! $continueIfEmpty) {
Expand All @@ -139,7 +138,6 @@ public function isValid($context = null)
}

$this->injectUploadValidator();
$validator = $this->getValidatorChain();
//$value = $this->getValue(); // Do not run the filters yet for File uploads (see getValue())

if (!is_array($rawValue)) {
Expand Down
40 changes: 27 additions & 13 deletions src/Input.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class Input implements
*/
protected $notEmptyValidator = false;

/**
* @var bool If required validator is in the validator chain.
*/
protected $requiredValidator = false;

/**
* @var bool
*/
Expand Down Expand Up @@ -403,10 +408,8 @@ public function isValid($context = null)
}

if (! $hasValue && $required) {
if ($this->errorMessage === null) {
$this->errorMessage = $this->prepareRequiredValidationFailureMessage();
}
return false;
$this->injectRequiredValidator();
$value = $this;
}

if ($empty && ! $required && ! $continueIfEmpty) {
Expand Down Expand Up @@ -485,16 +488,27 @@ protected function injectNotEmptyValidator()
}

/**
* Create and return the validation failure message for required input.
*
* @return string[]
* @return void
*/
protected function prepareRequiredValidationFailureMessage()
protected function injectRequiredValidator()
{
$notEmpty = new NotEmpty();
$templates = $notEmpty->getOption('messageTemplates');
return [
NotEmpty::IS_EMPTY => $templates[NotEmpty::IS_EMPTY],
];
if ($this->requiredValidator) {
return;
}

$chain = $this->getValidatorChain();

// Check if Required validator is already in chain
$validators = $chain->getValidators();
foreach ($validators as $validator) {
if ($validator['instance'] instanceof Validator\Required) {
$this->requiredValidator = true;
return;
}
}

$this->requiredValidator = true;

$chain->prependValidator(new Validator\Required(), true);
}
}
44 changes: 44 additions & 0 deletions src/Validator/Required.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Zend\InputFilter\Validator;

use Zend\InputFilter\Input;
use Zend\Validator\AbstractValidator;

class Required extends AbstractValidator
{
const INVALID = 'inputInvalid';
const REQUIRED = 'inputRequired';

/**
* @var string[]
*/
protected $messageTemplates = [
self::INVALID => 'Invalid type given. Zend\InputFilter\Input is required',
self::REQUIRED => 'Value is required',
];

/**
* {@inheritDoc}
*/
public function isValid($value)
{
if (!($value instanceof Input)) {
$this->error(self::INVALID);
return false;
}

$input = $value;

if ($input->hasValue()) { // If has value then all is ok
return true;
}

if ($input->isRequired()) { // It's Required and value was not set.
$this->error(self::REQUIRED);
return false;
}

return true;
}
}
62 changes: 8 additions & 54 deletions test/InputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,6 @@ public function setUp()
$this->input = new Input('foo');
}

public function assertRequiredValidationErrorMessage(Input $input, $message = '')
{
$message = $message ?: 'Expected failure message for required input';
$message .= ';';

$messages = $input->getMessages();
$this->assertInternalType('array', $messages, $message . ' non-array messages array');

$notEmpty = new NotEmptyValidator();
$messageTemplates = $notEmpty->getOption('messageTemplates');
$this->assertSame([
NotEmptyValidator::IS_EMPTY => $messageTemplates[NotEmptyValidator::IS_EMPTY],
], $messages, $message . ' missing NotEmpty::IS_EMPTY key and/or contains additional messages');
}

public function testConstructorRequiresAName()
{
$this->assertEquals('foo', $this->input->getName());
Expand Down Expand Up @@ -183,59 +168,28 @@ public function testRequiredWithoutFallbackAndValueNotSetThenFail()
$input = $this->input;
$input->setRequired(true);

$this->assertFalse(
$input->isValid(),
'isValid() should be return always false when no fallback value, is required, and not data is set.'
);
$this->assertRequiredValidationErrorMessage($input);
}

public function testRequiredWithoutFallbackAndValueNotSetThenFailReturnsCustomErrorMessageWhenSet()
{
$input = $this->input;
$input->setRequired(true);
$input->setErrorMessage('FAILED TO VALIDATE');
$expectedMessages = [
'inputRequired' => 'Value is required',
];

$this->assertFalse(
$input->isValid(),
'isValid() should be return always false when no fallback value, is required, and not data is set.'
);
$this->assertSame(['FAILED TO VALIDATE'], $input->getMessages());
$this->assertEquals($expectedMessages, $input->getMessages(), 'getMessages() value not match');
}

/**
* @group 28
* @group 60
*/
public function testRequiredWithoutFallbackAndValueNotSetProvidesNotEmptyValidatorIsEmptyErrorMessage()
{
$input = $this->input;
$input->setRequired(true);

$this->assertFalse(
$input->isValid(),
'isValid() should always return false when no fallback value is present, '
. 'the input is required, and no data is set.'
);
$this->assertRequiredValidationErrorMessage($input);
}

/**
* @group 28
* @group 60
*/
public function testRequiredWithoutFallbackAndValueNotSetProvidesCustomErrorMessageWhenSet()
public function testRequiredWithoutFallbackAndValueNotSetThenFailWithCustomErrorMessage()
{
$input = $this->input;
$input->setRequired(true);
$input->setErrorMessage('FAILED TO VALIDATE');
$input->setErrorMessage('fooErrorMessage');

$this->assertFalse(
$input->isValid(),
'isValid() should always return false when no fallback value is present, '
. 'the input is required, and no data is set.'
'isValid() should be return always false when no fallback value, is required, and not data is set.'
);
$this->assertSame(['FAILED TO VALIDATE'], $input->getMessages());
$this->assertEquals(['fooErrorMessage'], $input->getMessages(), 'getMessages() value not match');
}

public function testNotRequiredWithoutFallbackAndValueNotSetThenIsValid()
Expand Down
88 changes: 88 additions & 0 deletions test/Validator/RequiredTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace ZendTest\InputFilter\Validator;

use PHPUnit_Framework_MockObject_MockObject as MockObject;
use PHPUnit_Framework_TestCase as TestCase;
use Zend\InputFilter\Input;
use Zend\InputFilter\Validator\Required;

/**
* @covers Zend\InputFilter\Validator\Required
*/
class RequiredTest extends TestCase
{
/**
* @var Required
*/
protected $validator;

protected function setUp()
{
$this->validator = new Required();
}

/**
* @dataProvider inputProvider
*/
public function testValid($input, $expectedIsValid, $expectedMessages)
{
$this->assertEquals(
$expectedIsValid,
$this->validator->isValid($input),
'isValid() value not match. Detail: ' . json_encode($this->validator->getMessages())
);

$this->assertEquals(
$expectedMessages,
$this->validator->getMessages(),
'getMessages() value not match.'
);
}

public function inputProvider()
{
$requiredMsg = [
Required::REQUIRED => 'Value is required',
];
$invalidMsg = [
Required::INVALID => 'Invalid type given. Zend\InputFilter\Input is required',
];

$required = true;
$hasValue = true;

// @codingStandardsIgnoreStart
return [
// Description => [$input, isValid, getMessages]
'Invalid type' => [new \stdClass() , false, $invalidMsg],
'Required: T. Value: Set' => [$this->createInputMock($required, $hasValue), true , []],
'Required: T. Value: Not set' => [$this->createInputMock($required, !$hasValue), false, $requiredMsg],
'Required: F. Value: set' => [$this->createInputMock(!$required, $hasValue), true , []],
'Required: F. Value: Not set' => [$this->createInputMock(!$required, !$hasValue), true , []],
];
// @codingStandardsIgnoreEnd
}

/**
* @param bool $required
* @param bool $hasValue
*
* @return Input|MockObject
*/
protected function createInputMock($required, $hasValue)
{
/** @var Input|MockObject $input */
$input = $this->getMock(Input::class);

$input->method('isRequired')
->willReturn($required)
;

$input->method('hasValue')
->willReturn($hasValue)
;

return $input;
}
}

0 comments on commit f770d2d

Please sign in to comment.