Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.
Merged

1.x #31

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
975652d
chore: parse line breaks and tab chars on error messages
andrepimpao Aug 14, 2023
4de3d23
chore: require ctype polyfill for Type rule
andrepimpao Aug 14, 2023
b7e1580
feat: added Type rule
andrepimpao Aug 14, 2023
1187adc
feat: added Type rule documentation
andrepimpao Aug 14, 2023
2ec5740
fix: wrong Type argument name
andrepimpao Aug 14, 2023
e69cf72
Merge pull request #28 from programmatordev/YAPV-18-create-type-rule
andrepimpao Aug 14, 2023
fcb6470
chore: improved Type rule documentation
andrepimpao Aug 16, 2023
6e04a28
chore: added Type constants
andrepimpao Aug 16, 2023
bc3b803
chore: simplified message var to be coherent with other tests
andrepimpao Aug 16, 2023
b82e065
feat: added Country rule
andrepimpao Aug 16, 2023
9f4ec8f
chore: changed Country error message
andrepimpao Aug 16, 2023
201f97a
chore: added missing semi-colon in docs
andrepimpao Aug 16, 2023
e99c995
chore: improved Choice docs
andrepimpao Aug 16, 2023
d3ce672
chore: changed constant names
andrepimpao Aug 16, 2023
95d1f76
feat: added Country rule documentation
andrepimpao Aug 16, 2023
343c7ef
Merge pull request #29 from programmatordev/YAPV-44-create-country-rule
andrepimpao Aug 16, 2023
d1c75d5
chore: small docs fix
andrepimpao Aug 16, 2023
3e8bd8b
Merge pull request #30 from programmatordev/YAPV-44-create-country-rule
andrepimpao Aug 16, 2023
a3338c2
chore: added Country rule to list page
andrepimpao Aug 16, 2023
6aef764
chore: added Country rule to interfaces
andrepimpao Aug 16, 2023
720af0a
Merge pull request #32 from programmatordev/YAPV-44-create-country-rule
andrepimpao Aug 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
}
],
"require": {
"php": ">=8.1"
"php": ">=8.1",
"symfony/intl": "^6.3",
"symfony/polyfill-ctype": "^1.27"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
Expand Down
2 changes: 2 additions & 0 deletions docs/03-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
## Basic Rules

- [NotBlank](03x-rules-not-blank.md)
- [Type](03x-rules-type.md)

## Comparison Rules

Expand All @@ -20,6 +21,7 @@
## Choice Rules

- [Choice](03x-rules-choice.md)
- [Country](03x-rules-country.md)

## Other Rules

Expand Down
2 changes: 1 addition & 1 deletion docs/03x-rules-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Validator::choice(['red', 'green', 'blue'], multiple: true, minConstraint: 2, ma
```

> **Note**
> An `UnexpectedValueException` will be thrown when `multiple` is `true` and value to be validated is not an `array`.
> An `UnexpectedValueException` will be thrown when `multiple` is `true` and the input value is not an `array`.

> **Note**
> An `UnexpectedValueException` will be thrown when the `minConstraint` value is greater than or equal to the `maxConstraint` value.
Expand Down
55 changes: 55 additions & 0 deletions docs/03x-rules-country.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Country

Validates that a value is a valid country code.

```php
Country(
string $code = 'alpha-2',
string $message = 'The "{{ name }}" value is not a valid country code, "{{ value }}" given.'
);
```

## Basic Usage

```php
// Default alpha-2 code
Validator::country()->validate('PT'); // true
Validator::country(code: 'alpha-2')->validate('PT'); // true

// Alpha-3 code
Validator::country(code: 'alpha-3')->validate('PRT'); // true
```

> **Note**
> An `UnexpectedValueException` will be thrown when the `code` value is not a valid option.

> **Note**
> An `UnexpectedValueException` will be thrown when the input value is not a `string`.

## Options

### `code`

type: `string` default: `alpha-2`

Set code type to validate the country.
Check the [official country codes](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) list for more information.

Available options:

- `alpha-2`: two-letter code
- `alpha-3`: three-letter code

### `message`

type: `string` default: `The "{{ name }}" value is not a valid country code, "{{ value }}" given.`

Message that will be shown if the input value is not a valid country code.

The following parameters are available:

| Parameter | Description |
|---------------|---------------------------|
| `{{ value }}` | The current invalid value |
| `{{ name }}` | Name of the invalid value |
| `{{ code }}` | Selected code type |
90 changes: 90 additions & 0 deletions docs/03x-rules-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Type

Validates that a value is of a specific type.

If an array with multiple types is provided, it will validate if the value is of at least one of the given types.
For example, if `['alpha', 'numeric']` is provided, it will validate if the value is of type `alpha` or of type `numeric`.

```php
Type(
string|array $constraint,
string $message = 'The "{{ name }}" value should be of type "{{ constraint }}", "{{ value }}" given.'
);
```

## Basic Usage

```php
// Single type
Validator::type('string')->validate('green'); // true
Validator::type('alphanumeric')->validate('gr33n'); // true

// Multiple types
// Validates if value is of at least one of the provided types
Validator::type(['alpha', 'numeric'])->validate('green'); // true (alpha)
Validator::type(['alpha', 'numeric'])->validate('33'); // true (numeric)
Validator::type(['alpha', 'numeric'])->validate('gr33n'); // false (not alpha nor numeric)

// Class or interface type
Validator::type(\DateTime::class)->validate(new \DateTime()); // true
Validator::type(\DateTimeInterface::class)->validate(new \DateTime()); // true
```

> **Note**
> An `UnexpectedValueException` will be thrown when a constraint type, class or interface is invalid.

## Options

### `constraint`

type: `string`|`array` `required`

Type(s) to validate the input value type.
Can validate instances of classes and interfaces.

If an array with multiple types is provided, it will validate if the value is of at least one of the given types.
For example, if `['alpha', 'numeric']` is provided, it will validate if the value is of type `alpha` or of type `numeric`.

Available data type constraints:

- [`bool`](https://www.php.net/manual/en/function.is-bool.php), [`boolean`](https://www.php.net/manual/en/function.is-bool.php)
- [`int`](https://www.php.net/manual/en/function.is-int.php), [`integer`](https://www.php.net/manual/en/function.is-int.php), [`long`](https://www.php.net/manual/en/function.is-int.php)
- [`float`](https://www.php.net/manual/en/function.is-float.php), [`double`](https://www.php.net/manual/en/function.is-float.php), [`real`](https://www.php.net/manual/en/function.is-float.php)
- [`numeric`](https://www.php.net/manual/en/function.is-numeric.php)
- [`string`](https://www.php.net/manual/en/function.is-string.php)
- [`scalar`](https://www.php.net/manual/en/function.is-scalar.php)
- [`array`](https://www.php.net/manual/en/function.is-array.php)
- [`iterable`](https://www.php.net/manual/en/function.is-iterable.php)
- [`countable`](https://www.php.net/manual/en/function.is-countable.php)
- [`callable`](https://www.php.net/manual/en/function.is-callable.php)
- [`object`](https://www.php.net/manual/en/function.is-object.php)
- [`resource`](https://www.php.net/manual/en/function.is-resource.php)
- [`null`](https://www.php.net/manual/en/function.is-null.php)

Available character type constraints:

- [`alphanumeric`](https://www.php.net/manual/en/function.ctype-alnum)
- [`alpha`](https://www.php.net/manual/en/function.ctype-alpha.php)
- [`digit`](https://www.php.net/manual/en/function.ctype-digit.php)
- [`control`](https://www.php.net/manual/en/function.ctype-cntrl.php)
- [`punctuation`](https://www.php.net/manual/en/function.ctype-punct.php)
- [`hexadecimal`](https://www.php.net/manual/en/function.ctype-xdigit.php)
- [`graph`](https://www.php.net/manual/en/function.ctype-graph.php)
- [`printable`](https://www.php.net/manual/en/function.ctype-print.php)
- [`whitespace`](https://www.php.net/manual/en/function.ctype-space.php)
- [`lowercase`](https://www.php.net/manual/en/function.ctype-lower.php)
- [`uppercase`](https://www.php.net/manual/en/function.ctype-upper.php)

### `message`

type `string` default: `The "{{ name }}" value should be of type "{{ constraint }}", "{{ value }}" given.`

Message that will be shown if input value is not of a specific type.

The following parameters are available:

| Parameter | Description |
|--------------------|---------------------------|
| `{{ value }}` | The current invalid value |
| `{{ name }}` | Name of the invalid value |
| `{{ constraint }}` | The valid type(s) |
10 changes: 10 additions & 0 deletions src/ChainedValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public function choice(
string $maxMessage = 'The "{{ name }}" value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.'
): ChainedValidatorInterface;

public function country(
string $code = 'alpha-2',
string $message = 'The "{{ name }}" value is not a valid country code, "{{ value }}" given.'
): ChainedValidatorInterface;

public function greaterThan(
mixed $constraint,
string $message = 'The "{{ name }}" value should be greater than "{{ constraint }}", "{{ value }}" given.'
Expand Down Expand Up @@ -64,4 +69,9 @@ public function range(
): ChainedValidatorInterface;

public function rule(RuleInterface $constraint): ChainedValidatorInterface;

public function type(
string|array $constraint,
string $message = 'The "{{ name }}" value should be of type "{{ constraint }}", "{{ value }}" given.'
): ChainedValidatorInterface;
}
5 changes: 5 additions & 0 deletions src/Exception/CountryException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace ProgrammatorDev\YetAnotherPhpValidator\Exception;

class CountryException extends ValidationException {}
5 changes: 5 additions & 0 deletions src/Exception/TypeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace ProgrammatorDev\YetAnotherPhpValidator\Exception;

class TypeException extends ValidationException {}
3 changes: 2 additions & 1 deletion src/Exception/ValidationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ private function formatValue(mixed $value): string
}

if (\is_string($value)) {
return $value;
// Replace line breaks and tabs with single space
return str_replace(["\n", "\r", "\t", "\v", "\x00"], ' ', $value);
}

if (\is_resource($value)) {
Expand Down
59 changes: 59 additions & 0 deletions src/Rule/Country.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace ProgrammatorDev\YetAnotherPhpValidator\Rule;

use ProgrammatorDev\YetAnotherPhpValidator\Exception\CountryException;
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedValueException;
use Symfony\Component\Intl\Countries;

class Country extends AbstractRule implements RuleInterface
{
public const ALPHA_2_CODE = 'alpha-2';
public const ALPHA_3_CODE = 'alpha-3';

private const CODE_OPTIONS = [
self::ALPHA_2_CODE,
self::ALPHA_3_CODE
];

public function __construct(
private readonly string $code = self::ALPHA_2_CODE,
private readonly string $message = 'The "{{ name }}" value is not a valid country code, "{{ value }}" given.'
) {}

public function assert(mixed $value, string $name): void
{
if (!\in_array($this->code, self::CODE_OPTIONS)) {
throw new UnexpectedValueException(
\sprintf(
'Invalid code "%s". Accepted values are: "%s".',
$this->code,
\implode(", ", self::CODE_OPTIONS)
)
);
}

if (!\is_string($value)) {
throw new UnexpectedValueException(
\sprintf('Expected value of type "string", "%s" given.', get_debug_type($value))
);
}

// Keep original value for parameters
$input = strtoupper($value);

if (
($this->code === self::ALPHA_2_CODE && !Countries::exists($input))
|| ($this->code === self::ALPHA_3_CODE && !Countries::alpha3CodeExists($input))
) {
throw new CountryException(
message: $this->message,
parameters: [
'name' => $name,
'value' => $value,
'code' => $this->code
]
);
}
}
}
Loading