From 63800fa34c4bf9df46f38d7d7cd3c99b33bbb058 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Fri, 27 Oct 2023 22:36:58 +0200 Subject: [PATCH 1/9] chore: Stash changes --- src/Helpers/FormatsMessages.php | 14 ++--- src/Rules/AsciiOnly.php | 2 +- src/Validator/ValidationRuleParser.php | 65 ++++++++++++-------- src/Validator/Validator.php | 82 +++++++++++++++----------- 4 files changed, 95 insertions(+), 68 deletions(-) diff --git a/src/Helpers/FormatsMessages.php b/src/Helpers/FormatsMessages.php index 99fd3fa..e8a911e 100755 --- a/src/Helpers/FormatsMessages.php +++ b/src/Helpers/FormatsMessages.php @@ -60,9 +60,7 @@ protected function ruleToLower(string $rule): ?string $lowerRule = strtolower($lowerRule); - $lowerRule = ltrim($lowerRule, '_'); - - return $lowerRule; + return ltrim($lowerRule, '_'); } /** @@ -90,9 +88,7 @@ protected function makeReplacements( $message = $this->replaceValuePlaceholder($message, $value); - $message = $this->replaceErrorLinePlaceholder($message, $lineNumber); - - return $message; + return $this->replaceErrorLinePlaceholder($message, $lineNumber); } /** @@ -103,7 +99,11 @@ protected function replaceParameterPlaceholder( array $allowedParameters, array $parameters ): string { - return str_replace($allowedParameters, $parameters, $message); + $hasMultipleAllowedParameter = count($allowedParameters) > 1; + $search = $hasMultipleAllowedParameter ? $allowedParameters : $allowedParameters[0]; + $replace = $hasMultipleAllowedParameter ? $parameters : implode(',', $parameters); + + return str_replace($search, $replace, $message); } /** diff --git a/src/Rules/AsciiOnly.php b/src/Rules/AsciiOnly.php index a811a59..ed1bffc 100644 --- a/src/Rules/AsciiOnly.php +++ b/src/Rules/AsciiOnly.php @@ -15,7 +15,7 @@ class AsciiOnly implements ValidationRuleInterface */ public function passes($value, array $parameters): bool { - return (mb_detect_encoding($value, 'ASCII', true)) ? true : false; + return (bool)mb_detect_encoding($value, 'ASCII', true); } /** diff --git a/src/Validator/ValidationRuleParser.php b/src/Validator/ValidationRuleParser.php index 04c792f..09d08e3 100755 --- a/src/Validator/ValidationRuleParser.php +++ b/src/Validator/ValidationRuleParser.php @@ -13,44 +13,31 @@ class ValidationRuleParser /** * Extract the rule name and parameters from a rule. * - * @param string $rule|ValidationRuleInterface + * @param int|string $ruleKey + * @param string|Closure|ValidationRule $ruleValue */ - public static function parse($rule): array + public function parse($ruleKey, $ruleValue): array { - if ($rule instanceof Closure) { - return [new ClosureValidationRule($rule), []]; + if ($ruleValue instanceof Closure) { + return [new ClosureValidationRule($ruleValue), []]; } - if ($rule instanceof ValidationRule) { - return [$rule, []]; + if ($ruleValue instanceof ValidationRule) { + return [$ruleValue, []]; } - return static::parseStringRule($rule); + return $this->parseRule($ruleKey, $ruleValue); } - /** - * Parse a string based rule. - */ - protected static function parseStringRule(string $rule): array + protected function stringRuleHasParameter(string $rule): bool { - $parameters = []; - - // The format for specifying validation rules and parameters follows an - // easy {rule}:{parameters} formatting convention. For instance the - // rule "Between:3,5" states that the value may only be between 3 - 5. - if (false !== strpos($rule, ':')) { - list($rule, $parameter) = explode(':', $rule, 2); - - $parameters = static::parseParameters($parameter); - } - - return [static::normalizeRule($rule), $parameters]; + return false !== strpos($rule, ':'); } /** * Parse a parameter list. */ - protected static function parseParameters(string $parameter): array + protected function parseParameters(string $parameter): array { return str_getcsv($parameter); } @@ -58,10 +45,38 @@ protected static function parseParameters(string $parameter): array /** * Normalizes a rule. */ - protected static function normalizeRule(string $rule): string + protected function normalizeRule(string $rule): string { $rule = ucwords(str_replace(['-', '_'], ' ', $rule)); return preg_replace('/\s/', '', $rule); } + + /** + * Parse lib defined rule. + * + * @param int|string $ruleKey + * @param string|Closure|ValidationRule $ruleValue + */ + protected function parseRule($ruleKey, $ruleValue): array + { + $parameters = []; + $rule = ''; + + if (is_int($ruleKey) && is_string($ruleValue)) { + // This will match ["rule"], ["rule:value"], ["rule:value1, value2"] + $rule = $ruleValue; + + if ($this->stringRuleHasParameter($rule)) { + list($rule, $ruleParameters) = explode(':', $ruleValue); + + $parameters = static::parseParameters($ruleParameters); + } + } elseif (is_string($ruleKey) && !static::stringRuleHasParameter($ruleKey)) { + + } + + + return [$this->normalizeRule($rule), $parameters]; + } } diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index 1159ccd..4b20323 100755 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -114,7 +114,7 @@ class Validator /** * Create a new Validator instance. */ - public function __construct(string $filePath, string $delimiter = ',', array $rules, array $messages = []) + public function __construct(string $filePath, string $delimiter = ',', array $rules = [], array $messages = []) { $this->filePath = $filePath; $this->delimiter = $delimiter; @@ -123,6 +123,15 @@ public function __construct(string $filePath, string $delimiter = ',', array $ru $this->setFileDirectory(); $this->setFileName(); + + $this->validateFile(); + } + + protected function validateFile() + { + if ($this->doesFileExistAndReadable()) { + $this->message = self::INVALID_FILE_PATH_ERROR; + } } /** @@ -172,27 +181,27 @@ public function fails(): bool */ protected function passes(): bool { - if ($this->doesFileExistAndReadable($this->filePath)) { - if (false !== ($handle = fopen($this->filePath, 'r'))) { - while (false !== ($row = fgetcsv($handle, 0, $this->delimiter))) { - ++$this->currentRowLineNumber; - if (empty($this->headers)) { - $this->setHeaders($row); - continue; - } - - $rowWithAttribute = []; - - foreach ($row as $key => $value) { - $attribute = $this->headers[$key]; - $rowWithAttribute[$attribute] = $value; - } - - $this->validateRow($rowWithAttribute); + if (!empty($this->message)) { + return false; + } + + if (false !== ($handle = fopen($this->filePath, 'r'))) { + while (false !== ($row = fgetcsv($handle, 0, $this->delimiter))) { + ++$this->currentRowLineNumber; + if (empty($this->headers)) { + $this->setHeaders($row); + continue; } + + $rowWithAttribute = []; + + foreach ($row as $key => $value) { + $attribute = $this->headers[$key]; + $rowWithAttribute[$attribute] = $value; + } + + $this->validateRow($rowWithAttribute); } - } else { - $this->message = self::INVALID_FILE_PATH_ERROR; } return empty($this->invalidRows) && empty($this->message); @@ -241,8 +250,8 @@ protected function validateRow(array $row): void $this->currentRow = $row; foreach ($this->rules as $attribute => $rules) { - foreach ($rules as $rule) { - $this->validateAttribute($attribute, $rule); + foreach ($rules as $ruleKey => $ruleValue) { + $this->validateAttribute($attribute, $ruleKey, $ruleValue); } } @@ -257,11 +266,12 @@ protected function validateRow(array $row): void /** * Validate a given attribute against a rule. * - * @param string|object $rule + * @param int|string $ruleKey + * @param string|Closure|ValidationRule $ruleValue */ - protected function validateAttribute(string $attribute, $rule): void + protected function validateAttribute(string $attribute, $ruleKey, $ruleValue): void { - list($rule, $parameters) = ValidationRuleParser::parse($rule); + list($rule, $parameters) = ValidationRuleParser::parse($ruleKey, $ruleValue); if ('' === $rule) { return; @@ -277,22 +287,24 @@ protected function validateAttribute(string $attribute, $rule): void if ($this->isValidateAble($rule, $parameters)) { $ruleClass = $this->getRuleClass($rule); - if (!$ruleClass->passes($value, $parameters)) { - $this->addFailure( - $this->getMessage($attribute, $ruleClass, $rule), - $attribute, - $value, - $ruleClass, - $parameters - ); + + if ($ruleClass->passes($value, $parameters)) { + return; } - return; + $this->addFailure( + $this->getMessage($attribute, $ruleClass, $rule), + $attribute, + $value, + $ruleClass, + $parameters + ); } } - protected function doesFileExistAndReadable(string $filePath): bool + protected function doesFileExistAndReadable(): bool { + $filePath = $this->filePath; return file_exists($filePath) && is_readable($filePath); } From 07d6d52d0ad1b0bd733b9912b1be46e575254f94 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Fri, 27 Oct 2023 23:48:05 +0200 Subject: [PATCH 2/9] chore: Updated tests --- src/Validator/ValidationRuleParser.php | 20 ++++++++++---------- src/Validator/Validator.php | 7 +++++-- tests/src/CsvValidatorParserTest.php | 10 +++++----- tests/src/CsvValidatorTest.php | 4 ++-- tests/src/UppercaseRule.php | 3 ++- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Validator/ValidationRuleParser.php b/src/Validator/ValidationRuleParser.php index 09d08e3..f5a2232 100755 --- a/src/Validator/ValidationRuleParser.php +++ b/src/Validator/ValidationRuleParser.php @@ -16,7 +16,7 @@ class ValidationRuleParser * @param int|string $ruleKey * @param string|Closure|ValidationRule $ruleValue */ - public function parse($ruleKey, $ruleValue): array + public static function parse($ruleKey, $ruleValue): array { if ($ruleValue instanceof Closure) { return [new ClosureValidationRule($ruleValue), []]; @@ -26,10 +26,10 @@ public function parse($ruleKey, $ruleValue): array return [$ruleValue, []]; } - return $this->parseRule($ruleKey, $ruleValue); + return ValidationRuleParser::parseRule($ruleKey, $ruleValue); } - protected function stringRuleHasParameter(string $rule): bool + protected static function stringRuleHasParameter(string $rule): bool { return false !== strpos($rule, ':'); } @@ -37,7 +37,7 @@ protected function stringRuleHasParameter(string $rule): bool /** * Parse a parameter list. */ - protected function parseParameters(string $parameter): array + protected static function parseParameters(string $parameter): array { return str_getcsv($parameter); } @@ -45,7 +45,7 @@ protected function parseParameters(string $parameter): array /** * Normalizes a rule. */ - protected function normalizeRule(string $rule): string + protected static function normalizeRule(string $rule): string { $rule = ucwords(str_replace(['-', '_'], ' ', $rule)); @@ -58,16 +58,16 @@ protected function normalizeRule(string $rule): string * @param int|string $ruleKey * @param string|Closure|ValidationRule $ruleValue */ - protected function parseRule($ruleKey, $ruleValue): array + protected static function parseRule($ruleKey, $ruleValue): array { - $parameters = []; $rule = ''; + $parameters = []; if (is_int($ruleKey) && is_string($ruleValue)) { - // This will match ["rule"], ["rule:value"], ["rule:value1, value2"] + // This will match "rule", "rule:value", "rule:value1,value2" $rule = $ruleValue; - if ($this->stringRuleHasParameter($rule)) { + if (ValidationRuleParser::stringRuleHasParameter($rule)) { list($rule, $ruleParameters) = explode(':', $ruleValue); $parameters = static::parseParameters($ruleParameters); @@ -77,6 +77,6 @@ protected function parseRule($ruleKey, $ruleValue): array } - return [$this->normalizeRule($rule), $parameters]; + return [ValidationRuleParser::normalizeRule($rule), $parameters]; } } diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index 73a0b6a..696999c 100755 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -123,13 +123,16 @@ public function __construct(string $filePath, array $rules, string $delimiter = $this->setFileDirectory(); $this->setFileName(); - $this->validateFile(); } + /** + * + * @return void + */ protected function validateFile() { - if ($this->doesFileExistAndReadable()) { + if (!$this->doesFileExistAndReadable()) { $this->message = self::INVALID_FILE_PATH_ERROR; } } diff --git a/tests/src/CsvValidatorParserTest.php b/tests/src/CsvValidatorParserTest.php index 27086c6..19691ca 100755 --- a/tests/src/CsvValidatorParserTest.php +++ b/tests/src/CsvValidatorParserTest.php @@ -1,8 +1,8 @@ assertSame( [$customRule, []], - ValidationRuleParser::parse($customRule) + ValidationRuleParser::parse(0, $customRule) ); } @@ -21,7 +21,7 @@ public function testWhenOtherRulesArePassed() { $this->assertSame( ['AsciiOnly', []], - ValidationRuleParser::parse('ascii_only') + ValidationRuleParser::parse(0, 'ascii_only') ); } @@ -29,7 +29,7 @@ public function testWhenRulesAcceptParameters() { $this->assertSame( ['Between', ['1', '3']], - ValidationRuleParser::parse('between:1,3') + ValidationRuleParser::parse(0, 'between:1,3') ); } } diff --git a/tests/src/CsvValidatorTest.php b/tests/src/CsvValidatorTest.php index e9911ba..e5322d4 100755 --- a/tests/src/CsvValidatorTest.php +++ b/tests/src/CsvValidatorTest.php @@ -1,10 +1,10 @@ Date: Sat, 15 Nov 2025 21:21:59 +0100 Subject: [PATCH 3/9] chore: Fixed dependebot config --- .github/dependabot.yml | 12 ++++++------ .travis.yml | 12 ++++++------ docker-compose.yml | 2 -- src/Rules/AsciiOnly.php | 2 +- src/Validator/ValidationRuleParser.php | 6 ++---- src/Validator/Validator.php | 4 ++-- tests/src/UppercaseRule.php | 2 -- 7 files changed, 17 insertions(+), 23 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5a98fda..925131a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,8 @@ version: 2 updates: -- package-ecosystem: composer - directory: "/" - schedule: - interval: daily - time: "04:00" - open-pull-requests-limit: 10 + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "daily" + time: "04:00" + open-pull-requests-limit: 10 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 32d5e2e..b2ad444 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ language: php + php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 + - 8.0 + - 8.1 + - 8.2 + - 8.3 - nightly matrix: @@ -17,5 +18,4 @@ script: - composer test after_success: - - bash <(curl -s https://codecov.io/bash) - + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 95505fb..4444ddf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: php7: build: diff --git a/src/Rules/AsciiOnly.php b/src/Rules/AsciiOnly.php index ed1bffc..7f911e5 100644 --- a/src/Rules/AsciiOnly.php +++ b/src/Rules/AsciiOnly.php @@ -15,7 +15,7 @@ class AsciiOnly implements ValidationRuleInterface */ public function passes($value, array $parameters): bool { - return (bool)mb_detect_encoding($value, 'ASCII', true); + return (bool) mb_detect_encoding($value, 'ASCII', true); } /** diff --git a/src/Validator/ValidationRuleParser.php b/src/Validator/ValidationRuleParser.php index f5a2232..e8ac877 100755 --- a/src/Validator/ValidationRuleParser.php +++ b/src/Validator/ValidationRuleParser.php @@ -13,7 +13,7 @@ class ValidationRuleParser /** * Extract the rule name and parameters from a rule. * - * @param int|string $ruleKey + * @param int|string $ruleKey * @param string|Closure|ValidationRule $ruleValue */ public static function parse($ruleKey, $ruleValue): array @@ -55,7 +55,7 @@ protected static function normalizeRule(string $rule): string /** * Parse lib defined rule. * - * @param int|string $ruleKey + * @param int|string $ruleKey * @param string|Closure|ValidationRule $ruleValue */ protected static function parseRule($ruleKey, $ruleValue): array @@ -73,10 +73,8 @@ protected static function parseRule($ruleKey, $ruleValue): array $parameters = static::parseParameters($ruleParameters); } } elseif (is_string($ruleKey) && !static::stringRuleHasParameter($ruleKey)) { - } - return [ValidationRuleParser::normalizeRule($rule), $parameters]; } } diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index 696999c..57a5188 100755 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -127,7 +127,6 @@ public function __construct(string $filePath, array $rules, string $delimiter = } /** - * * @return void */ protected function validateFile() @@ -269,7 +268,7 @@ protected function validateRow(array $row): void /** * Validate a given attribute against a rule. * - * @param int|string $ruleKey + * @param int|string $ruleKey * @param string|Closure|ValidationRule $ruleValue */ protected function validateAttribute(string $attribute, $ruleKey, $ruleValue): void @@ -308,6 +307,7 @@ protected function validateAttribute(string $attribute, $ruleKey, $ruleValue): v protected function doesFileExistAndReadable(): bool { $filePath = $this->filePath; + return file_exists($filePath) && is_readable($filePath); } diff --git a/tests/src/UppercaseRule.php b/tests/src/UppercaseRule.php index 6286ceb..74ae0a9 100644 --- a/tests/src/UppercaseRule.php +++ b/tests/src/UppercaseRule.php @@ -8,8 +8,6 @@ class UppercaseRule implements ValidationRuleInterface { /** * @param mixed $value - * @param array $parameters - * @return bool */ public function passes($value, array $parameters): bool { From 4ea296b5ef45795e80de409b54d7a66c636ee2d8 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Sat, 15 Nov 2025 21:32:48 +0100 Subject: [PATCH 4/9] chore: Make php cs fixer happy --- .github/workflows/branch.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index f706a23..65babba 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -33,4 +33,6 @@ jobs: run: composer install --prefer-dist --no-progress - name: Run test suite + env: + PHP_CS_FIXER_IGNORE_ENV: 1 run: composer run-script php-cs-fixer-check && composer run-script test From 116aed978cf82d721cc69737d6ba5f759c6b5ebb Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Sat, 15 Nov 2025 21:58:27 +0100 Subject: [PATCH 5/9] chore: Delete travis --- .github/workflows/branch.yml | 8 ++++++++ .travis.yml | 21 --------------------- 2 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 65babba..a1230bd 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -36,3 +36,11 @@ jobs: env: PHP_CS_FIXER_IGNORE_ENV: 1 run: composer run-script php-cs-fixer-check && composer run-script test + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: build/logs/clover.xml + fail_ci_if_error: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b2ad444..0000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: php - -php: - - 8.0 - - 8.1 - - 8.2 - - 8.3 - - nightly - -matrix: - allow_failures: - - php: nightly - -install: - - composer install --no-interaction - -script: - - composer test - -after_success: - - bash <(curl -s https://codecov.io/bash) \ No newline at end of file From e71a57f15957bd23b03777ed1e732316a6a2d6b7 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Sat, 15 Nov 2025 22:05:52 +0100 Subject: [PATCH 6/9] chore: revert changes --- src/Helpers/FormatsMessages.php | 6 +- src/Validator/ValidationRuleParser.php | 57 +++++++----------- src/Validator/Validator.php | 83 +++++++++++--------------- tests/src/CsvValidatorParserTest.php | 6 +- 4 files changed, 60 insertions(+), 92 deletions(-) diff --git a/src/Helpers/FormatsMessages.php b/src/Helpers/FormatsMessages.php index e8a911e..b66b243 100755 --- a/src/Helpers/FormatsMessages.php +++ b/src/Helpers/FormatsMessages.php @@ -99,11 +99,7 @@ protected function replaceParameterPlaceholder( array $allowedParameters, array $parameters ): string { - $hasMultipleAllowedParameter = count($allowedParameters) > 1; - $search = $hasMultipleAllowedParameter ? $allowedParameters : $allowedParameters[0]; - $replace = $hasMultipleAllowedParameter ? $parameters : implode(',', $parameters); - - return str_replace($search, $replace, $message); + return str_replace($allowedParameters, $parameters, $message); } /** diff --git a/src/Validator/ValidationRuleParser.php b/src/Validator/ValidationRuleParser.php index 548ba73..4bdfae6 100755 --- a/src/Validator/ValidationRuleParser.php +++ b/src/Validator/ValidationRuleParser.php @@ -14,25 +14,38 @@ class ValidationRuleParser /** * Extract the rule name and parameters from a rule. * - * @param int|string * @param string|ValidationRuleInterface $rule */ - public static function parse($ruleKey, $ruleValue): array + public static function parse($rule): array { - if ($ruleValue instanceof Closure) { - return [new ClosureValidationRule($ruleValue), []]; + if ($rule instanceof Closure) { + return [new ClosureValidationRule($rule), []]; } - if ($ruleValue instanceof ValidationRule) { - return [$ruleValue, []]; + if ($rule instanceof ValidationRule) { + return [$rule, []]; } - return ValidationRuleParser::parseRule($ruleKey, $ruleValue); + return static::parseStringRule($rule); } - protected static function stringRuleHasParameter(string $rule): bool + /** + * Parse a string based rule. + */ + protected static function parseStringRule(string $rule): array { - return false !== strpos($rule, ':'); + $parameters = []; + + // The format for specifying validation rules and parameters follows an + // easy {rule}:{parameters} formatting convention. For instance the + // rule "Between:3,5" states that the value may only be between 3 - 5. + if (false !== strpos($rule, ':')) { + list($rule, $parameter) = explode(':', $rule, 2); + + $parameters = static::parseParameters($parameter); + } + + return [static::normalizeRule($rule), $parameters]; } /** @@ -52,30 +65,4 @@ protected static function normalizeRule(string $rule): string return preg_replace('/\s/', '', $rule); } - - /** - * Parse lib defined rule. - * - * @param int|string $ruleKey - * @param string|Closure|ValidationRule $ruleValue - */ - protected static function parseRule($ruleKey, $ruleValue): array - { - $rule = ''; - $parameters = []; - - if (is_int($ruleKey) && is_string($ruleValue)) { - // This will match "rule", "rule:value", "rule:value1,value2" - $rule = $ruleValue; - - if (ValidationRuleParser::stringRuleHasParameter($rule)) { - list($rule, $ruleParameters) = explode(':', $ruleValue); - - $parameters = static::parseParameters($ruleParameters); - } - } elseif (is_string($ruleKey) && !static::stringRuleHasParameter($ruleKey)) { - } - - return [ValidationRuleParser::normalizeRule($rule), $parameters]; - } } diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index 57a5188..cc29ea5 100755 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -123,17 +123,6 @@ public function __construct(string $filePath, array $rules, string $delimiter = $this->setFileDirectory(); $this->setFileName(); - $this->validateFile(); - } - - /** - * @return void - */ - protected function validateFile() - { - if (!$this->doesFileExistAndReadable()) { - $this->message = self::INVALID_FILE_PATH_ERROR; - } } /** @@ -183,27 +172,27 @@ public function fails(): bool */ protected function passes(): bool { - if (!empty($this->message)) { - return false; - } - - if (false !== ($handle = fopen($this->filePath, 'r'))) { - while (false !== ($row = fgetcsv($handle, 0, $this->delimiter))) { - ++$this->currentRowLineNumber; - if (empty($this->headers)) { - $this->setHeaders($row); - continue; + if ($this->doesFileExistAndReadable($this->filePath)) { + if (false !== ($handle = fopen($this->filePath, 'r'))) { + while (false !== ($row = fgetcsv($handle, 0, $this->delimiter))) { + ++$this->currentRowLineNumber; + if (empty($this->headers)) { + $this->setHeaders($row); + continue; + } + + $rowWithAttribute = []; + + foreach ($row as $key => $value) { + $attribute = $this->headers[$key]; + $rowWithAttribute[$attribute] = $value; + } + + $this->validateRow($rowWithAttribute); } - - $rowWithAttribute = []; - - foreach ($row as $key => $value) { - $attribute = $this->headers[$key]; - $rowWithAttribute[$attribute] = $value; - } - - $this->validateRow($rowWithAttribute); } + } else { + $this->message = self::INVALID_FILE_PATH_ERROR; } return empty($this->invalidRows) && empty($this->message); @@ -252,8 +241,8 @@ protected function validateRow(array $row): void $this->currentRow = $row; foreach ($this->rules as $attribute => $rules) { - foreach ($rules as $ruleKey => $ruleValue) { - $this->validateAttribute($attribute, $ruleKey, $ruleValue); + foreach ($rules as $rule) { + $this->validateAttribute($attribute, $rule); } } @@ -268,12 +257,11 @@ protected function validateRow(array $row): void /** * Validate a given attribute against a rule. * - * @param int|string $ruleKey - * @param string|Closure|ValidationRule $ruleValue + * @param string|object $rule */ - protected function validateAttribute(string $attribute, $ruleKey, $ruleValue): void + protected function validateAttribute(string $attribute, $rule): void { - list($rule, $parameters) = ValidationRuleParser::parse($ruleKey, $ruleValue); + list($rule, $parameters) = ValidationRuleParser::parse($rule); if ('' === $rule) { return; @@ -289,25 +277,22 @@ protected function validateAttribute(string $attribute, $ruleKey, $ruleValue): v if ($this->isValidateAble($rule, $parameters)) { $ruleClass = $this->getRuleClass($rule); - - if ($ruleClass->passes($value, $parameters)) { - return; + if (!$ruleClass->passes($value, $parameters)) { + $this->addFailure( + $this->getMessage($attribute, $ruleClass, $rule), + $attribute, + $value, + $ruleClass, + $parameters + ); } - $this->addFailure( - $this->getMessage($attribute, $ruleClass, $rule), - $attribute, - $value, - $ruleClass, - $parameters - ); + return; } } - protected function doesFileExistAndReadable(): bool + protected function doesFileExistAndReadable(string $filePath): bool { - $filePath = $this->filePath; - return file_exists($filePath) && is_readable($filePath); } diff --git a/tests/src/CsvValidatorParserTest.php b/tests/src/CsvValidatorParserTest.php index 19691ca..8ca74df 100755 --- a/tests/src/CsvValidatorParserTest.php +++ b/tests/src/CsvValidatorParserTest.php @@ -13,7 +13,7 @@ public function testWhenCustomRuleIsPassed() $this->assertSame( [$customRule, []], - ValidationRuleParser::parse(0, $customRule) + ValidationRuleParser::parse($customRule) ); } @@ -21,7 +21,7 @@ public function testWhenOtherRulesArePassed() { $this->assertSame( ['AsciiOnly', []], - ValidationRuleParser::parse(0, 'ascii_only') + ValidationRuleParser::parse('ascii_only') ); } @@ -29,7 +29,7 @@ public function testWhenRulesAcceptParameters() { $this->assertSame( ['Between', ['1', '3']], - ValidationRuleParser::parse(0, 'between:1,3') + ValidationRuleParser::parse('between:1,3') ); } } From 319b2a8c478613e91b04687db0cf6d8c2a06d4d8 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Sat, 15 Nov 2025 22:11:35 +0100 Subject: [PATCH 7/9] chore: use shivammathur for php setup --- .github/workflows/branch.yml | 63 +++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index a1230bd..c2c0efc 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -15,32 +15,37 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - name: Validate composer.json and composer.lock - run: composer validate --strict - - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@v3 - with: - path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php- - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - - name: Run test suite - env: - PHP_CS_FIXER_IGNORE_ENV: 1 - run: composer run-script php-cs-fixer-check && composer run-script test - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - files: build/logs/clover.xml - fail_ci_if_error: true - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/checkout@v3 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + tools: composer:v2 + coverage: xdebug + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Run test suite + run: composer run-script php-cs-fixer-check && composer run-script test + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: ./build/logs/clover.xml + fail_ci_if_error: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file From 2e12e5e417f731dd5d1c545d7d813a6054e64688 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Sat, 15 Nov 2025 22:26:16 +0100 Subject: [PATCH 8/9] chore: use php unit 9 --- Makefile | 16 ++++------------ composer.json | 2 +- docker-compose.yml | 4 ++-- docker/php/{Dockerfile.php7 => Dockerfile.php8} | 10 ++++++---- src/Contracts/ValidationRuleInterface.php | 2 -- src/Converter/XmlConverter.php | 8 +++----- src/Helpers/FormatsMessages.php | 10 ++-------- src/Rules/AsciiOnly.php | 2 -- src/Rules/Between.php | 2 -- src/Rules/ClosureValidationRule.php | 2 -- src/Rules/Url.php | 2 -- src/Validator/ValidationRuleParser.php | 3 +-- src/Validator/Validator.php | 10 ++-------- tests/src/UppercaseRule.php | 3 --- 14 files changed, 21 insertions(+), 55 deletions(-) rename docker/php/{Dockerfile.php7 => Dockerfile.php8} (69%) diff --git a/Makefile b/Makefile index 22a19d4..fff9723 100644 --- a/Makefile +++ b/Makefile @@ -27,28 +27,20 @@ clean-dependencies: ## Clean dev dependencies # Not implemented .PHONY: clean-dependencies -build-php7: ## Build PHP7 container +build: ## Build PHP7 container # Hint: force a rebuild by passing --no-cache - @UID=$(UID) GID=$(GID) docker-compose build --no-cache php7 + @UID=$(UID) GID=$(GID) docker-compose build --no-cache php .PHONY: install-web stop: ## Stop running containers @UID=$(UID) GID=$(GID) docker-compose stop .PHONY: stop -shell-php7: ## Start an interactive shell session for PHP7 container +shell: ## Start an interactive shell session for PHP7 container # Hint: adjust UID and GID to 0 if you want to use the shell as root - @UID=$(UID) GID=$(GID) docker-compose run --rm -w /var/www/html -e SHELL_VERBOSITY=1 php7 bash + @UID=$(UID) GID=$(GID) docker-compose run --rm -w /var/www/html -e SHELL_VERBOSITY=1 php bash .PHONY: shell -test: ## Run all unit tests -test: php7-tests -.PHONY: test - -test-php7: ## Run php unit tests - # Not implemented -.PHONY: php7-tests - watch-logs: ## Open a tail on all the logs @UID=$(UID) GID=$(GID) docker-compose logs -f -t .PHONY: watch-logs diff --git a/composer.json b/composer.json index 91d9bc2..5f1046d 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "ext-dom": "*" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", "friendsofphp/php-cs-fixer": "^2.19 || ^3.0" }, "autoload": { diff --git a/docker-compose.yml b/docker-compose.yml index 4444ddf..d3d2fdb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ services: - php7: + php: build: context: ./docker/php/ - dockerfile: Dockerfile.php7 + dockerfile: Dockerfile.php8 volumes: - .:/var/www/html - ./docker/php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini diff --git a/docker/php/Dockerfile.php7 b/docker/php/Dockerfile.php8 similarity index 69% rename from docker/php/Dockerfile.php7 rename to docker/php/Dockerfile.php8 index dd09ff5..c5b4574 100644 --- a/docker/php/Dockerfile.php7 +++ b/docker/php/Dockerfile.php8 @@ -1,4 +1,4 @@ -FROM php:7.4-fpm +FROM php:8.1-fpm ENV APP_DIR /var/www/html @@ -8,9 +8,11 @@ RUN apt-get update && apt-get install -y \ git \ curl \ zip \ - unzip + unzip \ + && rm -rf /var/lib/apt/lists/* -RUN pecl install xdebug-3.1.5 \ +# Install and enable Xdebug (compatible version will be chosen automatically) +RUN pecl install xdebug \ && docker-php-ext-enable xdebug # Get latest Composer @@ -23,4 +25,4 @@ WORKDIR $APP_DIR COPY ./docker-entrypoint.sh / RUN chmod +x /docker-entrypoint.sh -CMD /docker-entrypoint.sh +CMD ["/docker-entrypoint.sh"] \ No newline at end of file diff --git a/src/Contracts/ValidationRuleInterface.php b/src/Contracts/ValidationRuleInterface.php index 5b05e2e..dd87f49 100644 --- a/src/Contracts/ValidationRuleInterface.php +++ b/src/Contracts/ValidationRuleInterface.php @@ -9,8 +9,6 @@ interface ValidationRuleInterface /** * Determines if the validation rule passes. This is where we do the * actual validation. If the validation passes return true else false. - * - * @param mixed $value */ public function passes($value, array $parameters): bool; diff --git a/src/Converter/XmlConverter.php b/src/Converter/XmlConverter.php index 9ab651e..722637f 100755 --- a/src/Converter/XmlConverter.php +++ b/src/Converter/XmlConverter.php @@ -4,9 +4,7 @@ namespace Oshomo\CsvUtils\Converter; -use DOMDocument; use Oshomo\CsvUtils\Contracts\ConverterHandlerInterface; -use SimpleXMLElement; class XmlConverter implements ConverterHandlerInterface { @@ -35,7 +33,7 @@ public function __construct(string $recordElement = self::DEFAULT_RECORD_ELEMENT $this->recordElement = $recordElement; } - $this->data = new SimpleXMLElement(''); + $this->data = new \SimpleXMLElement(''); } public function getExtension(): string @@ -43,7 +41,7 @@ public function getExtension(): string return self::FILE_EXTENSION; } - protected function toXml(array $data, SimpleXMLElement $xmlData): void + protected function toXml(array $data, \SimpleXMLElement $xmlData): void { foreach ($data as $key => $value) { if (is_numeric($key)) { @@ -67,7 +65,7 @@ public function convert(array $data): ConverterHandlerInterface public function write(string $filename): bool { - $dom = new DOMDocument('1.0'); + $dom = new \DOMDocument('1.0'); $dom->preserveWhiteSpace = false; diff --git a/src/Helpers/FormatsMessages.php b/src/Helpers/FormatsMessages.php index b66b243..444845d 100755 --- a/src/Helpers/FormatsMessages.php +++ b/src/Helpers/FormatsMessages.php @@ -65,8 +65,6 @@ protected function ruleToLower(string $rule): ?string /** * Replace all error message place-holders with actual values. - * - * @param mixed $value */ protected function makeReplacements( string $message, @@ -74,7 +72,7 @@ protected function makeReplacements( $value, ValidationRuleInterface $rule, array $parameters, - int $lineNumber + int $lineNumber, ): string { $message = $this->replaceAttributePlaceholder($message, $attribute); @@ -97,7 +95,7 @@ protected function makeReplacements( protected function replaceParameterPlaceholder( string $message, array $allowedParameters, - array $parameters + array $parameters, ): string { return str_replace($allowedParameters, $parameters, $message); } @@ -112,8 +110,6 @@ protected function replaceAttributePlaceholder(string $message, string $attribut /** * Replace the :value placeholder in the given message. - * - * @param mixed $value */ protected function replaceValuePlaceholder(string $message, $value): string { @@ -122,8 +118,6 @@ protected function replaceValuePlaceholder(string $message, $value): string /** * Replace the :line placeholder in the given message. - * - * @return mixed */ protected function replaceErrorLinePlaceholder(string $message, int $lineNumber) { diff --git a/src/Rules/AsciiOnly.php b/src/Rules/AsciiOnly.php index 7f911e5..f34da76 100644 --- a/src/Rules/AsciiOnly.php +++ b/src/Rules/AsciiOnly.php @@ -10,8 +10,6 @@ class AsciiOnly implements ValidationRuleInterface { /** * Determine if the validation rule passes. - * - * @param mixed $value */ public function passes($value, array $parameters): bool { diff --git a/src/Rules/Between.php b/src/Rules/Between.php index daf5fff..e1a1ff2 100644 --- a/src/Rules/Between.php +++ b/src/Rules/Between.php @@ -16,8 +16,6 @@ public function allowedParameters(): array /** * Determine if the validation rule passes. - * - * @param mixed $value */ public function passes($value, array $parameters): bool { diff --git a/src/Rules/ClosureValidationRule.php b/src/Rules/ClosureValidationRule.php index 5da4c52..59164e9 100755 --- a/src/Rules/ClosureValidationRule.php +++ b/src/Rules/ClosureValidationRule.php @@ -39,8 +39,6 @@ public function __construct(\Closure $callback) /** * Determine if the validation rule passes. - * - * @param mixed $value */ public function passes($value, array $parameters): bool { diff --git a/src/Rules/Url.php b/src/Rules/Url.php index de1072f..4b51101 100644 --- a/src/Rules/Url.php +++ b/src/Rules/Url.php @@ -28,8 +28,6 @@ class Url implements ValidationRuleInterface /** * Determine if the validation rule passes. - * - * @param mixed $value */ public function passes($value, array $parameters): bool { diff --git a/src/Validator/ValidationRuleParser.php b/src/Validator/ValidationRuleParser.php index 4bdfae6..ff4698c 100755 --- a/src/Validator/ValidationRuleParser.php +++ b/src/Validator/ValidationRuleParser.php @@ -4,7 +4,6 @@ namespace Oshomo\CsvUtils\Validator; -use Closure; use Oshomo\CsvUtils\Contracts\ValidationRuleInterface; use Oshomo\CsvUtils\Contracts\ValidationRuleInterface as ValidationRule; use Oshomo\CsvUtils\Rules\ClosureValidationRule; @@ -18,7 +17,7 @@ class ValidationRuleParser */ public static function parse($rule): array { - if ($rule instanceof Closure) { + if ($rule instanceof \Closure) { return [new ClosureValidationRule($rule), []]; } diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index cc29ea5..db98c31 100755 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -362,14 +362,12 @@ protected function passesParameterCheck($rule, array $parameters): bool /** * Validate an attribute using a custom rule object. - * - * @param mixed $value */ protected function validateUsingCustomRule( string $attribute, $value, array $parameters, - ValidationRuleInterface $rule + ValidationRuleInterface $rule, ): void { if (!$rule->passes($value, $parameters)) { $this->addFailure($rule->message(), $attribute, $value, $rule, $parameters); @@ -378,15 +376,13 @@ protected function validateUsingCustomRule( /** * Add a failed rule and error message to the collection. - * - * @param mixed $value */ protected function addFailure( string $message, string $attribute, $value, ValidationRuleInterface $rule, - array $parameters = [] + array $parameters = [], ): void { $this->currentRowMessages[] = $this->makeReplacements( $message, @@ -400,8 +396,6 @@ protected function addFailure( /** * Get the value of a given attribute. - * - * @return mixed */ protected function getValue(string $attribute) { diff --git a/tests/src/UppercaseRule.php b/tests/src/UppercaseRule.php index 74ae0a9..aa02e76 100644 --- a/tests/src/UppercaseRule.php +++ b/tests/src/UppercaseRule.php @@ -6,9 +6,6 @@ class UppercaseRule implements ValidationRuleInterface { - /** - * @param mixed $value - */ public function passes($value, array $parameters): bool { return strtoupper($value) === $value; From b2df216f72857bfeb07903e2260085bd4cd99548 Mon Sep 17 00:00:00 2001 From: Oshomo Oforomeh Date: Sat, 15 Nov 2025 22:57:56 +0100 Subject: [PATCH 9/9] chore: updated php version to 8.1 --- composer.json | 6 +-- tests/src/CsvValidatorTest.php | 87 ++++++++++++++-------------------- 2 files changed, 39 insertions(+), 54 deletions(-) diff --git a/composer.json b/composer.json index 5f1046d..e8c89cc 100644 --- a/composer.json +++ b/composer.json @@ -12,15 +12,15 @@ ], "minimum-stability": "dev", "require": { - "php": ">7.1.3", + "php": ">=8.1", "ext-mbstring": "*", "ext-json": "*", "ext-simplexml": "*", "ext-dom": "*" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", - "friendsofphp/php-cs-fixer": "^2.19 || ^3.0" + "phpunit/phpunit": "^9.0", + "friendsofphp/php-cs-fixer": "^3.0" }, "autoload": { "psr-4": { diff --git a/tests/src/CsvValidatorTest.php b/tests/src/CsvValidatorTest.php index e5322d4..91bd7a1 100755 --- a/tests/src/CsvValidatorTest.php +++ b/tests/src/CsvValidatorTest.php @@ -67,24 +67,33 @@ public function testBetweenValidationRule() $file = $this->testAssets . '/between_test.csv'; $validator = new Validator($file, [ + 'name' => ['between:50,90'], 'stars' => ['between:4,10'], ]); $this->assertTrue($validator->fails()); + $result = $validator->errors(); + $data = $result['data'][0]; + $this->assertSame( $validator::ERROR_MESSAGE, - $validator->errors()['message'] + $result['message'] ); $this->assertArrayHasKey( 'errors', - $validator->errors()['data'][0] + $data + ); + + $this->assertContains( + 'The name value Well Health Hotels is not between 50 - 90 on line 2.', + $data['errors'] ); $this->assertContains( 'The stars value 3 is not between 4 - 10 on line 2.', - $validator->errors()['data'][0]['errors'] + $data['errors'] ); } @@ -128,6 +137,30 @@ public function testUrlValidationRule() ); } + public function testValidatorCsvOnEmptyRule() + { + $file = $this->testAssets . '/valid_test.csv'; + + $expectedArray = [ + 'message' => 'CSV is valid.', + 'data' => [ + [ + 'name' => 'Well Health Hotels', + 'address' => 'Inga N. P.O. Box 567', + 'stars' => '3', + 'contact' => 'Kasper Zen', + 'uri' => 'http://well.org', + ], + ], + ]; + + $validator = new Validator($file, [ + 'stars' => [''], + ]); + + $this->assertSame($expectedArray, $validator->validate()); + } + public function testValidatorWithCustomRuleObject() { $file = $this->testAssets . '/ascii_test.csv'; @@ -288,54 +321,6 @@ public function testValidatorXmlWriter() ); } - public function testValidatorCsvOnEmptyRule() - { - $file = $this->testAssets . '/valid_test.csv'; - - $expectedArray = [ - 'message' => 'CSV is valid.', - 'data' => [ - [ - 'name' => 'Well Health Hotels', - 'address' => 'Inga N. P.O. Box 567', - 'stars' => '3', - 'contact' => 'Kasper Zen', - 'uri' => 'http://well.org', - ], - ], - ]; - - $validator = new Validator($file, [ - 'stars' => [''], - ]); - - $this->assertSame($expectedArray, $validator->validate()); - } - - public function testValidatorCsvIsValid() - { - $file = $this->testAssets . '/valid_test.csv'; - - $validator = new Validator($file, [ - 'stars' => ['between:3,10'], - ]); - - $expectedArray = [ - 'message' => 'CSV is valid.', - 'data' => [ - [ - 'name' => 'Well Health Hotels', - 'address' => 'Inga N. P.O. Box 567', - 'stars' => '3', - 'contact' => 'Kasper Zen', - 'uri' => 'http://well.org', - ], - ], - ]; - - $this->assertSame($expectedArray, $validator->validate()); - } - public function testValidatorXmlWriterWithRecordElementParameter() { $file = $this->testAssets . '/valid_test.csv';