Skip to content

Commit

Permalink
Merge pull request #59 from programmatordev/1.x
Browse files Browse the repository at this point in the history
1.x
  • Loading branch information
andrepimpao authored Mar 27, 2024
2 parents ed0d636 + 1c2acad commit 63cf347
Show file tree
Hide file tree
Showing 37 changed files with 676 additions and 67 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ Simple usage looks like:
use ProgrammatorDev\Validator\Rule;
use ProgrammatorDev\Validator\Validator;

// do this...
$validator = Validator::notBlank()->greaterThanOrEqual(18);
// do this:
$validator = Validator::type('int')->greaterThanOrEqual(18);

// ...and validate with these:
// and validate with these:
$validator->validate(16); // returns bool: false
$validator->assert(16, 'age'); // throws exception: The age value should be greater than or equal to 18, 16 given.
```
Expand Down
6 changes: 3 additions & 3 deletions docs/01-get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ Simple usage looks like:
use ProgrammatorDev\Validator\Rule;
use ProgrammatorDev\Validator\Validator;

// do this...
$validator = Validator::notBlank()->greaterThanOrEqual(18);
// do this:
$validator = Validator::type('int')->greaterThanOrEqual(18);

// ...and validate with these:
// and validate with these:
$validator->validate(16); // returns bool: false
$validator->assert(16, 'age'); // throws exception: The age value should be greater than or equal to 18, 16 given.
```
8 changes: 4 additions & 4 deletions docs/02-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function getWeather(float $latitude, float $longitude, string $unitSystem
{
Validator::range(-90, 90)->assert($latitude, 'latitude');
Validator::range(-180, 180)->assert($longitude, 'longitude');
Validator::notBlank()->choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');
Validator::choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');

// ...
}
Expand Down Expand Up @@ -51,7 +51,7 @@ function getWeather(float $latitude, float $longitude, string $unitSystem): floa
{
Validator::range(-90, 90)->assert($latitude, 'latitude');
Validator::range(-180, 180)->assert($longitude, 'longitude');
Validator::notBlank()->choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');
Validator::choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');

// ...
}
Expand Down Expand Up @@ -98,7 +98,7 @@ use ProgrammatorDev\Validator\Validator;
try {
Validator::range(-90, 90)->assert($latitude, 'latitude');
Validator::range(-180, 180)->assert($longitude, 'longitude');
Validator::notBlank()->choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');
Validator::choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');
}
catch (Exception\RangeException $exception) {
// do something when Range fails
Expand All @@ -120,7 +120,7 @@ use ProgrammatorDev\Validator\Validator;
try {
Validator::range(-90, 90)->assert($latitude, 'latitude');
Validator::range(-180, 180)->assert($longitude, 'longitude');
Validator::notBlank()->choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');
Validator::choice(['metric', 'imperial'])->assert($unitSystem, 'unit system');
}
catch (ValidationException $exception) {
// do something when a rule fails
Expand Down
3 changes: 3 additions & 0 deletions docs/03-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

- [Email](03-rules_email.md)
- [Length](03-rules_length.md)
- [PasswordStrength](03-rules_password-strength.md)
- [Regex](03-rules_regex.md)
- [URL](03-rules_url.md)

## Comparison Rules
Expand All @@ -29,6 +31,7 @@

## Date Rules

- [DateTime](03-rules_date-time.md)
- [Timezone](03-rules_timezone.md)

## Choice Rules
Expand Down
56 changes: 56 additions & 0 deletions docs/03-rules_date-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# DateTime

Validates that a given value is a valid datetime in a specific format.

```php
DateTime(
string $format = 'Y-m-d H:i:s',
?string $message = null
);
```

## Basic Usage

```php
// default "Y-m-d H:i:s"
Validator::dateTime()->validate('2024-01-01 00:00:00'); // true
Validator::dateTime()->validate('2024-01-01'); // false

// validate date
Validator::dateTime(format: 'Y-m-d')->validate('2024-01-01'); // true
Validator::dateTime(format: 'Y-m-d')->validate('2024-01-35'); // false

// validate time
Validator::dateTime(format: 'H:i:s')->validate('21:00:00'); // true
Validator::dateTime(format: 'H:i:s')->validate('35:00:00'); // false
```

> [!NOTE]
> An `UnexpectedValueException` will be thrown when the input value is not a `string` or an object implementing `\Stringable`.
## Options

### `format`

type: `string` default: `Y-m-d H:i:s`

Format of the datetime to be validated.
Check all formatting options [here](https://www.php.net/manual/en/datetimeimmutable.createfromformat.php).

### `message`

type: `?string` default: `The {{ name }} value is not a valid datetime.`

Message that will be shown when the input value is not a valid datetime.

The following parameters are available:

| Parameter | Description |
|----------------|---------------------------|
| `{{ value }}` | The current invalid value |
| `{{ name }}` | Name of the invalid value |
| `{{ format }}` | The datetime format |

## Changelog

- `0.8.0` Created
6 changes: 3 additions & 3 deletions docs/03-rules_length.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ Allows to define a `callable` that will be applied to the value before checking
For example, use `trim`, or pass your own function, to not measure whitespaces at the end of a string:

```php
// existing php callables
Validator::length(max: 3)->validate('abc '); // false

Validator::length(max: 3, normalizer: 'trim')->validate('abc '); // true
// function
Validator::length(max: 3, normalizer: fn($value) => trim($value))->validate('abc '); // false
Validator::length(max: 3, normalizer: fn($value) => trim($value))->validate('abc '); // true
```

### `minMessage`
Expand Down
60 changes: 60 additions & 0 deletions docs/03-rules_password-strength.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# PasswordStrength

Validates that the given password has reached the minimum strength required by the constraint.
The strength is calculated by measuring the entropy of the password (in bits) based on its length and the number of unique characters.

```php
PasswordStrength(
string $minStrength = 'medium',
?string $message = null
);
```

## Basic Usage

```php
Validator::passwordStrength()->validate('password'); // false
Validator::passwordStrength()->validate('i8Kq*MBob~2W"=p'); // true
Validator::passwordStrength(minStrength: 'very-strong')->validate('i8Kq*MBob~2W"=p'); // false
```

> [!NOTE]
> An `UnexpectedValueException` will be thrown when a `minStrength` option is invalid.
> [!NOTE]
> An `UnexpectedValueException` will be thrown when the input value is not a `string`.
## Options

### `minStrength`

type: `string` default: `medium`

Sets the minimum strength of the password in entropy bits.
The entropy is calculated using the formula [here](https://www.pleacher.com/mp/mlessons/algebra/entropy.html).

Available options are:

- `weak` entropy between `64` and `79` bits.
- `medium` entropy between `80` and `95` bits.
- `strong` entropy between `96` and `127` bits.
- `very-strong` entropy greater than `128` bits.

All measurements less than `64` bits will fail.

### `message`

type: `?string` default: `The password strength is not strong enough.`

Message that will be shown when the password is not strong enough.

The following parameters are available:

| Parameter | Description |
|---------------------|---------------------------|
| `{{ name }}` | Name of the invalid value |
| `{{ minStrength }}` | Selected minimum strength |

## Changelog

- `0.8.0` Created
79 changes: 79 additions & 0 deletions docs/03-rules_regex.md
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` `required`

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
17 changes: 17 additions & 0 deletions src/ChainedValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public function country(
?string $message = null
): ChainedValidatorInterface&Validator;

public function dateTime(
string $format = 'Y-m-d H:i:s',
?string $message = null
): ChainedValidatorInterface&Validator;

public function eachKey(
Validator $validator,
?string $message = null
Expand Down Expand Up @@ -84,12 +89,24 @@ public function notBlank(
?string $message = null
): ChainedValidatorInterface&Validator;

public function passwordStrength(
string $minStrength = 'medium',
?string $message = null
): ChainedValidatorInterface&Validator;

public function range(
mixed $min,
mixed $max,
?string $message = null
): ChainedValidatorInterface&Validator;

public function regex(
string $pattern,
bool $match = true,
?callable $normalizer = null,
?string $message = null
): ChainedValidatorInterface&Validator;

public function rule(
RuleInterface $constraint
): ChainedValidatorInterface&Validator;
Expand Down
5 changes: 5 additions & 0 deletions src/Exception/DateTimeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace ProgrammatorDev\Validator\Exception;

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

namespace ProgrammatorDev\Validator\Exception;

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

namespace ProgrammatorDev\Validator\Exception;

class RegexException extends ValidationException {}
43 changes: 43 additions & 0 deletions src/Rule/DateTime.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace ProgrammatorDev\Validator\Rule;

use ProgrammatorDev\Validator\Exception\DateTimeException;
use ProgrammatorDev\Validator\Exception\UnexpectedTypeException;

class DateTime extends AbstractRule implements RuleInterface
{
private string $message = 'The {{ name }} value is not a valid datetime.';

public function __construct(
private readonly string $format = 'Y-m-d H:i:s',
?string $message = null
)
{
$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;

\DateTimeImmutable::createFromFormat($this->format, $value);

$errors = \DateTimeImmutable::getLastErrors();

if ($errors !== false && ($errors['error_count'] > 0 || $errors['warning_count'] > 0)) {
throw new DateTimeException(
message: $this->message,
parameters: [
'name' => $name,
'value' => $value,
'format' => $this->format
]
);
}
}
}
Loading

0 comments on commit 63cf347

Please sign in to comment.