Skip to content

Commit

Permalink
Merge pull request #154 from zf-fr/errors-for-nested-inputfilters
Browse files Browse the repository at this point in the history
Add support for nested input filters for errors
  • Loading branch information
bakura10 committed Apr 29, 2014
2 parents 2721ae0 + cecb529 commit 3ea4570
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Association mapping can now accept one new property: `collectionController`. It allows to map a specific
association resource to a specific controller, instead of using the target entity mapping.
* Add a doc section about optimizing ZfrRest for performance
* Nested input filters are now supported when errors occur on POST on PUT

## 0.2.3

Expand Down
Binary file modified db.sqlite
Binary file not shown.
23 changes: 16 additions & 7 deletions src/ZfrRest/Mvc/Controller/MethodHandler/DataValidationTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace ZfrRest\Mvc\Controller\MethodHandler;

use Zend\InputFilter\InputFilterInterface;
use Zend\InputFilter\InputFilterPluginManager;
use ZfrRest\Http\Exception\Client\UnprocessableEntityException;
use ZfrRest\Mvc\Controller\AbstractRestfulController;
Expand Down Expand Up @@ -62,23 +63,31 @@ public function validateData(ResourceInterface $resource, array $data, AbstractR
if (!$inputFilter->isValid($validationContext)) {
throw new UnprocessableEntityException(
'Validation error',
$this->formatErrorMessages($inputFilter->getMessages())
$this->extractErrorMessages($inputFilter)
);
}

return $inputFilter->getValues();
}

/**
* Format error messages. It removes message keys
* Extract error messages from the input filter
*
* @param array $errorMessages
* @param InputFilterInterface $inputFilter
* @return array
*/
protected function formatErrorMessages(array $errorMessages)
protected function extractErrorMessages(InputFilterInterface $inputFilter)
{
return array_map(function ($element) {
return array_values($element);
}, $errorMessages);
$errorMessages = $inputFilter->getMessages();

array_walk($errorMessages, function (&$value, $key) use ($inputFilter) {
if ($inputFilter->has($key) && $inputFilter->get($key) instanceof InputFilterInterface) {
$value = $this->extractErrorMessages($inputFilter->get($key));
} else {
$value = array_values($value);
}
});

return $errorMessages;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
namespace ZfrRestTest\Mvc\Controller\MethodHandler;

use PHPUnit_Framework_TestCase;
use Zend\InputFilter\InputFilter;
use ZfrRest\Http\Exception\Client\UnprocessableEntityException;
use ZfrRestTest\Asset\Mvc\DataValidationObject;

/**
Expand Down Expand Up @@ -98,30 +100,83 @@ public function testCanValidateData()

public function testThrowExceptionOnFailedValidation()
{
$this->setExpectedException('ZfrRest\Http\Exception\Client\UnprocessableEntityException');

$resource = $this->getMock('ZfrRest\Resource\ResourceInterface');
$metadata = $this->getMock('ZfrRest\Resource\Metadata\ResourceMetadataInterface');

$resource->expects($this->once())->method('getMetadata')->will($this->returnValue($metadata));
$metadata->expects($this->once())->method('getInputFilterName')->will($this->returnValue('inputFilter'));

$data = ['foo'];
$errorMessages = ['email' => ['Email is invalid']];
$data = ['foo'];

$inputFilter = $this->getMock('Zend\InputFilter\InputFilterInterface');
$inputFilter->expects($this->once())->method('setData')->with($data);
$inputFilter->expects($this->once())->method('getMessages')->will($this->returnValue($errorMessages));
$inputFilter->expects($this->once())
->method('isValid')
->will($this->returnValue(false));
$inputFilter = new InputFilter();
$inputFilter->add([
'name' => 'email',
'required' => true
]);

$controller = $this->getMock('ZfrRest\Mvc\Controller\AbstractRestfulController');
$controller->expects($this->once())
->method('getInputFilter')
->with($this->inputFilterPluginManager, 'inputFilter')
->will($this->returnValue($inputFilter));

$this->dataValidation->validateData($resource, $data, $controller);
$exceptionTriggered = false;
$errorMessages = ['email' => ['Value is required and can\'t be empty']];

try {
$this->dataValidation->validateData($resource, $data, $controller);
} catch(UnprocessableEntityException $exception) {
$exceptionTriggered = true;
$this->assertEquals($errorMessages, $exception->getErrors());
}

$this->assertTrue($exceptionTriggered);
}

public function testThrowExceptionOnFailedValidationWithNestedInputFilter()
{
$resource = $this->getMock('ZfrRest\Resource\ResourceInterface');
$metadata = $this->getMock('ZfrRest\Resource\Metadata\ResourceMetadataInterface');

$resource->expects($this->once())->method('getMetadata')->will($this->returnValue($metadata));
$metadata->expects($this->once())->method('getInputFilterName')->will($this->returnValue('inputFilter'));

$data = ['foo'];

$inputFilter = new InputFilter();
$inputFilter->add([
'name' => 'email',
'required' => true
]);

$inputFilter->add([
'type' => 'Zend\InputFilter\InputFilter',
'city' => [
'name' => 'address'
]
], 'address');

$controller = $this->getMock('ZfrRest\Mvc\Controller\AbstractRestfulController');
$controller->expects($this->once())
->method('getInputFilter')
->with($this->inputFilterPluginManager, 'inputFilter')
->will($this->returnValue($inputFilter));

$exceptionTriggered = false;
$errorMessages = [
'email' => ['Value is required and can\'t be empty'],
'address' => [
'city' => ['Value is required and can\'t be empty']
]
];

try {
$this->dataValidation->validateData($resource, $data, $controller);
} catch(UnprocessableEntityException $exception) {
$exceptionTriggered = true;
$this->assertEquals($errorMessages, $exception->getErrors());
}

$this->assertTrue($exceptionTriggered);
}
}

0 comments on commit 3ea4570

Please sign in to comment.