diff --git a/README.md b/README.md index a7b98312..3b2acda7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![GitHub Release](https://img.shields.io/github/v/release/jbzoo/csv-blueprint?label=Latest)](https://github.com/jbzoo/csv-blueprint/releases) [![Total Downloads](https://poser.pugx.org/jbzoo/csv-blueprint/downloads)](https://packagist.org/packages/jbzoo/csv-blueprint/stats) [![Docker Pulls](https://img.shields.io/docker/pulls/jbzoo/csv-blueprint.svg)](https://hub.docker.com/r/jbzoo/csv-blueprint/tags) [![Docker Image Size](https://img.shields.io/docker/image-size/jbzoo/csv-blueprint)](https://hub.docker.com/r/jbzoo/csv-blueprint/tags) -[![Static Badge](https://img.shields.io/badge/Rules-277-green?label=Total%20number%20of%20rules&labelColor=darkgreen&color=gray)](schema-examples/full.yml) [![Static Badge](https://img.shields.io/badge/Rules-66-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-5-green?label=Extra%20checks&labelColor=blue&color=gray)](#extra-checks) [![Static Badge](https://img.shields.io/badge/Rules-227-green?label=Plan%20to%20add&labelColor=gray&color=gray)](tests/schemas/todo.yml) +[![Static Badge](https://img.shields.io/badge/Rules-278-green?label=Total%20number%20of%20rules&labelColor=darkgreen&color=gray)](schema-examples/full.yml) [![Static Badge](https://img.shields.io/badge/Rules-67-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-5-green?label=Extra%20checks&labelColor=blue&color=gray)](#extra-checks) [![Static Badge](https://img.shields.io/badge/Rules-211-green?label=Plan%20to%20add&labelColor=gray&color=gray)](tests/schemas/todo.yml) ## Introduction @@ -242,9 +242,10 @@ columns: is_email: true # Only email format. Example: "user@example.com". is_domain: true # Only domain name. Example: "example.com". is_uuid: true # Validates whether the input is a valid UUID. It also supports validation of specific versions 1, 3, 4 and 5. - is_alias: true # Only alias format. Example: "my-alias-123". It can contain letters, numbers, and dashes. + is_slug: true # Only slug format. Example: "my-slug-123". It can contain letters, numbers, and dashes. is_currency_code: true # Validates an ISO 4217 currency code like GBP or EUR. Case-sensitive. See: https://en.wikipedia.org/wiki/ISO_4217. is_base64: true # Validate if a string is Base64-encoded. Example: "cmVzcGVjdCE=". + is_angle: true # Check if the cell value is a valid angle (0.0 to 360.0). # Validates if the given input is a valid JSON. # This is possible if you escape all special characters correctly and use a special CSV format. @@ -898,7 +899,6 @@ It's random ideas and plans. No orderings and deadlines. But batch processing * Warnings about deprecated options and features. * Add option `--recomendation` to show a list of recommended rules for the schema or potential issues in the CSV file or schema. It's useful when you are not sure what rules to use. * Add option `--error=[level]` to show only errors with a specific level. It's useful when you have a lot of warnings and you want to see only errors. - * Move `const:HELP` to PHP annotations. Canonic way to describe the command. * S3 Storage support. Validate files in the S3 bucket? Hmm... Why not? But... * More examples and documentation. diff --git a/schema-examples/full.json b/schema-examples/full.json index 272cc225..eaee85a4 100644 --- a/schema-examples/full.json +++ b/schema-examples/full.json @@ -84,9 +84,10 @@ "is_email" : true, "is_domain" : true, "is_uuid" : true, - "is_alias" : true, + "is_slug" : true, "is_currency_code" : true, "is_base64" : true, + "is_angle" : true, "is_json" : true, "is_latitude" : true, "is_longitude" : true, diff --git a/schema-examples/full.php b/schema-examples/full.php index 6ebdc382..01952588 100644 --- a/schema-examples/full.php +++ b/schema-examples/full.php @@ -105,9 +105,10 @@ 'is_email' => true, 'is_domain' => true, 'is_uuid' => true, - 'is_alias' => true, + 'is_slug' => true, 'is_currency_code' => true, 'is_base64' => true, + 'is_angle' => true, 'is_json' => true, 'is_latitude' => true, 'is_longitude' => true, diff --git a/schema-examples/full.yml b/schema-examples/full.yml index dc3a2f39..1f72dc8d 100644 --- a/schema-examples/full.yml +++ b/schema-examples/full.yml @@ -156,9 +156,10 @@ columns: is_email: true # Only email format. Example: "user@example.com". is_domain: true # Only domain name. Example: "example.com". is_uuid: true # Validates whether the input is a valid UUID. It also supports validation of specific versions 1, 3, 4 and 5. - is_alias: true # Only alias format. Example: "my-alias-123". It can contain letters, numbers, and dashes. + is_slug: true # Only slug format. Example: "my-slug-123". It can contain letters, numbers, and dashes. is_currency_code: true # Validates an ISO 4217 currency code like GBP or EUR. Case-sensitive. See: https://en.wikipedia.org/wiki/ISO_4217. is_base64: true # Validate if a string is Base64-encoded. Example: "cmVzcGVjdCE=". + is_angle: true # Check if the cell value is a valid angle (0.0 to 360.0). # Validates if the given input is a valid JSON. # This is possible if you escape all special characters correctly and use a special CSV format. diff --git a/schema-examples/full_clean.yml b/schema-examples/full_clean.yml index c9e5dfb3..32edd8d2 100644 --- a/schema-examples/full_clean.yml +++ b/schema-examples/full_clean.yml @@ -112,9 +112,10 @@ columns: is_email: true is_domain: true is_uuid: true - is_alias: true + is_slug: true is_currency_code: true is_base64: true + is_angle: true is_json: true is_latitude: true is_longitude: true diff --git a/src/Rules/Cell/DateFormat.php b/src/Rules/Cell/DateFormat.php index 0bdfa577..8e5fb3ce 100644 --- a/src/Rules/Cell/DateFormat.php +++ b/src/Rules/Cell/DateFormat.php @@ -40,7 +40,7 @@ public function validateRule(string $cellValue): ?string $date = \DateTimeImmutable::createFromFormat($expectedDateFormat, $cellValue); if ($date === false || $date->format($expectedDateFormat) !== $cellValue) { return "Date format of value \"{$cellValue}\" is not valid. " . - "Expected format: \"{$expectedDateFormat}\""; + "Expected format: \"{$expectedDateFormat}\""; } return null; diff --git a/src/Rules/Cell/ExactValue.php b/src/Rules/Cell/ExactValue.php index 9d820b3c..c244a0b9 100644 --- a/src/Rules/Cell/ExactValue.php +++ b/src/Rules/Cell/ExactValue.php @@ -30,9 +30,13 @@ public function getHelpMeta(): array public function validateRule(string $cellValue): ?string { + if ($cellValue === '') { + return null; + } + if ($this->getOptionAsString() !== $cellValue) { return "Value \"{$cellValue}\" is not strict equal to " . - "\"{$this->getOptionAsString()}\""; + "\"{$this->getOptionAsString()}\""; } return null; diff --git a/src/Rules/Cell/IsAngle.php b/src/Rules/Cell/IsAngle.php new file mode 100644 index 00000000..1bb5635a --- /dev/null +++ b/src/Rules/Cell/IsAngle.php @@ -0,0 +1,48 @@ + ['true', 'Check if the cell value is a valid angle (0.0 to 360.0).'], + ], + ]; + } + + public function validateRule(string $cellValue): ?string + { + $result = parent::validateRule($cellValue); + if ($result !== null) { + return $result; + } + + $angle = (float)$cellValue; + if ($angle < $this->min || $angle > $this->max) { + return "Value \"{$cellValue}\" is not a valid angle ({$this->min} to {$this->max})"; + } + + return null; + } +} diff --git a/src/Rules/Cell/IsAlias.php b/src/Rules/Cell/IsSlug.php similarity index 66% rename from src/Rules/Cell/IsAlias.php rename to src/Rules/Cell/IsSlug.php index bab6f35a..5c1e549c 100644 --- a/src/Rules/Cell/IsAlias.php +++ b/src/Rules/Cell/IsSlug.php @@ -16,9 +16,9 @@ namespace JBZoo\CsvBlueprint\Rules\Cell; -use JBZoo\Utils\Filter; +use Respect\Validation\Validator; -final class IsAlias extends AbstractCellRule +final class IsSlug extends AbstractCellRule { public function getHelpMeta(): array { @@ -27,7 +27,7 @@ public function getHelpMeta(): array [ self::DEFAULT => [ 'true', - 'Only alias format. Example: "my-alias-123". It can contain letters, numbers, and dashes.', + 'Only slug format. Example: "my-slug-123". It can contain letters, numbers, and dashes.', ], ], ]; @@ -35,9 +35,8 @@ public function getHelpMeta(): array public function validateRule(string $cellValue): ?string { - $alias = Filter::alias($cellValue); - if ($cellValue !== $alias) { - return "Value \"{$cellValue}\" is not a valid alias. Expected \"{$alias}\"."; + if (!Validator::slug()->validate($cellValue)) { + return "Value \"{$cellValue}\" is not a valid slug. Expected format \"my-slug-123\""; } return null; diff --git a/tests/Rules/Cell/ExactValueTest.php b/tests/Rules/Cell/ExactValueTest.php index 31f28761..55afbd19 100644 --- a/tests/Rules/Cell/ExactValueTest.php +++ b/tests/Rules/Cell/ExactValueTest.php @@ -28,16 +28,13 @@ final class ExactValueTest extends TestAbstractCellRule public function testPositive(): void { $rule = $this->create('123'); + isSame('', $rule->test('')); isSame('', $rule->test('123')); } public function testNegative(): void { $rule = $this->create('123'); - isSame( - 'Value "" is not strict equal to "123"', - $rule->test(''), - ); isSame( 'Value "2000-01-02" is not strict equal to "123"', $rule->test('2000-01-02'), diff --git a/tests/Rules/Cell/IsAngleTest.php b/tests/Rules/Cell/IsAngleTest.php new file mode 100644 index 00000000..11d51c2f --- /dev/null +++ b/tests/Rules/Cell/IsAngleTest.php @@ -0,0 +1,56 @@ +create(true); + isSame('', $rule->test('0')); + isSame('', $rule->test('90')); + isSame('', $rule->test('360.0')); + isSame('', $rule->test('360')); + + $rule = $this->create(false); + isSame(null, $rule->validate('90.1.1.1.1')); + } + + public function testNegative(): void + { + $rule = $this->create(true); + isSame( + 'Value "1230" is not a valid angle (0 to 360)', + $rule->test('1230'), + ); + isSame( + 'Value "-0.1" is not a valid angle (0 to 360)', + $rule->test('-0.1'), + ); + isSame( + 'Value "90.1.1.1.1" is not a float number', + $rule->test('90.1.1.1.1'), + ); + } +} diff --git a/tests/Rules/Cell/IsAliasTest.php b/tests/Rules/Cell/IsSlugTest.php similarity index 73% rename from tests/Rules/Cell/IsAliasTest.php rename to tests/Rules/Cell/IsSlugTest.php index 304f7004..774f0ab4 100644 --- a/tests/Rules/Cell/IsAliasTest.php +++ b/tests/Rules/Cell/IsSlugTest.php @@ -16,19 +16,19 @@ namespace JBZoo\PHPUnit\Rules\Cell; -use JBZoo\CsvBlueprint\Rules\Cell\IsAlias; +use JBZoo\CsvBlueprint\Rules\Cell\IsSlug; use JBZoo\PHPUnit\Rules\TestAbstractCellRule; use function JBZoo\PHPUnit\isSame; -final class IsAliasTest extends TestAbstractCellRule +final class IsSlugTest extends TestAbstractCellRule { - protected string $ruleClass = IsAlias::class; + protected string $ruleClass = IsSlug::class; public function testPositive(): void { $rule = $this->create(true); - isSame('', $rule->test('')); + isSame('Value "" is not a valid slug. Expected format "my-slug-123"', $rule->test('')); isSame('', $rule->test('123')); $rule = $this->create(false); @@ -39,7 +39,7 @@ public function testNegative(): void { $rule = $this->create(true); isSame( - 'Value "Qwerty, asd 123" is not a valid alias. Expected "qwerty-asd-123".', + 'Value "Qwerty, asd 123" is not a valid slug. Expected format "my-slug-123"', $rule->test('Qwerty, asd 123'), ); } diff --git a/tests/schemas/todo.yml b/tests/schemas/todo.yml index 5980fecc..735f9548 100644 --- a/tests/schemas/todo.yml +++ b/tests/schemas/todo.yml @@ -40,8 +40,6 @@ columns: rules: # https://github.com/Respect/Validation/blob/main/docs/08-list-of-rules-by-category.md - is_credit_card: brands[] # https://github.com/Respect/Validation/blob/main/docs/rules/CreditCard.md - is_iban: true is_bool_value: true # https://github.com/Respect/Validation/blob/main/docs/rules/BoolVal.md # Dates @@ -66,6 +64,8 @@ columns: subdivision_code: [ ] # https://github.com/Respect/Validation/blob/main/docs/rules/SubdivisionCode.md # ids + is_credit_card: brands[] # https://github.com/Respect/Validation/blob/main/docs/rules/CreditCard.md + is_iban: true postal_code: country code # https://github.com/Respect/Validation/blob/main/docs/rules/PostalCode.md is_bsn: true is_cnh: true @@ -194,15 +194,14 @@ columns: # Math is_fibonacci: true is_prime_number: true - is_positive: true - is_negative: true - is_zero: true is_digit: true is_digits: true is_even: true is_odd: true is_roman: true is_perfect_square: true + + # Strings is_alnum: true is_alpha: true is_charset: true @@ -210,22 +209,18 @@ columns: no_whitespace: true is_phone: true is_punct: true - is_slug: true - is_space(s): true + is_spaces: true + is_space: true is_regex: true is_version: true is_vowel: true is_consonant: true is_xdigit: true - is_angle: # 0.0-360.0 custom_func: callbak function aggregate_rules: - count_true: 1 - count_false: 1 - # https://github.com/markrogoyski/math-php#statistics---averages truncated_mean: [ 1, 25 ] # 25 percent of observations trimmed from each end of distribution generalized_mean: [ 1, 2 ] # p-power mean