Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add age validation to the schema #124

Merged
merged 2 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
<!-- /top-badges -->

<!-- rules-counter -->
[![Static Badge](https://img.shields.io/badge/Rules-373-green?label=Total%20number%20of%20rules&labelColor=darkgreen&color=gray)](schema-examples/full.yml)
[![Static Badge](https://img.shields.io/badge/Rules-159-green?label=Cell%20rules&labelColor=blue&color=gray)](src/Rules/Cell)
[![Static Badge](https://img.shields.io/badge/Rules-379-green?label=Total%20number%20of%20rules&labelColor=darkgreen&color=gray)](schema-examples/full.yml)
[![Static Badge](https://img.shields.io/badge/Rules-165-green?label=Cell%20rules&labelColor=blue&color=gray)](src/Rules/Cell)
[![Static Badge](https://img.shields.io/badge/Rules-206-green?label=Aggregate%20rules&labelColor=blue&color=gray)](src/Rules/Aggregate)
[![Static Badge](https://img.shields.io/badge/Rules-8-green?label=Extra%20checks&labelColor=blue&color=gray)](#extra-checks)
[![Static Badge](https://img.shields.io/badge/Rules-31/54/9-green?label=Plan%20to%20add&labelColor=gray&color=gray)](tests/schemas/todo.yml)
[![Static Badge](https://img.shields.io/badge/Rules-29/54/9-green?label=Plan%20to%20add&labelColor=gray&color=gray)](tests/schemas/todo.yml)
<!-- /rules-counter -->

A console utility designed for validating CSV files against a strictly defined schema and validation rules outlined
Expand Down Expand Up @@ -419,6 +419,17 @@ columns:
date_interval_less: PT23H59M59S # 23 hours, 59 minutes, and 59 seconds
date_interval_max: P1Y # 1 year

# Check an arbitrary date in a CSV cell for age (years).
# Actually it calculates the difference between the date and the current date.
# Convenient to use for age restrictions based on birthday.
# See the description of `date_*` functions for details on date formats.
date_age_min: 1 # x >= 1
date_age_greater: 14 # x > 14
date_age_not: 18 # x != 18
date_age: 21 # x == 21
date_age_less: 99 # x < 99
date_age_max: 100 # x <= 100

# Specific formats
is_bool: true # Allow only boolean values "true" and "false", case-insensitive.
is_uuid: true # Validates whether the input is a valid UUID. It also supports validation of specific versions 1, 3, 4 and 5.
Expand Down
7 changes: 7 additions & 0 deletions schema-examples/full.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@
"date_interval_less" : "PT23H59M59S",
"date_interval_max" : "P1Y",

"date_age_min" : 1,
"date_age_greater" : 14,
"date_age_not" : 18,
"date_age" : 21,
"date_age_less" : 99,
"date_age_max" : 100,

"is_bool" : true,
"is_uuid" : true,
"is_slug" : true,
Expand Down
7 changes: 7 additions & 0 deletions schema-examples/full.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@
'date_interval_less' => 'PT23H59M59S',
'date_interval_max' => 'P1Y',

'date_age_min' => 1,
'date_age_greater' => 14,
'date_age_not' => 18,
'date_age' => 21,
'date_age_less' => 99,
'date_age_max' => 100,

'is_bool' => true,
'is_uuid' => true,
'is_slug' => true,
Expand Down
11 changes: 11 additions & 0 deletions schema-examples/full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ columns:
date_interval_less: PT23H59M59S # 23 hours, 59 minutes, and 59 seconds
date_interval_max: P1Y # 1 year

# Check an arbitrary date in a CSV cell for age (years).
# Actually it calculates the difference between the date and the current date.
# Convenient to use for age restrictions based on birthday.
# See the description of `date_*` functions for details on date formats.
date_age_min: 1 # x >= 1
date_age_greater: 14 # x > 14
date_age_not: 18 # x != 18
date_age: 21 # x == 21
date_age_less: 99 # x < 99
date_age_max: 100 # x <= 100

# Specific formats
is_bool: true # Allow only boolean values "true" and "false", case-insensitive.
is_uuid: true # Validates whether the input is a valid UUID. It also supports validation of specific versions 1, 3, 4 and 5.
Expand Down
7 changes: 7 additions & 0 deletions schema-examples/full_clean.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ columns:
date_interval_less: PT23H59M59S
date_interval_max: P1Y

date_age_min: 1
date_age_greater: 14
date_age_not: 18
date_age: 21
date_age_less: 99
date_age_max: 100

is_bool: true
is_uuid: true
is_slug: true
Expand Down
85 changes: 85 additions & 0 deletions src/Rules/Cell/ComboDateAge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/**
* JBZoo Toolbox - Csv-Blueprint.
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @see https://github.com/JBZoo/Csv-Blueprint
*/

declare(strict_types=1);

namespace JBZoo\CsvBlueprint\Rules\Cell;

final class ComboDateAge extends AbstractCellRuleCombo
{
protected const NAME = 'age';

protected const INVALID_DATEINTERVAL_ACTUAL = -1;
protected const INVALID_DATEINTERVAL_EXPECTED = -2;

public function getHelpMeta(): array
{
return [
[
'Check an arbitrary date in a CSV cell for age (years).',
'Actually it calculates the difference between the date and the current date.',
'Convenient to use for age restrictions based on birthday.',
'See the description of `date_*` functions for details on date formats.',
],
[
self::MIN => [1, 'x >= 1'],
self::GREATER => [14, 'x > 14'],
self::NOT => [18, 'x != 18'],
self::EQ => [21, 'x == 21'],
self::LESS => [99, 'x < 99'],
self::MAX => [100, 'x <= 100'],
],
];
}

protected function getActualCell(string $cellValue): float
{
try {
$years = self::calculateAge($cellValue);
} catch (\Exception) {
return self::INVALID_DATEINTERVAL_ACTUAL;
}

return $years;
}

protected function getExpected(): float
{
return $this->getOptionAsInt();
}

protected function getExpectedStr(): string
{
return "{$this->getOptionAsInt()} years";
}

protected function getCurrentStr(string $cellValue): string
{
try {
$years = self::calculateAge($cellValue);
} catch (\Exception $exception) {
return "<red>{$exception->getMessage()}</red>";
}

return "parsed as \"{$years}\" years";
}

private static function calculateAge(string $dateString): int
{
$birthDateTime = new \DateTimeImmutable($dateString);
$currentDateTime = new \DateTimeImmutable('now');

return $birthDateTime->diff($currentDateTime)->y; // Returns the total number of full years
}
}
74 changes: 74 additions & 0 deletions tests/Rules/Cell/ComboDateAgeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

/**
* JBZoo Toolbox - Csv-Blueprint.
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @see https://github.com/JBZoo/Csv-Blueprint
*/

declare(strict_types=1);

namespace JBZoo\PHPUnit\Rules\Cell;

use JBZoo\CsvBlueprint\Rules\AbstarctRule as Combo;
use JBZoo\CsvBlueprint\Rules\Cell\ComboDateAge;
use JBZoo\PHPUnit\Rules\TestAbstractCellRuleCombo;

use function JBZoo\PHPUnit\isSame;

class ComboDateAgeTest extends TestAbstractCellRuleCombo
{
protected string $ruleClass = ComboDateAge::class;

public function testEqual(): void
{
$rule = $this->create(0, Combo::EQ);

isSame('', $rule->test(''));
isSame('', $rule->test('now'));

isSame(
'The age of the value "2020-10-02" is parsed as "3" years, ' .
'which is not equal than the expected "0 years"',
$rule->test('2020-10-02'),
);

isSame(
'The age of the value "<c>qwerty</c>" is ' .
'<red>Failed to parse time string (qwerty) at position 0 (q): ' .
'The timezone could not be found in the database</red>, ' .
'which is not equal than the expected "<green>0 years</green>"',
$rule->test('qwerty', true),
);
}

public function testMin(): void
{
$rule = $this->create(21, Combo::MIN);

isSame('', $rule->test(''));
isSame('', $rule->test('+22 years'));
isSame('', $rule->test('2100-01-01'));
isSame('', $rule->test('2100-01'));

isSame(
'The age of the value "2020-10-02" is parsed as "3" years, ' .
'which is less than the expected "21 years"',
$rule->test('2020-10-02'),
);

isSame(
'The age of the value "<c>qwerty</c>" is ' .
'<red>Failed to parse time string (qwerty) at position 0 (q): ' .
'The timezone could not be found in the database</red>, ' .
'which is less than the expected "<green>21 years</green>"',
$rule->test('qwerty', true),
);
}
}
4 changes: 0 additions & 4 deletions tests/schemas/todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ columns:
is_bool_value: true # https://github.com/Respect/Validation/blob/main/docs/rules/BoolVal.md
is_null: true # see empty_values

# Dates
age: 35
dateperiod: 1

# Codes
subdivision_code: [ ] # https://github.com/Respect/Validation/blob/main/docs/rules/SubdivisionCode.md

Expand Down