-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #56 from programmatordev/YAPV-22-create-regex-rule
Create Regex rule
- Loading branch information
Showing
8 changed files
with
211 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Regex | ||
|
||
Validates that a given regular expression pattern is valid. | ||
|
||
```php | ||
Regex( | ||
string $pattern, | ||
bool $match = true, | ||
?callable $normalizer = null, | ||
?string $message = null | ||
); | ||
``` | ||
|
||
## Basic Usage | ||
|
||
```php | ||
Validator::regex('/[a-z]/')->validate('abc'); // true | ||
Validator::regex('/[a-z]/')->validate('123'); // false | ||
|
||
// if match is false, assert that the pattern does not match | ||
// in this case, assert that the value does not contain any lowercase letters | ||
Validator::regex('/[a-z]/', match: false)->validate('abc'); // false | ||
Validator::regex('/[a-z]/', match: false)->validate('123'); // true | ||
``` | ||
|
||
> [!NOTE] | ||
> An `UnexpectedValueException` will be thrown if the `pattern` is not a valid regular expression. | ||
> [!NOTE] | ||
> An `UnexpectedValueException` will be thrown when the input value is not a `string` or an object implementing `\Stringable`. | ||
## Options | ||
|
||
### `pattern` | ||
|
||
type: `string` | ||
|
||
Regular expression pattern to be matched against. | ||
|
||
### `match` | ||
|
||
type: `bool` default: `true` | ||
|
||
- `true` the validation will pass if the given input value matches the regular expression pattern. | ||
- `false` the validation will pass if the given input value *does not* match the regular expression pattern. | ||
|
||
### `normalizer` | ||
|
||
type: `callable` default: `null` | ||
|
||
Allows to define a `callable` that will be applied to the value before checking if it is valid. | ||
|
||
For example, use `trim`, or pass your own function, to not evaluate whitespaces at the end of a string: | ||
|
||
```php | ||
// allow all chars except whitespaces | ||
Validator::length(pattern: '/^\S*$/')->validate('abc '); // false | ||
|
||
Validator::length(pattern: '/^\S*$/', normalizer: 'trim')->validate('abc '); // true | ||
Validator::length(pattern: '/^\S*$/', normalizer: fn($value) => trim($value))->validate('abc '); // true | ||
``` | ||
|
||
### `message` | ||
|
||
type: `?string` default: `The {{ name }} value is not valid.` | ||
|
||
Message that will be shown when the input value does not match the regular expression pattern. | ||
|
||
The following parameters are available: | ||
|
||
| Parameter | Description | | ||
|-----------------|---------------------------| | ||
| `{{ value }}` | The current invalid value | | ||
| `{{ name }}` | Name of the invalid value | | ||
| `{{ pattern }}` | The given pattern | | ||
|
||
## Changelog | ||
|
||
- `0.8.0` Created |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
namespace ProgrammatorDev\Validator\Exception; | ||
|
||
class RegexException extends ValidationException {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
namespace ProgrammatorDev\Validator\Rule; | ||
|
||
use ProgrammatorDev\Validator\Exception\RegexException; | ||
use ProgrammatorDev\Validator\Exception\UnexpectedTypeException; | ||
use ProgrammatorDev\Validator\Exception\UnexpectedValueException; | ||
|
||
class Regex extends AbstractRule implements RuleInterface | ||
{ | ||
/** @var ?callable */ | ||
private $normalizer; | ||
private string $message = 'The {{ name }} value is not valid.'; | ||
|
||
public function __construct( | ||
private readonly string $pattern, | ||
private readonly bool $match = true, | ||
?callable $normalizer = null, | ||
?string $message = null | ||
) | ||
{ | ||
$this->normalizer = $normalizer; | ||
$this->message = $message ?? $this->message; | ||
} | ||
|
||
public function assert(mixed $value, ?string $name = null): void | ||
{ | ||
if (!\is_scalar($value) && !$value instanceof \Stringable) { | ||
throw new UnexpectedTypeException('string|\Stringable', get_debug_type($value)); | ||
} | ||
|
||
$value = (string) $value; | ||
|
||
if ($this->normalizer !== null) { | ||
$value = ($this->normalizer)($value); | ||
} | ||
|
||
if (($regex = @\preg_match($this->pattern, $value)) === false) { | ||
throw new UnexpectedValueException('Invalid regular expression pattern.'); | ||
} | ||
|
||
if ($this->match xor $regex) { | ||
throw new RegexException( | ||
message: $this->message, | ||
parameters: [ | ||
'name' => $name, | ||
'value' => $value, | ||
'pattern' => $this->pattern | ||
] | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
namespace ProgrammatorDev\Validator\Test; | ||
|
||
use ProgrammatorDev\Validator\Exception\RegexException; | ||
use ProgrammatorDev\Validator\Rule\Regex; | ||
use ProgrammatorDev\Validator\Test\Util\TestRuleFailureConditionTrait; | ||
use ProgrammatorDev\Validator\Test\Util\TestRuleMessageOptionTrait; | ||
use ProgrammatorDev\Validator\Test\Util\TestRuleSuccessConditionTrait; | ||
use ProgrammatorDev\Validator\Test\Util\TestRuleUnexpectedValueTrait; | ||
|
||
class RegexTest extends AbstractTest | ||
{ | ||
use TestRuleUnexpectedValueTrait; | ||
use TestRuleFailureConditionTrait; | ||
use TestRuleSuccessConditionTrait; | ||
use TestRuleMessageOptionTrait; | ||
|
||
public static function provideRuleUnexpectedValueData(): \Generator | ||
{ | ||
$unexpectedPatternMessage = '/Invalid regular expression pattern./'; | ||
$unexpectedTypeMessage = '/Expected value of type "array|\Stringable", "(.*)" given./'; | ||
|
||
yield 'invalid pattern' => [new Regex('invalid'), 'abc', $unexpectedPatternMessage]; | ||
yield 'invalid value type' => [new Regex('/[a-z]/'), ['abc'], $unexpectedTypeMessage]; | ||
} | ||
|
||
public static function provideRuleFailureConditionData(): \Generator | ||
{ | ||
$value = 'abc'; | ||
$exception = RegexException::class; | ||
$message = '/The (.*) value is not valid./'; | ||
|
||
yield 'match true' => [new Regex('/[0-9]/'), $value, $exception, $message]; | ||
yield 'match false' => [new Regex('/[a-z]/', match: false), $value, $exception, $message]; | ||
} | ||
|
||
public static function provideRuleSuccessConditionData(): \Generator | ||
{ | ||
$value = 'abc'; | ||
|
||
yield 'match true' => [new Regex('/[a-z]/'), $value]; | ||
yield 'match false' => [new Regex('/[0-9]/', match: false), $value]; | ||
yield 'normalizer' => [new Regex('/^\S*$/', normalizer: 'trim'), 'abc ']; | ||
} | ||
|
||
public static function provideRuleMessageOptionData(): \Generator | ||
{ | ||
yield 'message' => [ | ||
new Regex( | ||
pattern: '/[a-z]/', | ||
message: 'The {{ name }} value does not match the pattern {{ pattern }}.' | ||
), | ||
'123', | ||
'The test value does not match the pattern "/[a-z]/".' | ||
]; | ||
} | ||
} |