From 727e7ccbfa54e2e10fa0acfa10ee2f56a3e25157 Mon Sep 17 00:00:00 2001 From: Alexandre Gomes Gaigalas Date: Sat, 18 Feb 2023 13:38:47 -0300 Subject: [PATCH] Increase phpstan level from 7 to 8 - Fixed all phpstan errors and ignoreds. - False positives now have a "Why:" comment on phpstan config. --- .../Exceptions/NestedValidationException.php | 7 ++++++ .../Exceptions/RecursiveExceptionIterator.php | 2 ++ library/Factory.php | 3 +++ library/Helpers/CanValidateDateTime.php | 2 +- library/Rules/Bsn.php | 11 +++++++-- library/Rules/Date.php | 2 +- library/Rules/DateTime.php | 2 +- library/Rules/Decimal.php | 2 +- library/Rules/Ip.php | 2 +- library/Rules/KeyNested.php | 1 + library/Rules/KeySet.php | 2 +- library/Rules/PolishIdCard.php | 7 ++++++ library/Rules/Size.php | 23 +++++++++---------- library/Rules/StartsWith.php | 13 +++++++++-- library/Rules/SubdivisionCode.php | 2 +- library/Rules/Time.php | 2 +- phpstan.neon.dist | 12 +++++----- tests/unit/Rules/AttributeTest.php | 2 +- tests/unit/Rules/EachTest.php | 4 ++++ 19 files changed, 70 insertions(+), 31 deletions(-) diff --git a/library/Exceptions/NestedValidationException.php b/library/Exceptions/NestedValidationException.php index a6d18042..cc7df301 100644 --- a/library/Exceptions/NestedValidationException.php +++ b/library/Exceptions/NestedValidationException.php @@ -80,8 +80,12 @@ class NestedValidationException extends ValidationException implements IteratorA return $this; } + /** + * @return SplObjectStorage + */ public function getIterator(): SplObjectStorage { + /** @var SplObjectStorage */ $childrenExceptions = new SplObjectStorage(); $recursiveIteratorIterator = $this->getRecursiveIterator(); @@ -182,6 +186,9 @@ class NestedValidationException extends ValidationException implements IteratorA return implode(PHP_EOL, $messages); } + /** + * @return RecursiveIteratorIterator + */ private function getRecursiveIterator(): RecursiveIteratorIterator { return new RecursiveIteratorIterator( diff --git a/library/Exceptions/RecursiveExceptionIterator.php b/library/Exceptions/RecursiveExceptionIterator.php index 53f13545..1fd41a48 100644 --- a/library/Exceptions/RecursiveExceptionIterator.php +++ b/library/Exceptions/RecursiveExceptionIterator.php @@ -16,6 +16,8 @@ use UnexpectedValueException; /** * @author Henrique Moody + * + * @implements RecursiveIterator */ final class RecursiveExceptionIterator implements RecursiveIterator, Countable { diff --git a/library/Factory.php b/library/Factory.php index 374fa261..1799eb60 100644 --- a/library/Factory.php +++ b/library/Factory.php @@ -192,6 +192,8 @@ final class Factory * * @throws InvalidClassException * @throws ReflectionException + * + * @return ReflectionClass */ private function createReflectionClass(string $name, string $parentName): ReflectionClass { @@ -237,6 +239,7 @@ final class Factory } /** + * @param ReflectionObject|ReflectionClass $reflection * @return mixed[] */ private function extractPropertiesValues(Validatable $validatable, ReflectionClass $reflection): array diff --git a/library/Helpers/CanValidateDateTime.php b/library/Helpers/CanValidateDateTime.php index 6b1e9950..d2ec4b84 100644 --- a/library/Helpers/CanValidateDateTime.php +++ b/library/Helpers/CanValidateDateTime.php @@ -65,6 +65,6 @@ trait CanValidateDateTime return checkdate((int) $info['month'], $info['day'], (int) $info['year']); } - return checkdate($info['month'] ?: 1, $info['day'] ?: 1, $info['year'] ?: 1); + return checkdate($info['month'] ?: 1, 1, $info['year'] ?: 1); } } diff --git a/library/Rules/Bsn.php b/library/Rules/Bsn.php index c1976084..a5cb5125 100644 --- a/library/Rules/Bsn.php +++ b/library/Rules/Bsn.php @@ -11,6 +11,7 @@ namespace Respect\Validation\Rules; use function ctype_digit; use function intval; +use function is_scalar; use function mb_strlen; use function strval; @@ -30,6 +31,12 @@ final class Bsn extends AbstractRule */ public function validate($input): bool { + if (!is_scalar($input)) { + return false; + } + + $input = (string) $input; + if (!ctype_digit($input)) { return false; } @@ -38,9 +45,9 @@ final class Bsn extends AbstractRule return false; } - $sum = -1 * intval($input[8]); /** @phpstan-ignore-line */ + $sum = -1 * intval($input[8]); for ($i = 9; $i > 1; --$i) { - $sum += $i * intval($input[9 - $i]); /** @phpstan-ignore-line */ + $sum += $i * intval($input[9 - $i]); } return $sum !== 0 && $sum % 11 === 0; diff --git a/library/Rules/Date.php b/library/Rules/Date.php index b4cce0b5..d39a7581 100644 --- a/library/Rules/Date.php +++ b/library/Rules/Date.php @@ -36,7 +36,7 @@ final class Date extends AbstractRule /** * @var string */ - private $sample; /** @phpstan-ignore-line */ + private $sample; /** * Initializes the rule. diff --git a/library/Rules/DateTime.php b/library/Rules/DateTime.php index 4282e545..cc1e6d2c 100644 --- a/library/Rules/DateTime.php +++ b/library/Rules/DateTime.php @@ -33,7 +33,7 @@ final class DateTime extends AbstractRule /** * @var string */ - private $sample; /** @phpstan-ignore-line */ + private $sample; /** * Initializes the rule. diff --git a/library/Rules/Decimal.php b/library/Rules/Decimal.php index 714addae..49161ea4 100644 --- a/library/Rules/Decimal.php +++ b/library/Rules/Decimal.php @@ -66,6 +66,6 @@ final class Decimal extends AbstractRule return $formatted; } - return preg_replace('/^(\d+\.\d)0*$/', '$1', $formatted); + return preg_replace('/^(\d+\.\d)0*$/', '$1', $formatted) ?: ''; } } diff --git a/library/Rules/Ip.php b/library/Rules/Ip.php index c78a658d..a7255333 100644 --- a/library/Rules/Ip.php +++ b/library/Rules/Ip.php @@ -41,7 +41,7 @@ final class Ip extends AbstractRule /** * @var string|null */ - private $range; /** @phpstan-ignore-line */ + private $range; /** * @var int|null diff --git a/library/Rules/KeyNested.php b/library/Rules/KeyNested.php index 6dc94044..582e94d8 100644 --- a/library/Rules/KeyNested.php +++ b/library/Rules/KeyNested.php @@ -89,6 +89,7 @@ final class KeyNested extends AbstractRelated } /** + * @param ArrayAccess $array * @param mixed $key * * @return mixed diff --git a/library/Rules/KeySet.php b/library/Rules/KeySet.php index d7aa55e0..ca9bf650 100644 --- a/library/Rules/KeySet.php +++ b/library/Rules/KeySet.php @@ -29,7 +29,7 @@ final class KeySet extends AbstractWrapper /** * @var mixed[] */ - private $keys; /** @phpstan-ignore-line */ + private $keys; /** * @var Key[] diff --git a/library/Rules/PolishIdCard.php b/library/Rules/PolishIdCard.php index 078561b0..f8d103db 100644 --- a/library/Rules/PolishIdCard.php +++ b/library/Rules/PolishIdCard.php @@ -9,6 +9,7 @@ declare(strict_types=1); namespace Respect\Validation\Rules; +use function is_scalar; use function ord; use function preg_match; @@ -31,6 +32,12 @@ final class PolishIdCard extends AbstractRule */ public function validate($input): bool { + if (!is_scalar($input)) { + return false; + } + + $input = (string) $input; + if (!preg_match('/^[A-Z0-9]{9}$/', $input)) { return false; } diff --git a/library/Rules/Size.php b/library/Rules/Size.php index 82182a6d..d7e1d472 100644 --- a/library/Rules/Size.php +++ b/library/Rules/Size.php @@ -33,7 +33,7 @@ final class Size extends AbstractRule /** * @var string|int|null */ - private $minSize; /** @phpstan-ignore-line */ + private $minSize; /** * @var float|null @@ -43,7 +43,7 @@ final class Size extends AbstractRule /** * @var string|int|null */ - private $maxSize; /** @phpstan-ignore-line */ + private $maxSize; /** * @var float|null @@ -57,9 +57,9 @@ final class Size extends AbstractRule public function __construct($minSize = null, $maxSize = null) { $this->minSize = $minSize; - $this->minValue = $minSize ? $this->toBytes($minSize) : null; + $this->minValue = $minSize ? $this->toBytes((string) $minSize) : null; $this->maxSize = $maxSize; - $this->maxValue = $maxSize ? $this->toBytes($maxSize) : null; + $this->maxValue = $maxSize ? $this->toBytes((string) $maxSize) : null; } /** @@ -68,19 +68,19 @@ final class Size extends AbstractRule public function validate($input): bool { if ($input instanceof SplFileInfo) { - return $this->isValidSize($input->getSize()); + return $this->isValidSize((float) $input->getSize()); } if ($input instanceof UploadedFileInterface) { - return $this->isValidSize($input->getSize()); + return $this->isValidSize((float) $input->getSize()); } if ($input instanceof StreamInterface) { - return $this->isValidSize($input->getSize()); + return $this->isValidSize((float) $input->getSize()); } if (is_string($input)) { - return $this->isValidSize((int) filesize($input)); + return $this->isValidSize((float) filesize($input)); } return false; @@ -89,14 +89,13 @@ final class Size extends AbstractRule /** * @todo Move it to a trait * - * @param mixed $size */ - private function toBytes($size): float + private function toBytes(string $size): float { $value = $size; $units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb']; foreach ($units as $exponent => $unit) { - if (!preg_match('/^(\d+(.\d+)?)' . $unit . '$/i', (string) $size, $matches)) { + if (!preg_match('/^(\d+(.\d+)?)' . $unit . '$/i', $size, $matches)) { continue; } $value = floatval($matches[1]) * 1024 ** $exponent; @@ -104,7 +103,7 @@ final class Size extends AbstractRule } if (!is_numeric($value)) { - throw new ComponentException(sprintf('"%s" is not a recognized file size.', (string) $size)); + throw new ComponentException(sprintf('"%s" is not a recognized file size.', $size)); } return (float) $value; diff --git a/library/Rules/StartsWith.php b/library/Rules/StartsWith.php index 2e412436..dc5e0a32 100644 --- a/library/Rules/StartsWith.php +++ b/library/Rules/StartsWith.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace Respect\Validation\Rules; use function is_array; +use function is_string; use function mb_stripos; use function mb_strpos; use function reset; @@ -63,7 +64,11 @@ final class StartsWith extends AbstractRule return reset($input) == $this->startValue; } - return mb_stripos($input, $this->startValue) === 0; + if (is_string($input) && is_string($this->startValue)) { + return mb_stripos($input, $this->startValue) === 0; + } + + return false; } /** @@ -75,6 +80,10 @@ final class StartsWith extends AbstractRule return reset($input) === $this->startValue; } - return mb_strpos($input, $this->startValue) === 0; + if (is_string($input) && is_string($this->startValue)) { + return mb_strpos($input, $this->startValue) === 0; + } + + return false; } } diff --git a/library/Rules/SubdivisionCode.php b/library/Rules/SubdivisionCode.php index 51855284..dde6386c 100644 --- a/library/Rules/SubdivisionCode.php +++ b/library/Rules/SubdivisionCode.php @@ -27,7 +27,7 @@ final class SubdivisionCode extends AbstractSearcher /** * @var string */ - private $countryName; /** @phpstan-ignore-line */ + private $countryName; /** * @var string[] diff --git a/library/Rules/Time.php b/library/Rules/Time.php index 16328f59..dc9f646c 100644 --- a/library/Rules/Time.php +++ b/library/Rules/Time.php @@ -35,7 +35,7 @@ final class Time extends AbstractRule /** * @var string */ - private $sample; /** @phpstan-ignore-line */ + private $sample; /** * Initializes the rule. diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 35158de2..106a482a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,30 +2,30 @@ includes: - vendor/phpstan/phpstan-deprecation-rules/rules.neon - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon - parameters: fileExtensions: - php - phpt - checkGenericClassInNonGenericObjectType: false - checkMissingIterableValueType: false ignoreErrors: - - message: '/Ternary operator condition is always false\./' - path: library/Helpers/CanValidateDateTime.php + # Why: Properties are read dynamically during message construction + message: '/Property Respect\\Validation\\Rules\\[a-zA-Z0-9\\_]+::\$[a-zA-Z0-9\\_]+ is never read, only written\./' - + # Why: SimpleXMLElement is weird and doesn't implement anything ArrayAccess-like message: '/Instanceof between mixed and SimpleXMLElement will always evaluate to false\./' path: library/Rules/ArrayVal.php - + # Why: This error is intentional, so PHPunit can test an invalid __callStatic call message: '/Call to an undefined static method Respect\\Validation\\Validator::iDoNotExistSoIShouldThrowException/' path: tests/unit/ValidatorTest.php - + # Why: StaticValidator is a stub interface that types __callStatic message: '/Call to static method PHPUnit\\Framework\\Assert::assertSame\(\) with Respect\\Validation\\Validator and Respect\\Validation\\ChainedValidator will always evaluate to false./' path: tests/unit/ValidatorTest.php - level: 7 + level: 8 paths: - library/ - tests/ diff --git a/tests/unit/Rules/AttributeTest.php b/tests/unit/Rules/AttributeTest.php index d4d599c2..8d4c4dee 100644 --- a/tests/unit/Rules/AttributeTest.php +++ b/tests/unit/Rules/AttributeTest.php @@ -31,7 +31,7 @@ final class AttributeTest extends RuleTestCase /** * @var string */ - private $bar = self::PROPERTY_VALUE; /** @phpstan-ignore-line */ + private $bar = self::PROPERTY_VALUE; /** * {@inheritDoc} diff --git a/tests/unit/Rules/EachTest.php b/tests/unit/Rules/EachTest.php index ccfd7f11..8fa0609c 100644 --- a/tests/unit/Rules/EachTest.php +++ b/tests/unit/Rules/EachTest.php @@ -93,8 +93,12 @@ final class EachTest extends RuleTestCase $rule->check(range(1, 3)); } + /** + * @return Traversable + */ private function createTraversableInput(int $firstValue, int $lastValue): Traversable { + /** @var SplStack */ $input = new SplStack(); foreach (range($firstValue, $lastValue) as $value) { $input->push($value);