mirror of
https://github.com/Respect/Validation.git
synced 2024-06-08 00:32:16 +02:00
Refactor Factory class
With this code the Factory class will be used also to create Exceptions. In order to do that, the AbstractRule::reportError() was changed, so the tests of the AbstractRule class. What this commit also does: - Port code to PHP 7; - Do not keep the default instance of the Factory in the Validator class; - Make Factory final.
This commit is contained in:
parent
2417080c4e
commit
1f217dda66
|
@ -234,6 +234,7 @@ a rule and an exception to go with the rule.
|
|||
To create a rule, you need to create a class that extends the AbstractRule class
|
||||
and is within the Rules `namespace`. When the rule is called the logic inside the
|
||||
validate method will be executed. Here's how the class should look:
|
||||
|
||||
```php
|
||||
namespace My\Validation\Rules;
|
||||
|
||||
|
@ -253,6 +254,7 @@ with the name of the rule followed by the word Exception. The process of creatin
|
|||
an Exception is similar to creating a rule but there are no methods in the
|
||||
Exception class. Instead, you create one static property that includes an
|
||||
array with the information below:
|
||||
|
||||
```php
|
||||
namespace My\Validation\Exceptions;
|
||||
|
||||
|
@ -274,6 +276,7 @@ class MyRuleException extends ValidationException
|
|||
So in the end, the folder structure for your Rules and Exceptions should look
|
||||
something like the structure below. Note that the folders (and namespaces) are
|
||||
plural but the actual Rules and Exceptions are singular.
|
||||
|
||||
```
|
||||
My
|
||||
+-- Validation
|
||||
|
@ -283,20 +286,19 @@ My
|
|||
+-- MyRule.php
|
||||
```
|
||||
|
||||
If you want Validation to execute your rule (or rules) in the chain, you must
|
||||
use `v::with()` passing your rule's namespace as an argument:
|
||||
All classes in Validation are created by the `Factory` class. If you want
|
||||
Validation to execute your rule (or rules) in the chain, you must overwrite the
|
||||
default `Factory`.
|
||||
|
||||
```php
|
||||
v::with('My\\Validation\\Rules\\');
|
||||
Factory::setDefaultInstance(
|
||||
new Factory(
|
||||
['My\\Validation\\Rules'],
|
||||
['My\\Validation\\Exceptions']
|
||||
)
|
||||
);
|
||||
v::myRule(); // Try to load "My\Validation\Rules\MyRule" if any
|
||||
```
|
||||
|
||||
By default `with()` appends the given prefix, but you can change this behavior
|
||||
in order to overwrite default rules:
|
||||
|
||||
```php
|
||||
v::with('My\\Validation\\Rules', true);
|
||||
v::alnum(); // Try to use "My\Validation\Rules\Alnum" if any
|
||||
v::alnum(); // Try to use "My\Validation\Rules\Alnum" if any, or else "Respect\Validation\Rules\Alnum"
|
||||
```
|
||||
|
||||
## Validator name
|
||||
|
|
25
library/Exceptions/InvalidClassException.php
Normal file
25
library/Exceptions/InvalidClassException.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?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\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception for invalid classes.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
final class InvalidClassException extends ComponentException
|
||||
{
|
||||
}
|
18
library/Exceptions/ValidatorException.php
Normal file
18
library/Exceptions/ValidatorException.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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\Exceptions;
|
||||
|
||||
final class ValidatorException extends AllOfException
|
||||
{
|
||||
}
|
|
@ -13,56 +13,234 @@ declare(strict_types=1);
|
|||
|
||||
namespace Respect\Validation;
|
||||
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_unique;
|
||||
use function class_exists;
|
||||
use function lcfirst;
|
||||
use function Respect\Stringifier\stringify;
|
||||
use ReflectionClass;
|
||||
use ReflectionObject;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Exceptions\InvalidClassException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
|
||||
class Factory
|
||||
/**
|
||||
* Factory of objects.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*
|
||||
* @since 0.8.0
|
||||
*/
|
||||
final class Factory
|
||||
{
|
||||
protected $rulePrefixes = ['Respect\\Validation\\Rules\\'];
|
||||
private const DEFAULT_RULES_NAMESPACES = [
|
||||
'Respect\\Validation\\Rules',
|
||||
'Respect\\Validation\\Rules\\Locale',
|
||||
'Respect\\Validation\\Rules\\SubdivisionCode',
|
||||
];
|
||||
|
||||
public function getRulePrefixes()
|
||||
private const DEFAULT_EXCEPTIONS_NAMESPACES = [
|
||||
'Respect\\Validation\\Exceptions',
|
||||
'Respect\\Validation\\Exceptions\\Locale',
|
||||
'Respect\\Validation\\Exceptions\\SubdivisionCode',
|
||||
];
|
||||
|
||||
/**
|
||||
* Default instance of the Factory.
|
||||
*
|
||||
* @var Factory
|
||||
*/
|
||||
private static $defaultInstance;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $rulesNamespaces = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $exceptionsNamespaces = [];
|
||||
|
||||
/**
|
||||
* Initializes the factory with the defined namespaces.
|
||||
*
|
||||
* If the default namespace is not in the array, it will be add to the end
|
||||
* of the array.
|
||||
*
|
||||
* @param string[] $rulesNamespaces
|
||||
* @param string[] $exceptionsNamespaces
|
||||
*/
|
||||
public function __construct(array $rulesNamespaces, array $exceptionsNamespaces)
|
||||
{
|
||||
return $this->rulePrefixes;
|
||||
$this->rulesNamespaces = $this->filterNamespaces($rulesNamespaces, self::DEFAULT_RULES_NAMESPACES);
|
||||
$this->exceptionsNamespaces = $this->filterNamespaces($exceptionsNamespaces, self::DEFAULT_EXCEPTIONS_NAMESPACES);
|
||||
}
|
||||
|
||||
private function filterRulePrefix($rulePrefix)
|
||||
/**
|
||||
* Define the default instance of the Factory.
|
||||
*
|
||||
* @param Factory $defaultInstance
|
||||
*/
|
||||
public static function setDefaultInstance(self $defaultInstance): void
|
||||
{
|
||||
$namespaceSeparator = '\\';
|
||||
$rulePrefix = rtrim($rulePrefix, $namespaceSeparator);
|
||||
|
||||
return $rulePrefix.$namespaceSeparator;
|
||||
self::$defaultInstance = $defaultInstance;
|
||||
}
|
||||
|
||||
public function appendRulePrefix($rulePrefix): void
|
||||
/**
|
||||
* Returns the default instance of the Factory.
|
||||
*
|
||||
* @return Factory
|
||||
*/
|
||||
public static function getDefaultInstance(): self
|
||||
{
|
||||
array_push($this->rulePrefixes, $this->filterRulePrefix($rulePrefix));
|
||||
}
|
||||
|
||||
public function prependRulePrefix($rulePrefix): void
|
||||
{
|
||||
array_unshift($this->rulePrefixes, $this->filterRulePrefix($rulePrefix));
|
||||
}
|
||||
|
||||
public function rule($ruleName, array $arguments = [])
|
||||
{
|
||||
if ($ruleName instanceof Validatable) {
|
||||
return $ruleName;
|
||||
if (null === self::$defaultInstance) {
|
||||
self::$defaultInstance = new self(self::DEFAULT_RULES_NAMESPACES, self::DEFAULT_EXCEPTIONS_NAMESPACES);
|
||||
}
|
||||
|
||||
foreach ($this->getRulePrefixes() as $prefix) {
|
||||
$className = $prefix.ucfirst($ruleName);
|
||||
return self::$defaultInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rule.
|
||||
*
|
||||
* @param string $ruleName
|
||||
* @param array $arguments
|
||||
*
|
||||
* @throws ComponentException
|
||||
*
|
||||
* @return Validatable
|
||||
*/
|
||||
public function rule(string $ruleName, array $arguments = []): Validatable
|
||||
{
|
||||
foreach ($this->rulesNamespaces as $namespace) {
|
||||
$className = sprintf('%s\\%s', $namespace, ucfirst($ruleName));
|
||||
if (!class_exists($className)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reflection = new ReflectionClass($className);
|
||||
if (!$reflection->isSubclassOf(Validatable::class)) {
|
||||
throw new ComponentException(sprintf('"%s" is not a valid respect rule', $className));
|
||||
}
|
||||
|
||||
return $reflection->newInstanceArgs($arguments);
|
||||
return $this->createReflectionClass($className, Validatable::class)->newInstanceArgs($arguments);
|
||||
}
|
||||
|
||||
throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an exception.
|
||||
*
|
||||
*
|
||||
* @param Validatable $validatable
|
||||
* @param mixed $input
|
||||
* @param array $extraParams
|
||||
*
|
||||
* @throws ComponentException
|
||||
*
|
||||
* @return ValidationException
|
||||
*/
|
||||
public function exception(Validatable $validatable, $input, array $extraParams = []): ValidationException
|
||||
{
|
||||
$reflection = new ReflectionObject($validatable);
|
||||
$ruleName = $reflection->getShortName();
|
||||
foreach ($this->exceptionsNamespaces as $namespace) {
|
||||
$exceptionName = sprintf('%s\\%sException', $namespace, $ruleName);
|
||||
if (!class_exists($exceptionName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $validatable->getName() ?: stringify($input);
|
||||
$params = ['input' => $input] + $extraParams + $this->extractPropertiesValues($validatable, $reflection);
|
||||
|
||||
return $this->createValidationException($exceptionName, $name, $params);
|
||||
}
|
||||
|
||||
throw new ComponentException(sprintf('Cannot find exception for "%s" rule', lcfirst($ruleName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reflection based on class name.
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $parentName
|
||||
*
|
||||
* @throws InvalidClassException
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
private function createReflectionClass(string $name, string $parentName): ReflectionClass
|
||||
{
|
||||
$reflection = new ReflectionClass($name);
|
||||
if (!$reflection->isSubclassOf($parentName)) {
|
||||
throw new InvalidClassException(sprintf('"%s" must be an instance of "%s"', $name, $parentName));
|
||||
}
|
||||
|
||||
if (!$reflection->isInstantiable()) {
|
||||
throw new InvalidClassException(sprintf('"%s" must be instantiable', $name));
|
||||
}
|
||||
|
||||
return $reflection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters namespaces.
|
||||
*
|
||||
* Ensure namespaces are in the right format and contain the default namespaces.
|
||||
*
|
||||
* @param array $namespaces
|
||||
* @param array $defaultNamespaces
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function filterNamespaces(array $namespaces, array $defaultNamespaces): array
|
||||
{
|
||||
$filter = function (string $namespace): string {
|
||||
return trim($namespace, '\\');
|
||||
};
|
||||
|
||||
return array_unique(
|
||||
array_merge(
|
||||
array_map($filter, $namespaces),
|
||||
array_map($filter, $defaultNamespaces)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Validation exception.
|
||||
*
|
||||
* @param string $exceptionName
|
||||
* @param mixed $name
|
||||
* @param array $params
|
||||
*
|
||||
* @return ValidationException
|
||||
*/
|
||||
private function createValidationException(string $exceptionName, $name, array $params): ValidationException
|
||||
{
|
||||
$exception = $this->createReflectionClass($exceptionName, ValidationException::class)->newInstance();
|
||||
$exception->configure($name, $params);
|
||||
if (isset($params['template'])) {
|
||||
$exception->setTemplate($params['template']);
|
||||
}
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Validatable $validatable
|
||||
* @param ReflectionObject $reflection
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function extractPropertiesValues(Validatable $validatable, ReflectionObject $reflection): array
|
||||
{
|
||||
$values = [];
|
||||
foreach ($reflection->getProperties() as $property) {
|
||||
$property->setAccessible(true);
|
||||
|
||||
$values[$property->getName()] = $property->getValue($validatable);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ declare(strict_types=1);
|
|||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Factory;
|
||||
use Respect\Validation\Validatable;
|
||||
use Respect\Validation\Validator;
|
||||
|
||||
abstract class AbstractRule implements Validatable
|
||||
{
|
||||
|
@ -31,6 +33,7 @@ abstract class AbstractRule implements Validatable
|
|||
if ($this->validate($input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw $this->reportError($input);
|
||||
}
|
||||
|
||||
|
@ -46,20 +49,7 @@ abstract class AbstractRule implements Validatable
|
|||
|
||||
public function reportError($input, array $extraParams = [])
|
||||
{
|
||||
$exception = $this->createException();
|
||||
$name = $this->name ?: ValidationException::stringify($input);
|
||||
$params = array_merge(
|
||||
get_class_vars(__CLASS__),
|
||||
get_object_vars($this),
|
||||
$extraParams,
|
||||
compact('input')
|
||||
);
|
||||
$exception->configure($name, $params);
|
||||
if (!is_null($this->template)) {
|
||||
$exception->setTemplate($this->template);
|
||||
}
|
||||
|
||||
return $exception;
|
||||
return Factory::getDefaultInstance()->exception($this, $input, $extraParams);
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
|
@ -75,13 +65,4 @@ abstract class AbstractRule implements Validatable
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function createException()
|
||||
{
|
||||
$currentFqn = get_called_class();
|
||||
$exceptionFqn = str_replace('\\Rules\\', '\\Exceptions\\', $currentFqn);
|
||||
$exceptionFqn .= 'Exception';
|
||||
|
||||
return new $exceptionFqn();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,41 +161,6 @@ use Respect\Validation\Rules\Key;
|
|||
*/
|
||||
class Validator extends AllOf
|
||||
{
|
||||
protected static $factory;
|
||||
|
||||
/**
|
||||
* @return Factory
|
||||
*/
|
||||
protected static function getFactory()
|
||||
{
|
||||
if (!static::$factory instanceof Factory) {
|
||||
static::$factory = new Factory();
|
||||
}
|
||||
|
||||
return static::$factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Factory $factory
|
||||
*/
|
||||
public static function setFactory($factory): void
|
||||
{
|
||||
static::$factory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rulePrefix
|
||||
* @param bool $prepend
|
||||
*/
|
||||
public static function with($rulePrefix, $prepend = false): void
|
||||
{
|
||||
if (false === $prepend) {
|
||||
self::getFactory()->appendRulePrefix($rulePrefix);
|
||||
} else {
|
||||
self::getFactory()->prependRulePrefix($rulePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
public function check($input)
|
||||
{
|
||||
try {
|
||||
|
@ -235,7 +200,7 @@ class Validator extends AllOf
|
|||
public static function buildRule($ruleSpec, $arguments = [])
|
||||
{
|
||||
try {
|
||||
return static::getFactory()->rule($ruleSpec, $arguments);
|
||||
return Factory::getDefaultInstance()->rule($ruleSpec, $arguments);
|
||||
} catch (\Exception $exception) {
|
||||
throw new ComponentException($exception->getMessage(), $exception->getCode(), $exception);
|
||||
}
|
||||
|
@ -252,11 +217,6 @@ class Validator extends AllOf
|
|||
return $this->addRule(static::buildRule($method, $arguments));
|
||||
}
|
||||
|
||||
protected function createException()
|
||||
{
|
||||
return new AllOfException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create instance validator.
|
||||
*
|
||||
|
|
20
tests/library/Exceptions/StubException.php
Normal file
20
tests/library/Exceptions/StubException.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?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\Exceptions;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
|
||||
final class StubException extends ValidationException
|
||||
{
|
||||
}
|
20
tests/library/Rules/AbstractClass.php
Normal file
20
tests/library/Rules/AbstractClass.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?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\Rules;
|
||||
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
abstract class AbstractClass implements Validatable
|
||||
{
|
||||
}
|
18
tests/library/Rules/Invalid.php
Normal file
18
tests/library/Rules/Invalid.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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\Rules;
|
||||
|
||||
final class Invalid
|
||||
{
|
||||
}
|
57
tests/library/Rules/Stub.php
Normal file
57
tests/library/Rules/Stub.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?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\Rules;
|
||||
|
||||
use function array_shift;
|
||||
use Respect\Validation\Rules\AbstractRule;
|
||||
|
||||
/**
|
||||
* Stub to help testing rules.
|
||||
*
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
final class Stub extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $validations;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $inputs;
|
||||
|
||||
/**
|
||||
* Initializes the rule.
|
||||
*
|
||||
* @param bool[] ...$validations
|
||||
*/
|
||||
public function __construct(bool ...$validations)
|
||||
{
|
||||
$this->validations = $validations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$this->inputs[] = $input;
|
||||
|
||||
return (bool) array_shift($validations);
|
||||
}
|
||||
}
|
27
tests/library/Rules/Valid.php
Normal file
27
tests/library/Rules/Valid.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?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\Rules;
|
||||
|
||||
use Respect\Validation\Rules\AbstractRule;
|
||||
|
||||
final class Valid extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -14,111 +14,210 @@ declare(strict_types=1);
|
|||
namespace Respect\Validation;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Exceptions\EqualsException;
|
||||
use Respect\Validation\Exceptions\InvalidClassException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Rules\Equals;
|
||||
use Respect\Validation\Rules\Uppercase;
|
||||
use Respect\Validation\Test\Exceptions\StubException;
|
||||
use Respect\Validation\Test\Rules\AbstractClass;
|
||||
use Respect\Validation\Test\Rules\Invalid;
|
||||
use Respect\Validation\Test\Rules\Stub;
|
||||
use Respect\Validation\Test\Rules\Valid;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @covers \Respect\Validation\Factory
|
||||
*/
|
||||
class FactoryTest extends TestCase
|
||||
final class FactoryTest extends TestCase
|
||||
{
|
||||
public function testShouldHaveRulePrefixesByDefault(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
private const TEST_RULES_NAMESPACE = 'Respect\\Validation\\Test\\Rules';
|
||||
private const TEST_EXCEPTIONS_NAMESPACE = 'Respect\\Validation\\Test\\Exceptions';
|
||||
|
||||
self::assertEquals(['Respect\\Validation\\Rules\\'], $factory->getRulePrefixes());
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldCreateARuleByNameBasedOnNamespace(): void
|
||||
{
|
||||
$factory = new Factory([self::TEST_RULES_NAMESPACE], []);
|
||||
|
||||
self::assertInstanceOf(Valid::class, $factory->rule('valid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideRulePrefixes
|
||||
* @test
|
||||
*/
|
||||
public function testShouldBeAbleToAppendANewPrefix($namespace, $expectedNamespace): void
|
||||
public function shouldLookUpToAllNamespacesUntilRuleIsFound(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
$factory->appendRulePrefix($namespace);
|
||||
$factory = new Factory([__NAMESPACE__, self::TEST_RULES_NAMESPACE], []);
|
||||
|
||||
$currentRulePrefixes = $factory->getRulePrefixes();
|
||||
|
||||
self::assertSame(
|
||||
$expectedNamespace,
|
||||
array_pop($currentRulePrefixes),
|
||||
'Appended namespace rule was not found as expected into the prefix list.'.PHP_EOL.
|
||||
sprintf(
|
||||
'Appended "%s", current list is '.PHP_EOL.'%s',
|
||||
$namespace,
|
||||
implode(PHP_EOL, $factory->getRulePrefixes())
|
||||
)
|
||||
);
|
||||
self::assertInstanceOf(Valid::class, $factory->rule('valid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideRulePrefixes
|
||||
* @test
|
||||
*/
|
||||
public function testShouldBeAbleToPrependANewRulePrefix($namespace, $expectedNamespace): void
|
||||
public function shouldDefineConstructorArgumentsWhenCreatingARule(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
$factory->prependRulePrefix($namespace);
|
||||
$constructorArguments = [true, false, true, false];
|
||||
|
||||
$currentRulePrefixes = $factory->getRulePrefixes();
|
||||
$factory = new Factory([self::TEST_RULES_NAMESPACE], []);
|
||||
$rule = $factory->rule('stub', $constructorArguments);
|
||||
|
||||
self::assertContains(
|
||||
$expectedNamespace,
|
||||
array_shift($currentRulePrefixes),
|
||||
'Prepended namespace rule was not found as expected into the prefix list.'.PHP_EOL.
|
||||
sprintf(
|
||||
'Prepended "%s", current list is '.PHP_EOL.'%s',
|
||||
$namespace,
|
||||
implode(PHP_EOL, $factory->getRulePrefixes())
|
||||
)
|
||||
);
|
||||
self::assertSame($constructorArguments, $rule->validations);
|
||||
}
|
||||
|
||||
public function provideRulePrefixes()
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldThrowsAnExceptionWhenRuleIsInvalid(): void
|
||||
{
|
||||
return [
|
||||
'Namespace with trailing separator' => [
|
||||
'namespace' => 'My\\Validation\\Rules\\',
|
||||
'expected' => 'My\\Validation\\Rules\\',
|
||||
],
|
||||
'Namespace without trailing separator' => [
|
||||
'namespace' => 'My\\Validation\\Rules',
|
||||
'expected' => 'My\\Validation\\Rules\\',
|
||||
],
|
||||
$factory = new Factory([self::TEST_RULES_NAMESPACE], []);
|
||||
|
||||
$this->expectException(InvalidClassException::class);
|
||||
$this->expectExceptionMessage(sprintf('"%s" must be an instance of "%s"', Invalid::class, Validatable::class));
|
||||
|
||||
$factory->rule('invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldThrowsAnExceptionWhenRuleIsNotInstantiable(): void
|
||||
{
|
||||
$factory = new Factory([self::TEST_RULES_NAMESPACE], []);
|
||||
|
||||
$this->expectException(InvalidClassException::class);
|
||||
$this->expectExceptionMessage(sprintf('"%s" must be instantiable', AbstractClass::class));
|
||||
|
||||
$factory->rule('abstractClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldThrowsAnExceptionWhenRuleIsNotFound(): void
|
||||
{
|
||||
$factory = new Factory([self::TEST_RULES_NAMESPACE], []);
|
||||
|
||||
$this->expectException(ComponentException::class);
|
||||
$this->expectExceptionMessage('"notFoundRule" is not a valid rule name');
|
||||
|
||||
$factory->rule('notFoundRule');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldCreateExceptionBasedOnRule(): void
|
||||
{
|
||||
$factory = new Factory([], [self::TEST_EXCEPTIONS_NAMESPACE]);
|
||||
|
||||
$rule = new Stub();
|
||||
$input = 2;
|
||||
|
||||
self::assertInstanceOf(StubException::class, $factory->exception($rule, $input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldLookUpToAllNamespacesUntilExceptionIsCreated(): void
|
||||
{
|
||||
$factory = new Factory([], [__NAMESPACE__, self::TEST_EXCEPTIONS_NAMESPACE]);
|
||||
|
||||
$rule = new Stub();
|
||||
$input = 2;
|
||||
|
||||
self::assertInstanceOf(StubException::class, $factory->exception($rule, $input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldThrowAnExceptionWhenExceptionIsNotFound(): void
|
||||
{
|
||||
$factory = new Factory([], []);
|
||||
|
||||
$this->expectException(ComponentException::class);
|
||||
$this->expectExceptionMessage('Cannot find exception for "stub" rule');
|
||||
|
||||
$factory->exception(new Stub(), 'foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldSetInputAsParameterOfCreatedException(): void
|
||||
{
|
||||
$factory = new Factory([], [self::TEST_EXCEPTIONS_NAMESPACE]);
|
||||
|
||||
$rule = new Stub();
|
||||
$input = 2;
|
||||
|
||||
$exception = $factory->exception($rule, $input);
|
||||
|
||||
self::assertSame($input, $exception->getParam('input'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldPassPropertiesToCreatedException(): void
|
||||
{
|
||||
$factory = new Factory([], [self::TEST_EXCEPTIONS_NAMESPACE]);
|
||||
|
||||
$validations = [true, false, true, true];
|
||||
$rule = new Stub(...$validations);
|
||||
$input = 2;
|
||||
|
||||
$exception = $factory->exception($rule, $input);
|
||||
|
||||
self::assertSame($validations, $exception->getParam('validations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function shouldSetTemplateWhenTemplateKeyIsDefined(): void
|
||||
{
|
||||
$factory = new Factory([], [self::TEST_EXCEPTIONS_NAMESPACE]);
|
||||
|
||||
$extraParams = [
|
||||
'template' => 'This is my template',
|
||||
];
|
||||
}
|
||||
|
||||
public function testShouldCreateARuleByName(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
$validations = [true, false, true, true];
|
||||
$rule = new Stub(...$validations);
|
||||
$input = 2;
|
||||
|
||||
self::assertInstanceOf(Uppercase::class, $factory->rule('uppercase'));
|
||||
}
|
||||
$exception = $factory->exception($rule, $input, $extraParams);
|
||||
|
||||
public function testShouldDefineConstructorArgumentsWhenCreatingARule(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
$rule = $factory->rule('dateTime', ['Y-m-d']);
|
||||
|
||||
self::assertEquals('Y-m-d', $rule->format);
|
||||
self::assertSame($extraParams['template'], $exception->getTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\ComponentException
|
||||
* @expectedExceptionMessage "uterere" is not a valid rule name
|
||||
* @test
|
||||
*/
|
||||
public function testShouldThrowsAnExceptionWhenRuleNameIsNotValid(): void
|
||||
public function shouldAlwaysReturnTheSameDefaultInstance(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
$factory->rule('uterere');
|
||||
self::assertSame(Factory::getDefaultInstance(), Factory::getDefaultInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\ComponentException
|
||||
* @expectedExceptionMessage "Respect\Validation\Exceptions\AgeException" is not a valid respect rule
|
||||
* @test
|
||||
*/
|
||||
public function testShouldThrowsAnExceptionWhenRuleIsNotInstanceOfRuleInterface(): void
|
||||
public function shouldBeAbleToOverwriteDefaultInstance(): void
|
||||
{
|
||||
$factory = new Factory();
|
||||
$factory->appendRulePrefix('Respect\\Validation\\Exceptions\\');
|
||||
$factory->rule('AgeException');
|
||||
$factory = new Factory([], []);
|
||||
|
||||
$defaultInstance = Factory::getDefaultInstance();
|
||||
|
||||
Factory::setDefaultInstance($factory);
|
||||
|
||||
self::assertSame($factory, Factory::getDefaultInstance());
|
||||
|
||||
Factory::setDefaultInstance($defaultInstance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,63 +126,6 @@ class AbstractRuleTest extends TestCase
|
|||
$abstractRuleMock->check($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Respect\Validation\Rules\AbstractRule::reportError
|
||||
* @covers \Respect\Validation\Rules\AbstractRule::createException
|
||||
*/
|
||||
public function testShouldCreateExceptionBasedOnTheCurrentClassName()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
return $this->markTestSkipped('If you are a HHVM user, and you are in the mood, please fix it');
|
||||
}
|
||||
|
||||
$exceptionMock = $this
|
||||
->getMockBuilder(ValidationException::class)
|
||||
->setMockClassName('MockRule1Exception')
|
||||
->getMock();
|
||||
|
||||
$abstractRuleMock = $this
|
||||
->getMockBuilder(AbstractRule::class)
|
||||
->setMockClassName('MockRule1')
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$exception = $abstractRuleMock->reportError('something');
|
||||
|
||||
self::assertInstanceOf(get_class($exceptionMock), $exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Respect\Validation\Rules\AbstractRule::reportError
|
||||
* @covers \Respect\Validation\Rules\AbstractRule::setTemplate
|
||||
*/
|
||||
public function testShouldUseDefinedTemplateOnCreatedException(): void
|
||||
{
|
||||
$template = 'This is my template';
|
||||
|
||||
$exceptionMock = $this
|
||||
->getMockBuilder(ValidationException::class)
|
||||
->setMethods(['setTemplate'])
|
||||
->getMock();
|
||||
|
||||
$exceptionMock
|
||||
->expects($this->once())
|
||||
->method('setTemplate')
|
||||
->with($template);
|
||||
|
||||
$abstractRuleMock = $this
|
||||
->getMockBuilder(AbstractRule::class)
|
||||
->setMethods(['createException'])
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$abstractRuleMock
|
||||
->expects($this->once())
|
||||
->method('createException')
|
||||
->will($this->returnValue($exceptionMock));
|
||||
|
||||
$abstractRuleMock->setTemplate($template);
|
||||
$abstractRuleMock->reportError('something');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Respect\Validation\Rules\AbstractRule::setTemplate
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue