Skip to content

Commit

Permalink
Merge pull request #64 from programmatordev/YAPV-46-create-language-rule
Browse files Browse the repository at this point in the history
Create Language rule
  • Loading branch information
andrepimpao authored Apr 29, 2024
2 parents 9eb9f3f + 0b63426 commit 738bd98
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 16 deletions.
1 change: 1 addition & 0 deletions docs/03-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

- [Choice](03-rules_choice.md)
- [Country](03-rules_country.md)
- [Language](03-rules_language.md)

## Iterable Rules

Expand Down
2 changes: 1 addition & 1 deletion docs/03-rules_country.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Available options:

### `message`

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

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

Expand Down
58 changes: 58 additions & 0 deletions docs/03-rules_language.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Language

Validates that a value is a valid language code.

```php
Language(
string $code = 'alpha-2',
?string $message = null
);
```

## Basic Usage

```php
// default alpha-2 code
Validator::language()->validate('pt'); // true

// alpha-3 code
Validator::language(code: 'alpha-3')->validate('por'); // 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 language.
Check the [official language codes](https://en.wikipedia.org/wiki/List_of_ISO_639_language_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 language, {{ value }} given.`

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

The following parameters are available:

| Parameter | Description |
|---------------|---------------------------|
| `{{ value }}` | The current invalid value |
| `{{ name }}` | Name of the invalid value |
| `{{ code }}` | Selected code type |

## Changelog

- `1.1.0` Created
5 changes: 5 additions & 0 deletions src/ChainedValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public function greaterThanOrEqual(
?string $message = null
): ChainedValidatorInterface&Validator;

public function language(
string $code = 'alpha-2',
?string $message = null
): ChainedValidatorInterface&Validator;

public function length(
?int $min = null,
?int $max = null,
Expand Down
5 changes: 5 additions & 0 deletions src/Exception/LanguageException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace ProgrammatorDev\Validator\Exception;

class LanguageException extends ValidationException {}
6 changes: 3 additions & 3 deletions src/Rule/Country.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Country extends AbstractRule implements RuleInterface
self::ALPHA_3_CODE
];

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

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

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

if (
($this->code === self::ALPHA_2_CODE && !Countries::exists($input))
Expand Down
57 changes: 57 additions & 0 deletions src/Rule/Language.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace ProgrammatorDev\Validator\Rule;

use ProgrammatorDev\Validator\Exception\LanguageException;
use ProgrammatorDev\Validator\Exception\UnexpectedOptionException;
use ProgrammatorDev\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Intl\Languages;

class Language 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
];

private string $message = 'The {{ name }} value is not a valid language, {{ value }} given.';

public function __construct(
private readonly string $code = self::ALPHA_2_CODE,
?string $message = null
)
{
$this->message = $message ?? $this->message;
}

public function assert(mixed $value, ?string $name = null): void
{
if (!\in_array($this->code, self::CODE_OPTIONS)) {
throw new UnexpectedOptionException('code', self::CODE_OPTIONS, $this->code);
}

if (!\is_string($value)) {
throw new UnexpectedTypeException('string', get_debug_type($value));
}

// keep original value for parameters
$input = \strtolower($value);

if (
($this->code === self::ALPHA_2_CODE && !Languages::exists($input))
|| ($this->code === self::ALPHA_3_CODE && !Languages::alpha3CodeExists($input))
) {
throw new LanguageException(
message: $this->message,
parameters: [
'name' => $name,
'value' => $value,
'code' => $this->code
]
);
}
}
}
5 changes: 5 additions & 0 deletions src/StaticValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public static function greaterThanOrEqual(
?string $message = null
): ChainedValidatorInterface&Validator;

public static function language(
string $code = 'alpha-2',
?string $message = null
): ChainedValidatorInterface&Validator;

public static function length(
?int $min = null,
?int $max = null,
Expand Down
18 changes: 8 additions & 10 deletions tests/CountryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,25 @@ public static function provideRuleUnexpectedValueData(): \Generator
$unexpectedCodeMessage = '/Invalid code "(.*)"\. Accepted values are\: "(.*)"\./';
$unexpectedTypeMessage = '/Expected value of type "string", (.*) given\./';

yield 'invalid code' => [new Country('invalid'), 'PT', $unexpectedCodeMessage];
yield 'invalid code' => [new Country('invalid'), 'pt', $unexpectedCodeMessage];
yield 'invalid type' => [new Country(), 123, $unexpectedTypeMessage];
}

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

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

public static function provideRuleSuccessConditionData(): \Generator
{
yield 'default' => [new Country(), 'PT'];
yield 'alpha2' => [new Country(code: 'alpha-2'), 'PT'];
yield 'alpha2 lowercase' => [new Country(code: 'alpha-2'), 'pt'];
yield 'alpha3' => [new Country(code: 'alpha-3'), 'PRT'];
yield 'alpha3 lowercase' => [new Country(code: 'alpha-3'), 'prt'];
yield 'default' => [new Country(), 'pt'];
yield 'alpha2' => [new Country(code: 'alpha-2'), 'pt'];
yield 'alpha3' => [new Country(code: 'alpha-3'), 'prt'];
}

public static function provideRuleMessageOptionData(): \Generator
Expand Down
55 changes: 55 additions & 0 deletions tests/LanguageTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace ProgrammatorDev\Validator\Test;

use ProgrammatorDev\Validator\Exception\LanguageException;
use ProgrammatorDev\Validator\Rule\Language;
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 LanguageTest extends AbstractTest
{
use TestRuleUnexpectedValueTrait;
use TestRuleFailureConditionTrait;
use TestRuleSuccessConditionTrait;
use TestRuleMessageOptionTrait;

public static function provideRuleUnexpectedValueData(): \Generator
{
$unexpectedCodeMessage = '/Invalid code "(.*)"\. Accepted values are\: "(.*)"\./';
$unexpectedTypeMessage = '/Expected value of type "string", (.*) given\./';

yield 'invalid code' => [new Language('invalid'), 'pt', $unexpectedCodeMessage];
yield 'invalid type' => [new Language(), 123, $unexpectedTypeMessage];
}

public static function provideRuleFailureConditionData(): \Generator
{
$exception = LanguageException::class;
$message = '/The (.*) value is not a valid language, (.*) given\./';

yield 'default' => [new Language(), 'prt', $exception, $message];
yield 'alpha2' => [new Language(code: 'alpha-2'), 'por', $exception, $message];
yield 'alpha3' => [new Language(code: 'alpha-3'), 'pt', $exception, $message];
}

public static function provideRuleSuccessConditionData(): \Generator
{
yield 'default' => [new Language(), 'pt'];
yield 'alpha2' => [new Language(code: 'alpha-2'), 'pt'];
yield 'alpha3' => [new Language(code: 'alpha-3'), 'por'];
}

public static function provideRuleMessageOptionData(): \Generator
{
yield 'message' => [
new Language(
message: 'The {{ name }} value {{ value }} is not a valid {{ code }} language code.'
),
'invalid',
'The test value "invalid" is not a valid "alpha-2" language code.'
];
}
}
4 changes: 2 additions & 2 deletions tests/TimezoneTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ class TimezoneTest extends AbstractTest
public static function provideRuleUnexpectedValueData(): \Generator
{
$unexpectedMissingCountryCodeMessage = '/A country code is required when timezone group is "\\\DateTimeZone::PER_COUNTRY"\./';
$unexpectedCountryCodeMessage = '/The (.*) value is not a valid (.*) country code, (.*) given\./';
$unexpectedCountryCodeMessage = '/The (.*) value is not a valid country, (.*) given\./';

yield 'missing country code' => [
new Timezone(\DateTimeZone::PER_COUNTRY),
'Europe/Lisbon',
$unexpectedMissingCountryCodeMessage
];
yield 'invalid country code' => [
new Timezone(\DateTimeZone::PER_COUNTRY, 'PRT'),
new Timezone(\DateTimeZone::PER_COUNTRY, 'prt'),
'Europe/Lisbon',
$unexpectedCountryCodeMessage
];
Expand Down

0 comments on commit 738bd98

Please sign in to comment.