diff --git a/README.md b/README.md index 8b2f48c2..d6501e8e 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ -[![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) A console utility designed for validating CSV files against a strictly defined schema and validation rules outlined @@ -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. diff --git a/schema-examples/full.json b/schema-examples/full.json index 2051f559..ba55b349 100644 --- a/schema-examples/full.json +++ b/schema-examples/full.json @@ -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, diff --git a/schema-examples/full.php b/schema-examples/full.php index 5e4d1544..c69740d2 100644 --- a/schema-examples/full.php +++ b/schema-examples/full.php @@ -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, diff --git a/schema-examples/full.yml b/schema-examples/full.yml index 2e1ab644..8b7b59ef 100644 --- a/schema-examples/full.yml +++ b/schema-examples/full.yml @@ -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. diff --git a/schema-examples/full_clean.yml b/schema-examples/full_clean.yml index cd73f8bd..90b00b7f 100644 --- a/schema-examples/full_clean.yml +++ b/schema-examples/full_clean.yml @@ -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 diff --git a/src/Rules/Cell/ComboDateAge.php b/src/Rules/Cell/ComboDateAge.php new file mode 100644 index 00000000..b672b569 --- /dev/null +++ b/src/Rules/Cell/ComboDateAge.php @@ -0,0 +1,85 @@ + [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 "{$exception->getMessage()}"; + } + + 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 + } +} diff --git a/tests/Rules/Cell/ComboDateAgeTest.php b/tests/Rules/Cell/ComboDateAgeTest.php new file mode 100644 index 00000000..22aeb0ff --- /dev/null +++ b/tests/Rules/Cell/ComboDateAgeTest.php @@ -0,0 +1,74 @@ +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 "qwerty" is ' . + 'Failed to parse time string (qwerty) at position 0 (q): ' . + 'The timezone could not be found in the database, ' . + 'which is not equal than the expected "0 years"', + $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 "qwerty" is ' . + 'Failed to parse time string (qwerty) at position 0 (q): ' . + 'The timezone could not be found in the database, ' . + 'which is less than the expected "21 years"', + $rule->test('qwerty', true), + ); + } +} diff --git a/tests/schemas/todo.yml b/tests/schemas/todo.yml index 492e6338..3854c7b3 100644 --- a/tests/schemas/todo.yml +++ b/tests/schemas/todo.yml @@ -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