diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b641120 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI Tests + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + operating-system: [ ubuntu-latest ] + php: [ '7.4', '8.0' ] + + name: PHP ${{ matrix.php }} + + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: none + ini-values: expose_php=1 + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Run spec tests + run: composer tests-spec + + - name: Run tests suite + run: composer tests + + - name: Run phpstan + run: composer analyze + + - name: Run codestyle checker + run: composer cs-check + + - uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- diff --git a/.gitignore b/.gitignore index 0a60947..9a8c46e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .idea/ vendor composer.lock +.phpunit.result.cache +/data/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1727505..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -dist: trusty -language: php - -matrix: - include: - - php: 5.6 - - php: hhvm - - php: 7.0 - - php: 7.1 - - php: nightly - allow_failures: - - php: nightly - fast_finish: true - -before_install: - -install: - - composer install - -script: - - vendor/bin/phpspec run --no-interaction - - vendor/bin/phpunit tests diff --git a/README.md b/README.md index 4bcb02c..14bee5e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ PHP Structure Check =================== -[![Build Status](https://travis-ci.org/1blankz7/php-structure-check.svg?branch=master)](https://travis-ci.org/1blankz7/php-structure-check) -[![Latest Stable Version](https://poser.pugx.org/1blankz7/php-structure-check/v/stable)](https://packagist.org/packages/1blankz7/php-structure-check) -[![Total Downloads](https://poser.pugx.org/1blankz7/php-structure-check/downloads)](https://packagist.org/packages/1blankz7/php-structure-check) -[![License](https://poser.pugx.org/1blankz7/php-structure-check/license)](https://packagist.org/packages/1blankz7/php-structure-check) +[![Build Status](https://travis-ci.org/CubiclDev/php-structure-check.svg?branch=master)](https://travis-ci.org/CubiclDev/php-structure-check) +[![License](https://poser.pugx.org/cubicl/php-structure-check/license)](https://packagist.org/packages/cubicl/php-structure-check) This library can check a complex array structure against a given requirement. The purpose of this library is to create a better experience when testing a result set from an api or something similar. @@ -12,7 +10,7 @@ The purpose of this library is to create a better experience when testing a resu ## Installation ``` -composer require 1blankz7/php-structure-check +composer require cubicl/php-structure-check ``` ## Usage @@ -84,6 +82,7 @@ Currently the following types are supported: * Datetime * Regex * Optional + * Enum There are some open issues with ideas for more types. Feel free to send pull requests. diff --git a/composer.json b/composer.json index 22fe000..edac254 100644 --- a/composer.json +++ b/composer.json @@ -1,29 +1,54 @@ { - "name": "1blankz7/php-structure-check", - "description": "Structural check of arrays for PHP 5.6+", - "keywords": ["array", "structure", "types"], - "homepage": "https://github.com/1blankz7/php-structure-check", - "type": "library", - "license": "MIT", - "authors": [ - { - "name": "Christian Blank", - "email": "mail@cblank.de", - "homepage": "http://cblank.de" - } + "name": "cubicl/php-structure-check", + "description": "Structural check of arrays for PHP 7.4+", + "keywords": [ + "array", + "structure", + "types" + ], + "homepage": "https://github.com/cubicldev/php-structure-check", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Christian Blank", + "email": "christian@cubicl.de", + "homepage": "https://cubicl.de" + } + ], + "scripts": { + "check": [ + "@analyze", + "@tests", + "@tests-spec", + "@cs-check" ], - "require-dev": { - "phpspec/phpspec": "^3.2", - "phpunit/phpunit": "^5.6" - }, - "autoload": { - "psr-4": { - "StructureCheck\\": [ - "src" - ], - "StructureCheck\\Test\\": [ - "tests" - ] - } + "tests": "phpunit tests", + "analyze": "phpstan analyse --level max", + "tests-spec": "phpspec run --no-interaction", + "cs-check": "phpcs --parallel=50", + "cs-fix": "phpcbf" + }, + "require-dev": { + "phpspec/phpspec": "^6.2", + "phpunit/phpunit": "^9.4", + "phpstan/phpstan": "^0.12.51", + "phpstan/phpstan-deprecation-rules": "^0.12.4", + "phpstan/phpstan-phpunit": "^0.12.16", + "squizlabs/php_codesniffer": "^3.5.5" + }, + "autoload": { + "psr-4": { + "Cubicl\\StructureCheck\\": [ + "src" + ], + "Cubicl\\StructureCheck\\Test\\": [ + "tests" + ] } + }, + "require": { + "ext-json": "*", + "php": "^7.4|^8.0" + } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..1c5e692 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + src + tests + \ No newline at end of file diff --git a/phpspec.yml b/phpspec.yml index 2a4150f..42b140e 100644 --- a/phpspec.yml +++ b/phpspec.yml @@ -1,4 +1,4 @@ suites: structure_check_suite: - namespace: StructureCheck - psr4_prefix: StructureCheck \ No newline at end of file + namespace: Cubicl\StructureCheck + psr4_prefix: Cubicl\StructureCheck \ No newline at end of file diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..da420ab --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,9 @@ +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon +parameters: + tmpDir: data + level: max + paths: + - src + - tests \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..a2d1acc --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,11 @@ + + + + + ./tests/ + + + \ No newline at end of file diff --git a/spec/Check/CountCheckSpec.php b/spec/Check/CountCheckSpec.php index e1c08c3..6a53485 100644 --- a/spec/Check/CountCheckSpec.php +++ b/spec/Check/CountCheckSpec.php @@ -1,12 +1,14 @@ isValid()->willReturn(false); - $child->check(Argument::any())->willReturn($result); + $child->check('', Argument::any())->willReturn($result); $this->beConstructedWith($child, 1); - $this->check([])->shouldHaveType(ResultInterface::class); + $this->check('', [])->shouldHaveType(ResultInterface::class); } function it_returns_a_result_on_check(TypeInterface $child, ResultInterface $result) { $result->isValid()->willReturn(true); - $child->check(Argument::any())->willReturn($result); + $child->check('', Argument::any())->willReturn($result); $this->beConstructedWith($child, 1); - $this->check([3])->shouldHaveType(ResultInterface::class); + $this->check('', [3])->shouldHaveType(ResultInterface::class); } } diff --git a/spec/Check/NumericRangeCheckSpec.php b/spec/Check/NumericRangeCheckSpec.php index b0fe05c..ae71910 100644 --- a/spec/Check/NumericRangeCheckSpec.php +++ b/spec/Check/NumericRangeCheckSpec.php @@ -1,12 +1,14 @@ isValid()->willReturn(false); - $child->check(Argument::any())->willReturn($result); + $child->check('', Argument::any())->willReturn($result); $this->beConstructedWith($child, 0, 1); - $this->check(Argument::any())->shouldHaveType(ResultInterface::class); + $this->check('', Argument::any())->shouldHaveType(ResultInterface::class); } function it_returns_a_result_on_check(TypeInterface $child, ResultInterface $result) { $result->isValid()->willReturn(true); - $child->check(Argument::any())->willReturn($result); + $child->check('', Argument::any())->willReturn($result); $this->beConstructedWith($child, 0, 1); - $this->check(0)->shouldHaveType(ResultInterface::class); + $this->check('', 0)->shouldHaveType(ResultInterface::class); } } diff --git a/spec/CheckerSpec.php b/spec/CheckerSpec.php index b351b52..ad2a345 100644 --- a/spec/CheckerSpec.php +++ b/spec/CheckerSpec.php @@ -1,27 +1,30 @@ shouldHaveType(Checker::class); } - function it_accepts_a_type_and_an_array_as_parameter_for_fulfills(TypeInterface $type) + function it_accepts_a_type_and_an_array_as_parameter_for_fulfills(TypeInterface $type, ResultInterface $result) { + $type->check('', [])->willReturn($result); $this->fulfills([], $type); } function it_returns_the_result_of_the_type_in_fulfills(TypeInterface $type, ResultInterface $result) { - $type->check([])->willReturn($result); + $type->check('', [])->willReturn($result); $this->fulfills([], $type)->shouldBe($result); } } diff --git a/spec/ResultSpec.php b/spec/ResultSpec.php index b3149e7..2a5c2bb 100644 --- a/spec/ResultSpec.php +++ b/spec/ResultSpec.php @@ -1,9 +1,11 @@ beConstructedWith(true); + $this->beConstructedWith(true, []); $this->getErrors()->shouldHaveCount(0); } } diff --git a/spec/Type/AnyTypeSpec.php b/spec/Type/AnyTypeSpec.php index 26b6cf9..43b428f 100644 --- a/spec/Type/AnyTypeSpec.php +++ b/spec/Type/AnyTypeSpec.php @@ -1,8 +1,10 @@ check(null)->isValid()->shouldBe(true); + $this->check('', null)->isValid()->shouldBe(true); } function it_should_return_empty_errors_for_null() { - $this->check(null)->getErrors()->shouldHaveCount(0); + $this->check('', null)->getErrors()->shouldHaveCount(0); } function it_should_return_valid_for_all_values() { - $this->check(true)->isValid()->shouldBe(true); - $this->check("foo")->isValid()->shouldBe(true); - $this->check(13)->isValid()->shouldBe(true); + $this->check('', true)->isValid()->shouldBe(true); + $this->check('', "foo")->isValid()->shouldBe(true); + $this->check('', 13)->isValid()->shouldBe(true); } function it_should_return_empty_errors_for_all_values() { - $this->check(true)->getErrors()->shouldHaveCount(0); - $this->check("foo")->getErrors()->shouldHaveCount(0); - $this->check(13)->getErrors()->shouldHaveCount(0); + $this->check('', true)->getErrors()->shouldHaveCount(0); + $this->check('', "foo")->getErrors()->shouldHaveCount(0); + $this->check('', 13)->getErrors()->shouldHaveCount(0); } } diff --git a/spec/Type/BoolTypeSpec.php b/spec/Type/BoolTypeSpec.php index aac647f..aae328c 100644 --- a/spec/Type/BoolTypeSpec.php +++ b/spec/Type/BoolTypeSpec.php @@ -1,9 +1,11 @@ check(true)->isValid()->shouldBe(true); - $this->check(false)->isValid()->shouldBe(true); + $this->check('', true)->isValid()->shouldBe(true); + $this->check('', false)->isValid()->shouldBe(true); } function it_should_return_invalid_for_others() { - $this->check(null)->isValid()->shouldBe(false); - $this->check("foo")->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(1)->isValid()->shouldBe(false); - $this->check(1.0)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', "foo")->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', 1)->isValid()->shouldBe(false); + $this->check('', 1.0)->isValid()->shouldBe(false); } } diff --git a/spec/Type/DatetimeTypeSpec.php b/spec/Type/DatetimeTypeSpec.php index 27ed724..3008718 100644 --- a/spec/Type/DatetimeTypeSpec.php +++ b/spec/Type/DatetimeTypeSpec.php @@ -1,35 +1,37 @@ beConstructedWith('d-m-Y h:m:s', 'UTC'); $this->shouldHaveType(DatetimeType::class); } - function it_should_return_valid_for_correct_values() + public function it_should_return_valid_for_correct_values(): void { $this->beConstructedWith('d-m-Y h:m:s', 'Europe/Berlin'); - $this->check('12-12-2012 12:12:10')->isValid()->shouldBe(true); + $this->check('', '12-12-2012 12:12:10')->isValid()->shouldBe(true); } - function it_should_return_invalid_for_others() + public function it_should_return_invalid_for_others(): void { $this->beConstructedWith('d-m-Y h:m:s', 'Europe/Berlin'); - $this->check(null)->isValid()->shouldBe(false); - $this->check('foo')->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(1.234)->isValid()->shouldBe(false); - $this->check(true)->isValid()->shouldBe(false); - $this->check(false)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', 'foo')->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', 1.234)->isValid()->shouldBe(false); + $this->check('', true)->isValid()->shouldBe(false); + $this->check('', false)->isValid()->shouldBe(false); } } diff --git a/spec/Type/EnumTypeSpec.php b/spec/Type/EnumTypeSpec.php new file mode 100644 index 0000000..453c4e1 --- /dev/null +++ b/spec/Type/EnumTypeSpec.php @@ -0,0 +1,37 @@ +beConstructedWith(['test', 1, null]); + + $this->shouldHaveType(EnumType::class); + } + + function it_is_valid_for_all_allowed_values() + { + $this->beConstructedWith(['test', 1, null]); + + $this->check('', 'test')->isValid()->shouldBe(true); + $this->check('', 1)->isValid()->shouldBe(true); + $this->check('', null)->isValid()->shouldBe(true); + } + + function it_is_invalid_for_not_allowed_values() + { + $this->beConstructedWith(['test', 1, null]); + + $this->check('', 'array')->isValid()->shouldBe(false); + $this->check('', 100)->isValid()->shouldBe(false); + $this->check('', 1.5)->isValid()->shouldBe(false); + $this->check('', ['test'])->isValid()->shouldBe(false); + } +} diff --git a/spec/Type/ExactValueTypeSpec.php b/spec/Type/ExactValueTypeSpec.php index 38ff88b..c2faf8b 100644 --- a/spec/Type/ExactValueTypeSpec.php +++ b/spec/Type/ExactValueTypeSpec.php @@ -1,8 +1,10 @@ beConstructedWith(null); - $this->check(null)->isValid()->shouldBe(true); + $this->check('', null)->isValid()->shouldBe(true); } } diff --git a/spec/Type/FloatTypeSpec.php b/spec/Type/FloatTypeSpec.php index 04e1dd3..698abf6 100644 --- a/spec/Type/FloatTypeSpec.php +++ b/spec/Type/FloatTypeSpec.php @@ -1,8 +1,10 @@ check(0.0)->isValid()->shouldBe(true); - $this->check(1.1)->isValid()->shouldBe(true); - $this->check(2.0)->isValid()->shouldBe(true); - $this->check(-144.2)->isValid()->shouldBe(true); + $this->check('', 0.0)->isValid()->shouldBe(true); + $this->check('', 1.1)->isValid()->shouldBe(true); + $this->check('', 2.0)->isValid()->shouldBe(true); + $this->check('', -144.2)->isValid()->shouldBe(true); } function it_should_return_invalid_for_others() { - $this->check(null)->isValid()->shouldBe(false); - $this->check("foo")->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(1)->isValid()->shouldBe(false); - $this->check(true)->isValid()->shouldBe(false); - $this->check(false)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', "foo")->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', 1)->isValid()->shouldBe(false); + $this->check('', true)->isValid()->shouldBe(false); + $this->check('', false)->isValid()->shouldBe(false); } } diff --git a/spec/Type/IntTypeSpec.php b/spec/Type/IntTypeSpec.php index df75166..93bc2b7 100644 --- a/spec/Type/IntTypeSpec.php +++ b/spec/Type/IntTypeSpec.php @@ -1,8 +1,10 @@ check(0)->isValid()->shouldBe(true); - $this->check(1)->isValid()->shouldBe(true); - $this->check(20)->isValid()->shouldBe(true); - $this->check(-144)->isValid()->shouldBe(true); + $this->check('', 0)->isValid()->shouldBe(true); + $this->check('', 1)->isValid()->shouldBe(true); + $this->check('', 20)->isValid()->shouldBe(true); + $this->check('', -144)->isValid()->shouldBe(true); } function it_should_return_invalid_for_others() { - $this->check(null)->isValid()->shouldBe(false); - $this->check("foo")->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(1.234)->isValid()->shouldBe(false); - $this->check(true)->isValid()->shouldBe(false); - $this->check(false)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', "foo")->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', 1.234)->isValid()->shouldBe(false); + $this->check('', true)->isValid()->shouldBe(false); + $this->check('', false)->isValid()->shouldBe(false); } } diff --git a/spec/Type/ListTypeSpec.php b/spec/Type/ListTypeSpec.php index 7884f1d..8edad91 100644 --- a/spec/Type/ListTypeSpec.php +++ b/spec/Type/ListTypeSpec.php @@ -1,11 +1,13 @@ beConstructedWith($childType); - $this->check(null)->isValid()->shouldBe(true); + $this->check('', null)->isValid()->shouldBe(true); } function it_should_return_the_value_from_the_child(TypeInterface $childType) { $this->beConstructedWith($childType); - $childType->check(false)->willReturn(new Result(false, [])); - $this->check(false)->isValid()->shouldBe(false); + $childType->check('', false)->willReturn(new Result(false, [])); + $this->check('', false)->isValid()->shouldBe(false); } } diff --git a/spec/Type/NumericTypeSpec.php b/spec/Type/NumericTypeSpec.php index 9e863a3..449cbc2 100644 --- a/spec/Type/NumericTypeSpec.php +++ b/spec/Type/NumericTypeSpec.php @@ -1,8 +1,10 @@ check(0)->isValid()->shouldBe(true); - $this->check(1)->isValid()->shouldBe(true); - $this->check(20)->isValid()->shouldBe(true); - $this->check(-144)->isValid()->shouldBe(true); + $this->check('', 0)->isValid()->shouldBe(true); + $this->check('', 1)->isValid()->shouldBe(true); + $this->check('', 20)->isValid()->shouldBe(true); + $this->check('', -144)->isValid()->shouldBe(true); } function it_should_return_valid_for_floats() { - $this->check(0.0)->isValid()->shouldBe(true); - $this->check(1.1235)->isValid()->shouldBe(true); - $this->check(-0.00001)->isValid()->shouldBe(true); - $this->check(-144.12313131313)->isValid()->shouldBe(true); + $this->check('', 0.0)->isValid()->shouldBe(true); + $this->check('', 1.1235)->isValid()->shouldBe(true); + $this->check('', -0.00001)->isValid()->shouldBe(true); + $this->check('', -144.12313131313)->isValid()->shouldBe(true); } function it_should_return_invalid_for_others() { - $this->check(null)->isValid()->shouldBe(false); - $this->check("foo")->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(true)->isValid()->shouldBe(false); - $this->check(false)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', "foo")->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', true)->isValid()->shouldBe(false); + $this->check('', false)->isValid()->shouldBe(false); } } diff --git a/spec/Type/ObjectTypeSpec.php b/spec/Type/ObjectTypeSpec.php index 3b94d01..3941dde 100644 --- a/spec/Type/ObjectTypeSpec.php +++ b/spec/Type/ObjectTypeSpec.php @@ -1,11 +1,13 @@ beConstructedWith($childType); $this->shouldHaveType(OptionalType::class); } - function it_should_return_the_value_from_the_child(TypeInterface $childType) { + function it_should_return_the_value_from_the_child(TypeInterface $childType): void + { $this->beConstructedWith($childType); - $childType->check(false)->willReturn(new Result(false, [])); - $this->check(false)->isValid()->shouldBe(false); + $childType->check('', false)->willReturn(new Result(false, [])); + $this->check('', false)->isValid()->shouldBe(false); } } diff --git a/spec/Type/RegexTypeSpec.php b/spec/Type/RegexTypeSpec.php index 5b89312..3f260a4 100644 --- a/spec/Type/RegexTypeSpec.php +++ b/spec/Type/RegexTypeSpec.php @@ -1,42 +1,44 @@ beConstructedWith('/^def/'); $this->shouldHaveType(RegexType::class); } - function it_should_return_valid_for_matching_strings() + function it_should_return_valid_for_matching_strings(): void { $this->beConstructedWith('/^def/'); - $this->check('definitive')->isValid()->shouldBe(true); + $this->check('', 'definitive')->isValid()->shouldBe(true); } - function it_should_return_invalid_for_not_matching_strings() + function it_should_return_invalid_for_not_matching_strings(): void { $this->beConstructedWith('/^def/'); - $this->check('developers')->isValid()->shouldBe(false); + $this->check('', 'developers')->isValid()->shouldBe(false); } - function it_should_return_invalid_for_others() + function it_should_return_invalid_for_others(): void { $this->beConstructedWith('/^def/'); - $this->check(null)->isValid()->shouldBe(false); - $this->check(12.3)->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(-1)->isValid()->shouldBe(false); - $this->check(true)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', 12.3)->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', -1)->isValid()->shouldBe(false); + $this->check('', true)->isValid()->shouldBe(false); } } diff --git a/spec/Type/StringTypeSpec.php b/spec/Type/StringTypeSpec.php index 789627b..9c1ca8c 100644 --- a/spec/Type/StringTypeSpec.php +++ b/spec/Type/StringTypeSpec.php @@ -1,31 +1,33 @@ shouldHaveType(StringType::class); } - function it_should_return_valid_for_strings() + function it_should_return_valid_for_strings(): void { - $this->check("")->isValid()->shouldBe(true); - $this->check("fooo")->isValid()->shouldBe(true); - $this->check('adadsad asd a')->isValid()->shouldBe(true); + $this->check('', '')->isValid()->shouldBe(true); + $this->check('', 'fooo')->isValid()->shouldBe(true); + $this->check('', 'adadsad asd a')->isValid()->shouldBe(true); } - function it_should_return_invalid_for_others() + function it_should_return_invalid_for_others(): void { - $this->check(null)->isValid()->shouldBe(false); - $this->check(12.3)->isValid()->shouldBe(false); - $this->check([])->isValid()->shouldBe(false); - $this->check(-1)->isValid()->shouldBe(false); - $this->check(true)->isValid()->shouldBe(false); + $this->check('', null)->isValid()->shouldBe(false); + $this->check('', 12.3)->isValid()->shouldBe(false); + $this->check('', [])->isValid()->shouldBe(false); + $this->check('', -1)->isValid()->shouldBe(false); + $this->check('', true)->isValid()->shouldBe(false); } } diff --git a/src/Check/CountCheck.php b/src/Check/CountCheck.php index c640dde..6b629d6 100644 --- a/src/Check/CountCheck.php +++ b/src/Check/CountCheck.php @@ -1,74 +1,51 @@ child = $child; $this->count = $count; } - /** - * @inheritdoc - */ - public function check($value) + public function check(string $key, $value): ResultInterface { - $result = $this->child->check($value); + $result = $this->child->check($key, $value); if (!$result->isValid()) { return $result; } if (!$value instanceof Countable) { - return new Result( - false, - [sprintf(self::$countableErrorMessage, json_encode($value))] - ); + return Result::invalid([ + new Error($key, sprintf(self::$countableErrorMessage, json_encode($value))) + ]); } if (count($value) !== $this->count) { - return new Result( - false, - [sprintf(self::$countErrorMessage, json_encode($value), $this->count)] - ); + return Result::invalid([ + new Error($key, sprintf(self::$countErrorMessage, json_encode($value), $this->count)) + ]); } - return new Result(true); + return Result::valid(); } } diff --git a/src/Check/NumericRangeCheck.php b/src/Check/NumericRangeCheck.php index b14c5c2..ef3dc38 100644 --- a/src/Check/NumericRangeCheck.php +++ b/src/Check/NumericRangeCheck.php @@ -1,14 +1,14 @@ child = $child; $this->upperBound = $upperBound; $this->lowerBound = $lowerBound; } - /** - * @inheritdoc - */ - public function check($value) + public function check(string $key, $value): ResultInterface { - $result = $this->child->check($value); + $result = $this->child->check($key, $value); if (!$result->isValid()) { - return $result; + return $result; } if ($this->lowerBound > $value) { - return new Result( - false, - [sprintf(self::$lowerBoundErrorMessage, $this->lowerBound, $value)] - ); + return Result::invalid([ + new Error($key, sprintf(self::$lowerBoundErrorMessage, $this->lowerBound, $value)) + ]); } if ($this->upperBound < $value) { - return new Result( - false, - [sprintf(self::$upperBoundErrorMessage, $this->upperBound, $value)] - ); + return Result::invalid([ + new Error($key, sprintf(self::$upperBoundErrorMessage, $this->lowerBound, $value)) + ]); } - return new Result(true); + return Result::valid(); } } diff --git a/src/Checker.php b/src/Checker.php index 88b3f3d..9f06034 100644 --- a/src/Checker.php +++ b/src/Checker.php @@ -1,22 +1,15 @@ check($element); + return $requirement->check('', $element); } - -} \ No newline at end of file +} diff --git a/src/CheckerInterface.php b/src/CheckerInterface.php index 57a0605..e6ecc55 100644 --- a/src/CheckerInterface.php +++ b/src/CheckerInterface.php @@ -1,21 +1,15 @@ key = $key; + $this->message = $message; + } + + public function getKey(): string + { + return $this->key; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/src/ErrorInterface.php b/src/ErrorInterface.php new file mode 100644 index 0000000..6efb18a --- /dev/null +++ b/src/ErrorInterface.php @@ -0,0 +1,12 @@ + */ - private $errors; + private array $errors; /** - * Result constructor. - * - * @param bool $valid - * @param array $errors + * @param array $errors */ - public function __construct($valid, array $errors = []) + public function __construct(bool $valid, array $errors) { $this->valid = $valid; $this->errors = $errors; } + public static function valid(): ResultInterface + { + return new self(true, []); + } + /** - * @inheritdoc + * @param array $errors */ - public function isValid() + public static function invalid(array $errors): ResultInterface + { + return new self(false, $errors); + } + + public function isValid(): bool { return $this->valid; } - /** - * @inheritdoc - */ - public function getErrors() + public function getErrors(): array { return $this->errors; } -} \ No newline at end of file +} diff --git a/src/ResultInterface.php b/src/ResultInterface.php index 8a4ee76..17eabde 100644 --- a/src/ResultInterface.php +++ b/src/ResultInterface.php @@ -1,24 +1,23 @@ */ - public function getErrors(); -} \ No newline at end of file + public function getErrors(): array; +} diff --git a/src/Type/AnyType.php b/src/Type/AnyType.php index 4e8b1b4..aecd21b 100644 --- a/src/Type/AnyType.php +++ b/src/Type/AnyType.php @@ -1,20 +1,16 @@ datetimeFormat = $format; $this->datetimeZone = $datetimeZone; } - /** - * @param mixed $value - * - * @return ResultInterface - */ - public function check($value) + public function check(string $key, $value): ResultInterface { $checkResult = is_string($value) && $this->isValidDatetime($value); - return new Result( - $checkResult, - !$checkResult ? [sprintf(self::$errorMessage, json_encode($value))] : [] - ); + return $checkResult + ? Result::valid() + : Result::invalid([new Error($key, sprintf(self::$errorMessage, json_encode($value)))]); } - /** - * @param string $value - * - * @return bool - */ - private function isValidDatetime($value) { + private function isValidDatetime(string $value): bool + { $date = DateTime::createFromFormat($this->datetimeFormat, $value, new DateTimeZone($this->datetimeZone)); - $errors = DateTime::getLastErrors()["warning_count"]; + $errors = DateTime::getLastErrors(); - return $date && $errors["warning_count"] == 0 && $errors["error_count"] == 0; + return $date && ( + !$errors || ($errors['warning_count'] === 0 && $errors['error_count'] === 0) + ); } } diff --git a/src/Type/EnumType.php b/src/Type/EnumType.php new file mode 100644 index 0000000..064e502 --- /dev/null +++ b/src/Type/EnumType.php @@ -0,0 +1,42 @@ + */ + private array $values; + + /** + * @param array $values + */ + public function __construct(array $values) + { + $this->values = $values; + } + + /** + * @param string $key + * @param T $value + */ + public function check(string $key, $value): ResultInterface + { + $checkResult = in_array($value, $this->values, true); + return $checkResult + ? Result::valid() + : Result::invalid([ + new Error($key, sprintf(self::$errorMessage, json_encode($value), implode(',', $this->values))) + ]); + } +} diff --git a/src/Type/ExactValueType.php b/src/Type/ExactValueType.php index ae72087..36d03cb 100644 --- a/src/Type/ExactValueType.php +++ b/src/Type/ExactValueType.php @@ -1,21 +1,21 @@ value = $value; } - /** - * @param mixed $value - * - * @return ResultInterface - */ - public function check($value) + public function check(string $key, $value): ResultInterface { $checkResult = $this->value === $value; - return new Result( - $checkResult, - !$checkResult ? [sprintf(self::$errorMessage, json_encode($value), $this->value)] : [] - ); + return $checkResult + ? Result::valid() + : Result::invalid([ + new Error($key, sprintf(self::$errorMessage, json_encode($value), json_encode($this->value))) + ]); } } diff --git a/src/Type/FloatType.php b/src/Type/FloatType.php index 70e74b4..80aec7a 100644 --- a/src/Type/FloatType.php +++ b/src/Type/FloatType.php @@ -1,23 +1,23 @@ child = $child; } - /** - * @inheritdoc - */ - public function check($value) + public function check(string $key, $value): ResultInterface { if (!is_array($value)) { - return new Result( - false, - [sprintf(self::$isNotAnArrayMessage, json_encode($value))] + return Result::invalid( + [new Error($key, sprintf(self::$isNotAnArrayMessage, json_encode($value)))] ); } $errors = []; $valid = true; - foreach ($value as $item) { - $result = $this->child->check($item); + foreach ($value as $idx => $item) { + $result = $this->child->check(sprintf('%s.%d', $key, $idx), $item); $valid = $valid && $result->isValid(); $errors += $result->getErrors(); } - return new Result($valid, $errors); + return $valid + ? Result::valid() + : Result::invalid($errors); } } diff --git a/src/Type/NullableType.php b/src/Type/NullableType.php index 8853ff9..f3eb64e 100644 --- a/src/Type/NullableType.php +++ b/src/Type/NullableType.php @@ -1,40 +1,27 @@ child = $child; } - /** - * @inheritdoc - */ - public function check($value) + public function check(string $key, $value): ResultInterface { - if(is_null($value)) { - return new Result(true); + if ($value === null) { + return Result::valid(); } - return $this->child->check($value); + return $this->child->check($key, $value); } -} \ No newline at end of file +} diff --git a/src/Type/NumericType.php b/src/Type/NumericType.php index 7cc1c56..96a24da 100644 --- a/src/Type/NumericType.php +++ b/src/Type/NumericType.php @@ -1,26 +1,23 @@ children = $children; } - /** - * @inheritdoc - */ - public function check($value) + public function check(string $key, $value): ResultInterface { $errors = []; $valid = true; - foreach ($this->children as $key => $child) { - if (!array_key_exists($key, $value)) { + foreach ($this->children as $objectProperty => $child) { + $fullKey = sprintf('%s.%s', $key, $objectProperty); + if (!array_key_exists($objectProperty, $value)) { if (!$child instanceof OptionalType) { $valid = false; - $errors[] = sprintf(self::$missingKeyErrorMessage, $key); + $errors[] = new Error($fullKey, sprintf(self::$missingKeyErrorMessage, $objectProperty)); } - continue; } - $result = $child->check($value[$key]); + $result = $child->check($fullKey, $value[$objectProperty]); $valid = $valid && $result->isValid(); $errors += $result->getErrors(); } diff --git a/src/Type/OptionalType.php b/src/Type/OptionalType.php index 9110a5a..91cb0b8 100644 --- a/src/Type/OptionalType.php +++ b/src/Type/OptionalType.php @@ -1,37 +1,22 @@ - */ class OptionalType implements TypeInterface { - /** - * @var TypeInterface - */ - private $child; + private TypeInterface $child; - /** - * OptionalType constructor. - * @param TypeInterface $child - */ public function __construct(TypeInterface $child) { $this->child = $child; } - /** - * @param mixed $value - * - * @return ResultInterface - */ - public function check($value) + public function check(string $key, $value): ResultInterface { - return $this->child->check($value); + return $this->child->check($key, $value); } -} \ No newline at end of file +} diff --git a/src/Type/RegexType.php b/src/Type/RegexType.php index fe033c8..7471246 100644 --- a/src/Type/RegexType.php +++ b/src/Type/RegexType.php @@ -1,48 +1,32 @@ regex = $regex; } - /** - * @param mixed $value - * - * @return ResultInterface - */ - public function check($value) + public function check(string $key, $value): ResultInterface { $checkResult = is_string($value) && preg_match($this->regex, $value) === 1; - return new Result( - $checkResult, - !$checkResult ? [sprintf(self::$errorMessage, json_encode($value), $this->regex)] : [] - ); + return $checkResult + ? Result::valid() + : Result::invalid([ + new Error($key, sprintf(self::$errorMessage, json_encode($value), json_encode($this->regex))) + ]); } } diff --git a/src/Type/StringType.php b/src/Type/StringType.php index 46af09d..7fcb4ca 100644 --- a/src/Type/StringType.php +++ b/src/Type/StringType.php @@ -1,30 +1,23 @@ */ class ObjectTypeTest extends TestCase { - /** - * @var CheckerInterface - */ - private $checker; + private CheckerInterface $checker; - /** - * - */ - protected function setUp() + protected function setUp(): void { parent::setUp(); $this->checker = new Checker(); @@ -33,14 +29,14 @@ protected function setUp() /** * @test */ - public function itShouldHandleAbsenceOfOptionalDeclaredType() + public function itShouldHandleAbsenceOfOptionalDeclaredType(): void { $structure = new ObjectType([ 'opt' => new OptionalType(new AnyType()) ]); - $actual = $structure->check([]); + $actual = $structure->check('', []); $this->assertSame(true, $actual->isValid()); } -} \ No newline at end of file +}