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

Commit

Permalink
Merge branch 'feature/170-required-collection-message' into develop
Browse files Browse the repository at this point in the history
Close #170
Fixes #94
  • Loading branch information
weierophinney committed Dec 17, 2018
2 parents 68b5d93 + 9fd3546 commit f48098a
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ All notable changes to this project will be documented in this file, in reverse

### Added

- Nothing.
- [#170](https://github.com/zendframework/zend-inputfilter/pull/170) adds the ability to set a "required" message on a `CollectionInputFilter`.
By default, such instances will lazy-load a `NotEmpty` validator, and use its
messages to report that the collection was empty if it is marked as required.
If you wish to set a different message, you have two options:

- provide a custom `NotEmpty` validator via the new method
`setNotEmptyValidator()`.

- if using a factory, provide the key `required_message` as a sibling to
`required`, containing the custom message. This will replace the typical
`IS_EMPTY` message.

### Changed

Expand Down
63 changes: 59 additions & 4 deletions src/CollectionInputFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace Zend\InputFilter;

use Traversable;
use Zend\Validator\NotEmpty;

class CollectionInputFilter extends InputFilter
{
Expand Down Expand Up @@ -43,6 +44,11 @@ class CollectionInputFilter extends InputFilter
*/
protected $inputFilter;

/**
* @var NotEmpty
*/
protected $notEmptyValidator;

/**
* Set the input filter to use when looping the data
*
Expand Down Expand Up @@ -164,6 +170,39 @@ public function setData($data)
return $this;
}

/**
* Retrieve the NotEmpty validator to use for failed "required" validations.
*
* This validator will be used to produce a validation failure message in
* cases where the collection is empty but required.
*
* @return NotEmpty
*/
public function getNotEmptyValidator()
{
if ($this->notEmptyValidator === null) {
$this->notEmptyValidator = new NotEmpty();
}

return $this->notEmptyValidator;
}

/**
* Set the NotEmpty validator to use for failed "required" validations.
*
* This validator will be used to produce a validation failure message in
* cases where the collection is empty but required.
*
* @param NotEmpty $notEmptyValidator
* @return $this
*/
public function setNotEmptyValidator(NotEmpty $notEmptyValidator)
{
$this->notEmptyValidator = $notEmptyValidator;

return $this;
}

/**
* {@inheritdoc}
* @param mixed $context Ignored, but present to retain signature compatibility.
Expand All @@ -174,10 +213,9 @@ public function isValid($context = null)
$inputFilter = $this->getInputFilter();
$valid = true;

if ($this->getCount() < 1) {
if ($this->isRequired) {
$valid = false;
}
if ($this->getCount() < 1 && $this->isRequired) {
$this->collectionMessages[] = $this->prepareRequiredValidationFailureMessage();
$valid = false;
}

if (count($this->data) < $this->getCount()) {
Expand Down Expand Up @@ -295,4 +333,21 @@ public function getUnknown()

return $unknownInputs;
}

/**
* @return array<string, string>
*/
protected function prepareRequiredValidationFailureMessage()
{
$notEmptyValidator = $this->getNotEmptyValidator();
$templates = $notEmptyValidator->getOption('messageTemplates');
$message = $templates[NotEmpty::IS_EMPTY];
$translator = $notEmptyValidator->getTranslator();

return [
NotEmpty::IS_EMPTY => $translator
? $translator->translate($message, $notEmptyValidator->getTranslatorTextDomain())
: $message,
];
}
}
3 changes: 3 additions & 0 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ public function createInputFilter($inputFilterSpecification)
if (isset($inputFilterSpecification['required'])) {
$inputFilter->setIsRequired($inputFilterSpecification['required']);
}
if (isset($inputFilterSpecification['required_message'])) {
$inputFilter->getNotEmptyValidator()->setMessage($inputFilterSpecification['required_message']);
}
return $inputFilter;
}

Expand Down
32 changes: 31 additions & 1 deletion test/CollectionInputFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public function dataVsValidProvider()
'Required: F, Count: N, Valid: T' => [!$isRequired, null, $colRaw, $validIF , $colRaw, $colFiltered, true , []],
'Required: F, Count: N, Valid: F' => [!$isRequired, null, $colRaw, $invalidIF, $colRaw, $colFiltered, false, $colMessages],
'Required: F, Count: +1, Valid: F' => [!$isRequired, 2, $colRaw, $invalidIF, $colRaw, $colFiltered, false, $colMessages],
'Required: T, Data: [], Valid: X' => [ $isRequired, null, [] , $noValidIF, [] , [] , false, []],
'Required: T, Data: [], Valid: X' => [ $isRequired, null, [] , $noValidIF, [] , [] , false, [['isEmpty' => 'Value is required and can\'t be empty']]],
'Required: F, Data: [], Valid: X' => [!$isRequired, null, [] , $noValidIF, [] , [] , true , []],
];
// @codingStandardsIgnoreEnd
Expand Down Expand Up @@ -735,4 +735,34 @@ public function testDuplicatedErrorMessages()
],
], $inputFilter->getMessages());
}

public function testLazyLoadsANotEmptyValidatorWhenNoneProvided()
{
$this->assertInstanceOf(NotEmpty::class, $this->inputFilter->getNotEmptyValidator());
}

public function testAllowsComposingANotEmptyValidator()
{
$notEmptyValidator = new NotEmpty();
$this->inputFilter->setNotEmptyValidator($notEmptyValidator);
$this->assertSame($notEmptyValidator, $this->inputFilter->getNotEmptyValidator());
}

public function testUsesMessageFromComposedNotEmptyValidatorWhenRequiredButCollectionIsEmpty()
{
$message = 'this is the validation message';
$notEmptyValidator = new NotEmpty();
$notEmptyValidator->setMessage($message);

$this->inputFilter->setIsRequired(true);
$this->inputFilter->setNotEmptyValidator($notEmptyValidator);

$this->inputFilter->setData([]);

$this->assertFalse($this->inputFilter->isValid());

$this->assertEquals([
[NotEmpty::IS_EMPTY => $message],
], $this->inputFilter->getMessages());
}
}
22 changes: 22 additions & 0 deletions test/FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,28 @@ public function testWhenCreateInputPullsInputFromThePluginManagerItMustNotOverwr
$this->assertSame($input->reveal(), $factory->createInput($spec));
}

public function testFactoryCanCreateCollectionInputFilterWithRequiredMessage()
{
$factory = $this->createDefaultFactory();
$message = 'this is the validation message';

/** @var CollectionInputFilter $inputFilter */
$inputFilter = $factory->createInputFilter([
'type' => CollectionInputFilter::class,
'required' => true,
'required_message' => $message,
'inputfilter' => new InputFilter(),
'count' => 3,
]);

$this->assertInstanceOf(CollectionInputFilter::class, $inputFilter);

$notEmptyValidator = $inputFilter->getNotEmptyValidator();
$messageTemplates = $notEmptyValidator->getMessageTemplates();
$this->assertArrayHasKey(Validator\NotEmpty::IS_EMPTY, $messageTemplates);
$this->assertSame($message, $messageTemplates[Validator\NotEmpty::IS_EMPTY]);
}

/**
* @return Factory
*/
Expand Down

0 comments on commit f48098a

Please sign in to comment.