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

Commit 738bd98

Browse files
authored
Merge pull request #64 from programmatordev/YAPV-46-create-language-rule
Create Language rule
2 parents 9eb9f3f + 0b63426 commit 738bd98

File tree

11 files changed

+200
-16
lines changed

11 files changed

+200
-16
lines changed

docs/03-rules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
- [Choice](03-rules_choice.md)
4141
- [Country](03-rules_country.md)
42+
- [Language](03-rules_language.md)
4243

4344
## Iterable Rules
4445

docs/03-rules_country.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Available options:
4141

4242
### `message`
4343

44-
type: `?string` default: `The {{ name }} value is not a valid {{ code }} country code, {{ value }} given.`
44+
type: `?string` default: `The {{ name }} value is not a valid country, {{ value }} given.`
4545

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

docs/03-rules_language.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Language
2+
3+
Validates that a value is a valid language code.
4+
5+
```php
6+
Language(
7+
string $code = 'alpha-2',
8+
?string $message = null
9+
);
10+
```
11+
12+
## Basic Usage
13+
14+
```php
15+
// default alpha-2 code
16+
Validator::language()->validate('pt'); // true
17+
18+
// alpha-3 code
19+
Validator::language(code: 'alpha-3')->validate('por'); // true
20+
```
21+
22+
> [!NOTE]
23+
> An `UnexpectedValueException` will be thrown when the `code` value is not a valid option.
24+
25+
> [!NOTE]
26+
> An `UnexpectedValueException` will be thrown when the input value is not a `string`.
27+
28+
## Options
29+
30+
### `code`
31+
32+
type: `string` default: `alpha-2`
33+
34+
Set code type to validate the language.
35+
Check the [official language codes](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) list for more information.
36+
37+
Available options:
38+
39+
- `alpha-2`: two-letter code
40+
- `alpha-3`: three-letter code
41+
42+
### `message`
43+
44+
type: `?string` default: `The {{ name }} value is not a valid language, {{ value }} given.`
45+
46+
Message that will be shown if the input value is not a valid language code.
47+
48+
The following parameters are available:
49+
50+
| Parameter | Description |
51+
|---------------|---------------------------|
52+
| `{{ value }}` | The current invalid value |
53+
| `{{ name }}` | Name of the invalid value |
54+
| `{{ code }}` | Selected code type |
55+
56+
## Changelog
57+
58+
- `1.1.0` Created

src/ChainedValidatorInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ public function greaterThanOrEqual(
7070
?string $message = null
7171
): ChainedValidatorInterface&Validator;
7272

73+
public function language(
74+
string $code = 'alpha-2',
75+
?string $message = null
76+
): ChainedValidatorInterface&Validator;
77+
7378
public function length(
7479
?int $min = null,
7580
?int $max = null,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Validator\Exception;
4+
5+
class LanguageException extends ValidationException {}

src/Rule/Country.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Country extends AbstractRule implements RuleInterface
1717
self::ALPHA_3_CODE
1818
];
1919

20-
private string $message = 'The {{ name }} value is not a valid {{ code }} country code, {{ value }} given.';
20+
private string $message = 'The {{ name }} value is not a valid country, {{ value }} given.';
2121

2222
public function __construct(
2323
private readonly string $code = self::ALPHA_2_CODE,
@@ -37,8 +37,8 @@ public function assert(mixed $value, ?string $name = null): void
3737
throw new UnexpectedTypeException('string', get_debug_type($value));
3838
}
3939

40-
// Keep original value for parameters
41-
$input = strtoupper($value);
40+
// keep original value for parameters
41+
$input = \strtoupper($value);
4242

4343
if (
4444
($this->code === self::ALPHA_2_CODE && !Countries::exists($input))

src/Rule/Language.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Validator\Rule;
4+
5+
use ProgrammatorDev\Validator\Exception\LanguageException;
6+
use ProgrammatorDev\Validator\Exception\UnexpectedOptionException;
7+
use ProgrammatorDev\Validator\Exception\UnexpectedTypeException;
8+
use Symfony\Component\Intl\Languages;
9+
10+
class Language extends AbstractRule implements RuleInterface
11+
{
12+
public const ALPHA_2_CODE = 'alpha-2';
13+
public const ALPHA_3_CODE = 'alpha-3';
14+
15+
private const CODE_OPTIONS = [
16+
self::ALPHA_2_CODE,
17+
self::ALPHA_3_CODE
18+
];
19+
20+
private string $message = 'The {{ name }} value is not a valid language, {{ value }} given.';
21+
22+
public function __construct(
23+
private readonly string $code = self::ALPHA_2_CODE,
24+
?string $message = null
25+
)
26+
{
27+
$this->message = $message ?? $this->message;
28+
}
29+
30+
public function assert(mixed $value, ?string $name = null): void
31+
{
32+
if (!\in_array($this->code, self::CODE_OPTIONS)) {
33+
throw new UnexpectedOptionException('code', self::CODE_OPTIONS, $this->code);
34+
}
35+
36+
if (!\is_string($value)) {
37+
throw new UnexpectedTypeException('string', get_debug_type($value));
38+
}
39+
40+
// keep original value for parameters
41+
$input = \strtolower($value);
42+
43+
if (
44+
($this->code === self::ALPHA_2_CODE && !Languages::exists($input))
45+
|| ($this->code === self::ALPHA_3_CODE && !Languages::alpha3CodeExists($input))
46+
) {
47+
throw new LanguageException(
48+
message: $this->message,
49+
parameters: [
50+
'name' => $name,
51+
'value' => $value,
52+
'code' => $this->code
53+
]
54+
);
55+
}
56+
}
57+
}

src/StaticValidatorInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ public static function greaterThanOrEqual(
6969
?string $message = null
7070
): ChainedValidatorInterface&Validator;
7171

72+
public static function language(
73+
string $code = 'alpha-2',
74+
?string $message = null
75+
): ChainedValidatorInterface&Validator;
76+
7277
public static function length(
7378
?int $min = null,
7479
?int $max = null,

tests/CountryTest.php

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,25 @@ public static function provideRuleUnexpectedValueData(): \Generator
2121
$unexpectedCodeMessage = '/Invalid code "(.*)"\. Accepted values are\: "(.*)"\./';
2222
$unexpectedTypeMessage = '/Expected value of type "string", (.*) given\./';
2323

24-
yield 'invalid code' => [new Country('invalid'), 'PT', $unexpectedCodeMessage];
24+
yield 'invalid code' => [new Country('invalid'), 'pt', $unexpectedCodeMessage];
2525
yield 'invalid type' => [new Country(), 123, $unexpectedTypeMessage];
2626
}
2727

2828
public static function provideRuleFailureConditionData(): \Generator
2929
{
3030
$exception = CountryException::class;
31-
$message = '/The (.*) value is not a valid (.*) country code, (.*) given\./';
31+
$message = '/The (.*) value is not a valid country, (.*) given\./';
3232

33-
yield 'default' => [new Country(), 'PRT', $exception, $message];
34-
yield 'alpha2' => [new Country(code: 'alpha-2'), 'PRT', $exception, $message];
35-
yield 'alpha3' => [new Country(code: 'alpha-3'), 'PT', $exception, $message];
33+
yield 'default' => [new Country(), 'prt', $exception, $message];
34+
yield 'alpha2' => [new Country(code: 'alpha-2'), 'prt', $exception, $message];
35+
yield 'alpha3' => [new Country(code: 'alpha-3'), 'pt', $exception, $message];
3636
}
3737

3838
public static function provideRuleSuccessConditionData(): \Generator
3939
{
40-
yield 'default' => [new Country(), 'PT'];
41-
yield 'alpha2' => [new Country(code: 'alpha-2'), 'PT'];
42-
yield 'alpha2 lowercase' => [new Country(code: 'alpha-2'), 'pt'];
43-
yield 'alpha3' => [new Country(code: 'alpha-3'), 'PRT'];
44-
yield 'alpha3 lowercase' => [new Country(code: 'alpha-3'), 'prt'];
40+
yield 'default' => [new Country(), 'pt'];
41+
yield 'alpha2' => [new Country(code: 'alpha-2'), 'pt'];
42+
yield 'alpha3' => [new Country(code: 'alpha-3'), 'prt'];
4543
}
4644

4745
public static function provideRuleMessageOptionData(): \Generator

tests/LanguageTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Validator\Test;
4+
5+
use ProgrammatorDev\Validator\Exception\LanguageException;
6+
use ProgrammatorDev\Validator\Rule\Language;
7+
use ProgrammatorDev\Validator\Test\Util\TestRuleFailureConditionTrait;
8+
use ProgrammatorDev\Validator\Test\Util\TestRuleMessageOptionTrait;
9+
use ProgrammatorDev\Validator\Test\Util\TestRuleSuccessConditionTrait;
10+
use ProgrammatorDev\Validator\Test\Util\TestRuleUnexpectedValueTrait;
11+
12+
class LanguageTest extends AbstractTest
13+
{
14+
use TestRuleUnexpectedValueTrait;
15+
use TestRuleFailureConditionTrait;
16+
use TestRuleSuccessConditionTrait;
17+
use TestRuleMessageOptionTrait;
18+
19+
public static function provideRuleUnexpectedValueData(): \Generator
20+
{
21+
$unexpectedCodeMessage = '/Invalid code "(.*)"\. Accepted values are\: "(.*)"\./';
22+
$unexpectedTypeMessage = '/Expected value of type "string", (.*) given\./';
23+
24+
yield 'invalid code' => [new Language('invalid'), 'pt', $unexpectedCodeMessage];
25+
yield 'invalid type' => [new Language(), 123, $unexpectedTypeMessage];
26+
}
27+
28+
public static function provideRuleFailureConditionData(): \Generator
29+
{
30+
$exception = LanguageException::class;
31+
$message = '/The (.*) value is not a valid language, (.*) given\./';
32+
33+
yield 'default' => [new Language(), 'prt', $exception, $message];
34+
yield 'alpha2' => [new Language(code: 'alpha-2'), 'por', $exception, $message];
35+
yield 'alpha3' => [new Language(code: 'alpha-3'), 'pt', $exception, $message];
36+
}
37+
38+
public static function provideRuleSuccessConditionData(): \Generator
39+
{
40+
yield 'default' => [new Language(), 'pt'];
41+
yield 'alpha2' => [new Language(code: 'alpha-2'), 'pt'];
42+
yield 'alpha3' => [new Language(code: 'alpha-3'), 'por'];
43+
}
44+
45+
public static function provideRuleMessageOptionData(): \Generator
46+
{
47+
yield 'message' => [
48+
new Language(
49+
message: 'The {{ name }} value {{ value }} is not a valid {{ code }} language code.'
50+
),
51+
'invalid',
52+
'The test value "invalid" is not a valid "alpha-2" language code.'
53+
];
54+
}
55+
}

0 commit comments

Comments
 (0)