mirror of
https://github.com/Respect/Validation.git
synced 2024-06-04 23:02:16 +02:00
Refactor "Zend" rule
- Only create objects that are instantiable. - Validate if validator is a valid Zend Validator after its creation. - Parse messages from Zend Validator on "assert()" and "check()." - Upgrade supported version of Zend Validator: version 2.0 has some PHP deprecations therefore there is no used to support it. Co-authored-by: Danilo Correa <danilosilva87@gmail.com> Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
parent
df5cb1e6d2
commit
166501804f
|
@ -30,7 +30,7 @@
|
|||
"slevomat/coding-standard": "^5.0",
|
||||
"squizlabs/php_codesniffer": "^3.4",
|
||||
"symfony/validator": "^3.0||^4.0",
|
||||
"zendframework/zend-validator": "^2.0"
|
||||
"zendframework/zend-validator": "^2.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Arbitrary Precision Mathematics",
|
||||
|
|
|
@ -15,19 +15,9 @@ namespace Respect\Validation\Exceptions;
|
|||
|
||||
/**
|
||||
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
final class ZendException extends NestedValidationException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $defaultTemplates = [
|
||||
self::MODE_DEFAULT => [
|
||||
self::STANDARD => '{{name}}',
|
||||
],
|
||||
self::MODE_NEGATIVE => [
|
||||
self::STANDARD => '{{name}}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -15,61 +15,72 @@ namespace Respect\Validation\Rules;
|
|||
|
||||
use ReflectionClass;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Exceptions\ZendException;
|
||||
use Zend\Validator\ValidatorInterface as ZendValidator;
|
||||
use function get_object_vars;
|
||||
use Throwable;
|
||||
use Zend\Validator\ValidatorInterface;
|
||||
use function array_map;
|
||||
use function current;
|
||||
use function is_string;
|
||||
use function mb_stripos;
|
||||
use function sprintf;
|
||||
use function stripos;
|
||||
|
||||
/**
|
||||
* Use Zend validators inside Respect\Validation flow.
|
||||
*
|
||||
* Messages are preserved.
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Hugo Hamon <hugo.hamon@sensiolabs.com>
|
||||
*/
|
||||
final class Zend extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $messages = [];
|
||||
|
||||
/**
|
||||
* @var ZendValidator
|
||||
* @var ValidatorInterface
|
||||
*/
|
||||
private $zendValidator;
|
||||
|
||||
/**
|
||||
* @param string|ZendValidator $validator
|
||||
* @param string|ValidatorInterface $validator
|
||||
* @param mixed[] $params
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function __construct($validator, array $params = [])
|
||||
{
|
||||
if ($validator instanceof ZendValidator) {
|
||||
$this->zendValidator = $validator;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_string($validator)) {
|
||||
throw new ComponentException('Invalid Validator Construct');
|
||||
}
|
||||
|
||||
$this->zendValidator = $this->createZendValidator($validator, $params);
|
||||
$this->zendValidator = $this->zendValidator($validator, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $validator
|
||||
* @param mixed[] $params
|
||||
*
|
||||
* @throws ComponentException
|
||||
*/
|
||||
private function createZendValidator(string $name, array $params): ZendValidator
|
||||
private function zendValidator($validator, array $params = []): ValidatorInterface
|
||||
{
|
||||
$name = mb_stripos($name, 'Zend') === false ? 'Zend\\Validator\\'.$name : '\\'.$name;
|
||||
if ($validator instanceof ValidatorInterface) {
|
||||
return $validator;
|
||||
}
|
||||
|
||||
$reflection = new ReflectionClass($name);
|
||||
if (!is_string($validator)) {
|
||||
throw new ComponentException('The given argument is not a valid Zend Validator');
|
||||
}
|
||||
|
||||
/** @var ZendValidator $validator */
|
||||
$validator = $reflection->newInstanceArgs($params);
|
||||
$className = stripos($validator, 'Zend') === false ? 'Zend\\Validator\\'.$validator : '\\'.$validator;
|
||||
|
||||
return $validator;
|
||||
try {
|
||||
$reflection = new ReflectionClass($className);
|
||||
if (!$reflection->isInstantiable()) {
|
||||
throw new ComponentException(sprintf('"%s" is not instantiable', $className));
|
||||
}
|
||||
|
||||
return $this->zendValidator($reflection->newInstanceArgs($params));
|
||||
} catch (Throwable $exception) {
|
||||
throw new ComponentException(sprintf('Could not create "%s"', $validator), 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,19 +89,40 @@ final class Zend extends AbstractRule
|
|||
public function assert($input): void
|
||||
{
|
||||
$validator = clone $this->zendValidator;
|
||||
|
||||
if ($validator->isValid($input)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$exceptions = [];
|
||||
foreach ($validator->getMessages() as $m) {
|
||||
$exceptions[] = $this->reportError($m, get_object_vars($this));
|
||||
/** @var ZendException $zendException */
|
||||
$zendException = $this->reportError($input);
|
||||
$zendException->addChildren(
|
||||
array_map(
|
||||
function (string $message) use ($input): ValidationException {
|
||||
$exception = $this->reportError($input);
|
||||
$exception->updateTemplate($message);
|
||||
|
||||
return $exception;
|
||||
},
|
||||
$validator->getMessages()
|
||||
)
|
||||
);
|
||||
|
||||
throw $zendException;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function check($input): void
|
||||
{
|
||||
$validator = clone $this->zendValidator;
|
||||
if ($validator->isValid($input)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var ZendException $zendException */
|
||||
$zendException = $this->reportError($input);
|
||||
$zendException->addChildren($exceptions);
|
||||
$zendException->updateTemplate(current($validator->getMessages()));
|
||||
|
||||
throw $zendException;
|
||||
}
|
||||
|
@ -100,8 +132,6 @@ final class Zend extends AbstractRule
|
|||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$validator = clone $this->zendValidator;
|
||||
|
||||
return $validator->isValid($input);
|
||||
return (clone $this->zendValidator)->isValid($input);
|
||||
}
|
||||
}
|
||||
|
|
44
tests/integration/rules/zend.phpt
Normal file
44
tests/integration/rules/zend.phpt
Normal file
|
@ -0,0 +1,44 @@
|
|||
--CREDITS--
|
||||
Danilo Correa <danilosilva87@gmail.com>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Exceptions\NestedValidationException;
|
||||
use Respect\Validation\Exceptions\ZendException;
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
try {
|
||||
v::zend('Hostname')->check('googlecombr');
|
||||
} catch (ZendException $exception) {
|
||||
echo $exception->getMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
v::not(v::zend('Hostname'))->check('google.com.br');
|
||||
} catch (ZendException $exception) {
|
||||
echo $exception->getMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
v::zend('Hostname')->assert('googlecombr');
|
||||
} catch (NestedValidationException $exception) {
|
||||
echo $exception->getFullMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
v::not(v::zend('Hostname'))->assert('google.com.br');
|
||||
} catch (NestedValidationException $exception) {
|
||||
echo $exception->getFullMessage().PHP_EOL;
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
The input does not match the expected structure for a DNS hostname
|
||||
"google.com.br" must not be valid
|
||||
- "googlecombr" must be valid
|
||||
- The input does not match the expected structure for a DNS hostname
|
||||
- The input appears to be a local network name but local network names are not allowed
|
||||
- "google.com.br" must not be valid
|
35
tests/library/Stubs/ZendValidator.php
Normal file
35
tests/library/Stubs/ZendValidator.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Test\Stubs;
|
||||
|
||||
use Zend\Validator\ValidatorInterface;
|
||||
|
||||
final class ZendValidator implements ValidatorInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isValid($value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessages()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -13,153 +13,106 @@ declare(strict_types=1);
|
|||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use DateTime;
|
||||
use Respect\Validation\Test\TestCase;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Test\Rules\Stub;
|
||||
use Respect\Validation\Test\RuleTestCase;
|
||||
use Respect\Validation\Test\Stubs\ZendValidator;
|
||||
use Zend\Validator\ConfigProvider;
|
||||
use Zend\Validator\Date as ZendDate;
|
||||
use Zend\Validator\ValidatorInterface;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @group rule
|
||||
* @covers \Respect\Validation\Exceptions\ZendException
|
||||
* @group rule
|
||||
*
|
||||
* @covers \Respect\Validation\Rules\Zend
|
||||
*
|
||||
* @author Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
* @author Augusto Pascutti <augusto@phpsp.org.br>
|
||||
* @author Danilo Correa <danilosilva87@gmail.com>
|
||||
* @author Gabriel Caruso <carusogabriel34@gmail.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
*/
|
||||
final class ZendTest extends TestCase
|
||||
final class ZendTest extends RuleTestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function constructorWithValidatorName(): void
|
||||
public function providerForValidInput(): array
|
||||
{
|
||||
$v = new Zend('Date');
|
||||
self::assertAttributeInstanceOf(
|
||||
$instanceOf = ValidatorInterface::class,
|
||||
$attribute = 'zendValidator',
|
||||
$instance = $v
|
||||
);
|
||||
return [
|
||||
'Constructor with name' => [new Zend('Date'), '2019-02-05'],
|
||||
'Constructor with class name' => [new Zend(ZendDate::class), '2015-02-05'],
|
||||
'Constructor with custom class name' => [new Zend(ZendValidator::class), '2015-02-05'],
|
||||
'Constructor with instance' => [new Zend(new ZendDate()), '2018-02-05'],
|
||||
'Constructor with custom instance' => [new Zend(new ZendValidator()), 'whatever'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends constructorWithValidatorName
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerForInvalidInput(): array
|
||||
{
|
||||
return [
|
||||
'Zend Date' => [new Zend('Date'), 'abc'],
|
||||
'Constructor with class name' => [new Zend(ZendDate::class), '05/02/19'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function constructorWithValidatorClassName(): void
|
||||
{
|
||||
$v = new Zend(ZendDate::class);
|
||||
self::assertAttributeInstanceOf(
|
||||
$instanceOf = ValidatorInterface::class,
|
||||
$attribute = 'zendValidator',
|
||||
$instance = $v
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function constructorWithZendValidatorInstance(): void
|
||||
{
|
||||
$zendInstance = new ZendDate();
|
||||
$v = new Zend($zendInstance);
|
||||
self::assertAttributeSame(
|
||||
$expected = $zendInstance,
|
||||
$attribute = 'zendValidator',
|
||||
$instance = $v
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends constructorWithZendValidatorInstance
|
||||
* @dataProvider providerForInvalidValidator
|
||||
*
|
||||
* @test
|
||||
* @param mixed $validator
|
||||
*/
|
||||
public function userlandValidatorExtendingZendInterface(): void
|
||||
public function itShouldThrowAnExceptionWhenValidatorIsNotValid($validator): void
|
||||
{
|
||||
$v = new Zend(new ZendDate());
|
||||
self::assertAttributeInstanceOf(
|
||||
$instanceOf = ValidatorInterface::class,
|
||||
$attribute = 'zendValidator',
|
||||
$instance = $v
|
||||
);
|
||||
$this->expectExceptionObject(new ComponentException('The given argument is not a valid Zend Validator'));
|
||||
|
||||
new Zend($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
*/
|
||||
public function providerForInvalidValidator(): array
|
||||
{
|
||||
return [
|
||||
[null],
|
||||
[[]],
|
||||
[new Stub()],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function constructorWithZendValidatorPartialNamespace(): void
|
||||
{
|
||||
$v = new Zend('Sitemap\Lastmod');
|
||||
self::assertAttributeInstanceOf(
|
||||
$instanceOf = ValidatorInterface::class,
|
||||
$attribute = 'zendValidator',
|
||||
$instance = $v
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends constructorWithValidatorName
|
||||
* @depends constructorWithZendValidatorPartialNamespace
|
||||
*
|
||||
* @test
|
||||
* @dataProvider providerForUnbuildableValidator
|
||||
*
|
||||
* @param mixed $validator
|
||||
*/
|
||||
public function constructorWithValidatorNameAndParams(): void
|
||||
public function itShouldThrowAnExceptionWhenValidatorCannotBeCreated(string $validator): void
|
||||
{
|
||||
$zendValidatorName = 'StringLength';
|
||||
$zendValidatorParams = ['min' => 10, 'max' => 25];
|
||||
$v = new Zend($zendValidatorName, $zendValidatorParams);
|
||||
self::assertTrue(
|
||||
$v->validate('12345678901'),
|
||||
'The value should be valid for Zend\'s validator'
|
||||
$this->expectExceptionObject(
|
||||
new ComponentException(sprintf('Could not create "%s"', $validator))
|
||||
);
|
||||
|
||||
new Zend($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends constructorWithValidatorName
|
||||
*
|
||||
* @test
|
||||
* @return string[][]
|
||||
*/
|
||||
public function zendDateValidatorWithRespectMethods(): void
|
||||
public function providerForUnbuildableValidator(): array
|
||||
{
|
||||
$v = new Zend('Date');
|
||||
$date = new DateTime();
|
||||
self::assertTrue($v->validate($date));
|
||||
$v->assert($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends constructorWithValidatorName
|
||||
* @depends zendDateValidatorWithRespectMethods
|
||||
* @expectedException \Respect\Validation\Exceptions\ZendException
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function respectExceptionForFailedValidation(): void
|
||||
{
|
||||
$v = new Zend('Date');
|
||||
$notValid = 'a';
|
||||
self::assertFalse(
|
||||
$v->validate($notValid),
|
||||
'The validator returned true for an invalid value, this won\'t cause an exception later on.'
|
||||
);
|
||||
$v->assert($notValid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends constructorWithValidatorName
|
||||
* @depends constructorWithValidatorNameAndParams
|
||||
* @depends zendDateValidatorWithRespectMethods
|
||||
* @expectedException \Respect\Validation\Exceptions\ZendException
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function paramsNot(): void
|
||||
{
|
||||
$v = new Zend('StringLength', ['min' => 10, 'max' => 25]);
|
||||
$v->assert('aw');
|
||||
return [
|
||||
['ConfigProvider'],
|
||||
[ConfigProvider::class],
|
||||
['Zend\\Nonexistent\\Class'],
|
||||
[ValidatorInterface::class],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue