diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d96f1c1..7b9bf9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,41 +6,41 @@ on: - cron: '0 0 * * *' jobs: - php81: - name: PHP 8.1 - runs-on: ubuntu-22.04 + php82: + name: PHP 8.2 + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v4 - name: composer test - uses: docker://ghcr.io/chubbyphp/ci-php81:latest + uses: docker://ghcr.io/chubbyphp/ci-php82:latest env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} - php82: - name: PHP 8.2 - runs-on: ubuntu-22.04 + php83: + name: PHP 8.3 + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v4 - name: composer test - uses: docker://ghcr.io/chubbyphp/ci-php82:latest + uses: docker://ghcr.io/chubbyphp/ci-php83:latest env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} - php83: - name: PHP 8.3 - runs-on: ubuntu-22.04 + php84: + name: PHP 8.4 + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v4 - name: composer test - uses: docker://ghcr.io/chubbyphp/ci-php83:latest + uses: docker://ghcr.io/chubbyphp/ci-php84:latest env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} - name: sonarcloud.io - uses: sonarsource/sonarcloud-github-action@master + uses: sonarsource/sonarqube-scan-action@v4.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/README.md b/README.md index c0a55c5..86be86b 100644 --- a/README.md +++ b/README.md @@ -25,25 +25,25 @@ A simple deserialization. ## Requirements - * php: ^8.1 + * php: ^8.2 * chubbyphp/chubbyphp-decode-encode: ^1.1 * psr/http-message: ^1.1|^2.0 - * psr/log: ^2.0|^3.0 + * psr/log: ^2.0|^3.0.2 ## Suggest * chubbyphp/chubbyphp-container: ^2.2 * pimple/pimple: ^3.5 * psr/container: ^2.0.2 - * symfony/config: ^5.4.31|^6.3.8|^7.0 (symfony integration) - * symfony/dependency-injection: ^5.4.31|^6.3.8|^7.0 (symfony integration) + * symfony/config: ^5.4.46|^6.4.14|^7.2 (symfony integration) + * symfony/dependency-injection: ^5.4.46|^6.4.14|^7.2 (symfony integration) ## Installation Through [Composer](http://getcomposer.org) as [chubbyphp/chubbyphp-deserialization][1]. ```sh -composer require chubbyphp/chubbyphp-deserialization "^4.1" +composer require chubbyphp/chubbyphp-deserialization "^4.2" ``` ## Usage diff --git a/composer.json b/composer.json index 19517eb..b0cc229 100644 --- a/composer.json +++ b/composer.json @@ -10,30 +10,30 @@ } ], "require": { - "php": "^8.1", + "php": "^8.2", "ext-dom": "*", "ext-json": "*", "ext-mbstring": "*", "chubbyphp/chubbyphp-decode-encode": "^1.1", "psr/http-message": "^1.1|^2.0", - "psr/log": "^2.0|^3.0" + "psr/log": "^2.0|^3.0.2" }, "require-dev": { "chubbyphp/chubbyphp-container": "^2.2", "chubbyphp/chubbyphp-dev-helper": "dev-master", "chubbyphp/chubbyphp-laminas-config-factory": "^1.3", - "chubbyphp/chubbyphp-mock": "^1.7.0", - "doctrine/collections": "^2.1.4", - "doctrine/persistence": "^3.2", - "infection/infection": "^0.27.8", + "chubbyphp/chubbyphp-mock": "^1.8", + "doctrine/collections": "^2.2.2", + "doctrine/persistence": "^4.0", + "infection/infection": "^0.29.8", "php-coveralls/php-coveralls": "^2.7.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.10.45", - "phpunit/phpunit": "^10.4.2", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.0.3", + "phpunit/phpunit": "^11.5.0", "pimple/pimple": "^3.5", "psr/container": "^2.0.2", - "symfony/config": "^5.4.31|^6.3.8|^7.0", - "symfony/dependency-injection": "^5.4.31|^6.3.8|^7.0" + "symfony/config": "^5.4.46|^6.4.14|^7.2", + "symfony/dependency-injection": "^5.4.46|^6.4.14|^7.2" }, "autoload": { "psr-4": { "Chubbyphp\\Deserialization\\": "src/" } @@ -50,7 +50,7 @@ }, "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "scripts": { @@ -65,9 +65,9 @@ ], "test:cs": "mkdir -p build && PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run --stop-on-violation --cache-file=build/phpcs.cache", "test:infection": "vendor/bin/infection --threads=$(nproc) --min-msi=93 --verbose --coverage=build/phpunit", - "test:integration": "vendor/bin/phpunit --testsuite=Integration --cache-result-file=build/phpunit/result.cache", + "test:integration": "vendor/bin/phpunit --testsuite=Integration --cache-directory=build/phpunit", "test:lint": "mkdir -p build && find src tests -name '*.php' -print0 | xargs -0 -n1 -P$(nproc) php -l | tee build/phplint.log", "test:static-analysis": "mkdir -p build && bash -c 'vendor/bin/phpstan analyse src --no-progress --level=8 --error-format=junit | tee build/phpstan.junit.xml; if [ ${PIPESTATUS[0]} -ne \"0\" ]; then exit 1; fi'", - "test:unit": "vendor/bin/phpunit --testsuite=Unit --coverage-text --coverage-clover=build/phpunit/clover.xml --coverage-html=build/phpunit/coverage-html --coverage-xml=build/phpunit/coverage-xml --log-junit=build/phpunit/junit.xml --cache-result-file=build/phpunit/result.cache" + "test:unit": "vendor/bin/phpunit --testsuite=Unit --coverage-text --coverage-clover=build/phpunit/clover.xml --coverage-html=build/phpunit/coverage-html --coverage-xml=build/phpunit/coverage-xml --log-junit=build/phpunit/junit.xml --cache-directory=build/phpunit" } } diff --git a/phpstan.neon b/phpstan.neon index 25f35ec..5ce1fa1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,6 +6,15 @@ parameters: - message: '/supplied for foreach, only iterables are supported/' path: %currentWorkingDirectory%/src/Denormalizer/Relation/EmbedManyFieldDenormalizer.php + - + message: '/Call to function is_array\(\) with array will always evaluate to true./' + path: %currentWorkingDirectory%/src/Denormalizer/Relation/EmbedManyFieldDenormalizer.php - message: '/supplied for foreach, only iterables are supported/' path: %currentWorkingDirectory%/src/Denormalizer/Relation/ReferenceManyFieldDenormalizer.php + - + message: '/Call to function is_string\(\) with string will always evaluate to true./' + path: %currentWorkingDirectory%/src/Denormalizer/Relation/ReferenceManyFieldDenormalizer.php + - + message: '/Parameter .*relatedObjects.*/' + path: %currentWorkingDirectory%/src/Denormalizer/Relation/ReferenceManyFieldDenormalizer.php diff --git a/src/Accessor/PropertyAccessor.php b/src/Accessor/PropertyAccessor.php index 713ba3e..bbec7dd 100644 --- a/src/Accessor/PropertyAccessor.php +++ b/src/Accessor/PropertyAccessor.php @@ -55,6 +55,9 @@ public function getValue(object $object) return $getter($this->property); } + /** + * @return class-string + */ private function getClass(object $object): string { if (interface_exists('Doctrine\Persistence\Proxy') && $object instanceof Proxy) { diff --git a/src/Denormalizer/FieldDenormalizer.php b/src/Denormalizer/FieldDenormalizer.php index aaee070..268f49b 100644 --- a/src/Denormalizer/FieldDenormalizer.php +++ b/src/Denormalizer/FieldDenormalizer.php @@ -5,15 +5,11 @@ namespace Chubbyphp\Deserialization\Denormalizer; use Chubbyphp\Deserialization\Accessor\AccessorInterface; -use Chubbyphp\Deserialization\DeserializerRuntimeException; final class FieldDenormalizer implements FieldDenormalizerInterface { public function __construct(private AccessorInterface $accessor, private bool $emptyToNull = false) {} - /** - * @throws DeserializerRuntimeException - */ public function denormalizeField( string $path, object $object, diff --git a/src/DeserializerLogicException.php b/src/DeserializerLogicException.php index 9f384f8..de9b1fe 100644 --- a/src/DeserializerLogicException.php +++ b/src/DeserializerLogicException.php @@ -8,17 +8,17 @@ final class DeserializerLogicException extends \LogicException { public static function createMissingContentType(string $contentType): self { - return new self(sprintf('There is no decoder for content-type: "%s"', $contentType)); + return new self(\sprintf('There is no decoder for content-type: "%s"', $contentType)); } public static function createMissingDenormalizer(string $path): self { - return new self(sprintf('There is no denormalizer at path: "%s"', $path)); + return new self(\sprintf('There is no denormalizer at path: "%s"', $path)); } public static function createMissingMapping(string $class): self { - return new self(sprintf('There is no mapping for class: "%s"', $class)); + return new self(\sprintf('There is no mapping for class: "%s"', $class)); } /** @@ -27,22 +27,22 @@ public static function createMissingMapping(string $class): self public static function createMissingMethod(string $class, array $methods): self { return new self( - sprintf('There are no accessible method(s) "%s", within class: "%s"', implode('", "', $methods), $class) + \sprintf('There are no accessible method(s) "%s", within class: "%s"', implode('", "', $methods), $class) ); } public static function createMissingProperty(string $class, string $property): self { - return new self(sprintf('There is no property "%s" within class: "%s"', $property, $class)); + return new self(\sprintf('There is no property "%s" within class: "%s"', $property, $class)); } public static function createFactoryDoesNotReturnObject(string $path, string $dataType): self { - return new self(sprintf('Factory does not return object, "%s" given at path: "%s"', $dataType, $path)); + return new self(\sprintf('Factory does not return object, "%s" given at path: "%s"', $dataType, $path)); } public static function createConvertTypeDoesNotExists(string $convertType): self { - return new self(sprintf('Convert type "%s" is not supported', $convertType)); + return new self(\sprintf('Convert type "%s" is not supported', $convertType)); } } diff --git a/src/DeserializerRuntimeException.php b/src/DeserializerRuntimeException.php index daf4548..de11921 100644 --- a/src/DeserializerRuntimeException.php +++ b/src/DeserializerRuntimeException.php @@ -9,15 +9,15 @@ final class DeserializerRuntimeException extends \RuntimeException public static function createInvalidDataType(string $path, string $givenType, string $wishedType): self { return new self( - sprintf('There is an invalid data type "%s", needed "%s" at path: "%s"', $givenType, $wishedType, $path) + \sprintf('There is an invalid data type "%s", needed "%s" at path: "%s"', $givenType, $wishedType, $path) ); } public static function createNotParsable(string $contentType, ?string $error = null): self { - $message = sprintf('Data is not parsable with content-type: "%s"', $contentType); + $message = \sprintf('Data is not parsable with content-type: "%s"', $contentType); if (null !== $error) { - $message .= sprintf(', error: "%s"', $error); + $message .= \sprintf(', error: "%s"', $error); } return new self($message); @@ -28,7 +28,7 @@ public static function createNotParsable(string $contentType, ?string $error = n */ public static function createNotAllowedAdditionalFields(array $paths): self { - return new self(sprintf('There are additional field(s) at paths: "%s"', implode('", "', $paths))); + return new self(\sprintf('There are additional field(s) at paths: "%s"', implode('", "', $paths))); } /** @@ -36,7 +36,7 @@ public static function createNotAllowedAdditionalFields(array $paths): self */ public static function createMissingObjectType(string $path, array $supportedTypes): self { - return new self(sprintf( + return new self(\sprintf( 'Missing object type, supported are "%s" at path: "%s"', implode('", "', $supportedTypes), $path @@ -48,7 +48,7 @@ public static function createMissingObjectType(string $path, array $supportedTyp */ public static function createInvalidObjectType(string $path, string $type, array $supportedTypes): self { - return new self(sprintf( + return new self(\sprintf( 'Unsupported object type "%s", supported are "%s" at path: "%s"', $type, implode('", "', $supportedTypes), @@ -58,6 +58,6 @@ public static function createInvalidObjectType(string $path, string $type, array public static function createTypeIsNotAString(string $path, string $dataType): self { - return new self(sprintf('Type is not a string, "%s" given at path: "%s"', $dataType, $path)); + return new self(\sprintf('Type is not a string, "%s" given at path: "%s"', $dataType, $path)); } } diff --git a/tests/Integration/DeserializerTest.php b/tests/Integration/DeserializerTest.php index 51f28ef..5a48cad 100644 --- a/tests/Integration/DeserializerTest.php +++ b/tests/Integration/DeserializerTest.php @@ -499,7 +499,7 @@ public function testDenormalizeWithAllowedAdditionalFields(): void private function getLogger(): AbstractLogger { - return new class() extends AbstractLogger { + return new class extends AbstractLogger { private array $entries = []; public function log($level, $message, array $context = []): void diff --git a/tests/Unit/Accessor/MethodAccessorTest.php b/tests/Unit/Accessor/MethodAccessorTest.php index 511e321..be0066f 100644 --- a/tests/Unit/Accessor/MethodAccessorTest.php +++ b/tests/Unit/Accessor/MethodAccessorTest.php @@ -17,7 +17,7 @@ final class MethodAccessorTest extends TestCase { public function testSetValue(): void { - $object = new class() { + $object = new class { private ?string $name = null; public function getName(): string @@ -41,7 +41,7 @@ public function testMissingSet(): void { $this->expectException(DeserializerLogicException::class); - $object = new class() {}; + $object = new class {}; $accessor = new MethodAccessor('name'); $accessor->setValue($object, 'Name'); @@ -49,7 +49,7 @@ public function testMissingSet(): void public function testGetValue(): void { - $object = new class() { + $object = new class { private ?string $name = null; public function getName(): string @@ -72,7 +72,7 @@ public function setName(string $name): void public function testHasValue(): void { - $object = new class() { + $object = new class { private ?string $name = null; public function hasName(): bool @@ -95,7 +95,7 @@ public function setName(string $name): void public function testIsValue(): void { - $object = new class() { + $object = new class { private ?string $name = null; public function isName(): bool @@ -120,7 +120,7 @@ public function testMissingGet(): void { $this->expectException(DeserializerLogicException::class); - $object = new class() {}; + $object = new class {}; $accessor = new MethodAccessor('name'); $accessor->getValue($object); diff --git a/tests/Unit/Accessor/PropertyAccessorTest.php b/tests/Unit/Accessor/PropertyAccessorTest.php index 5901240..5f87f3b 100644 --- a/tests/Unit/Accessor/PropertyAccessorTest.php +++ b/tests/Unit/Accessor/PropertyAccessorTest.php @@ -19,7 +19,7 @@ final class PropertyAccessorTest extends TestCase { public function testSetValue(): void { - $object = new class() { + $object = new class { private string $name; public function getName(): string @@ -36,7 +36,7 @@ public function getName(): string public function testSetValueCanAccessPrivatePropertyThroughDoctrineProxyClass(): void { - $object = new class() extends AbstractManyModel implements Proxy { + $object = new class extends AbstractManyModel implements Proxy { private bool $initialized = false; public function __load(): void @@ -65,7 +65,7 @@ public function testMissingSet(): void { $this->expectException(DeserializerLogicException::class); - $object = new class() {}; + $object = new class {}; $accessor = new PropertyAccessor('name'); $accessor->setValue($object, 'Name'); @@ -73,7 +73,7 @@ public function testMissingSet(): void public function testGetValue(): void { - $object = new class() { + $object = new class { private string $name; public function setName(string $name): void @@ -91,7 +91,7 @@ public function setName(string $name): void public function testGetValueHandleUninitializedProperty(): void { - $object = new class() { + $object = new class { private string $name; public function getName(): string @@ -107,7 +107,7 @@ public function getName(): string public function testGetValueCanAccessPrivatePropertyThroughDoctrineProxyClass(): void { - $object = new class() extends AbstractManyModel implements Proxy { + $object = new class extends AbstractManyModel implements Proxy { private bool $initialized = false; public function __load(): void @@ -136,7 +136,7 @@ public function testMissingGet(): void { $this->expectException(DeserializerLogicException::class); - $object = new class() {}; + $object = new class {}; $accessor = new PropertyAccessor('name'); $accessor->getValue($object); diff --git a/tests/Unit/Denormalizer/CallbackFieldDenormalizerTest.php b/tests/Unit/Denormalizer/CallbackFieldDenormalizerTest.php index 09682de..20499c3 100644 --- a/tests/Unit/Denormalizer/CallbackFieldDenormalizerTest.php +++ b/tests/Unit/Denormalizer/CallbackFieldDenormalizerTest.php @@ -22,7 +22,7 @@ final class CallbackFieldDenormalizerTest extends TestCase public function testDenormalizeField(): void { - $object = new class() { + $object = new class { private ?string $name = null; public function getName(): string diff --git a/tests/Unit/Denormalizer/DenormalizerObjectMappingRegistryTest.php b/tests/Unit/Denormalizer/DenormalizerObjectMappingRegistryTest.php index f5e1696..9a1bbd9 100644 --- a/tests/Unit/Denormalizer/DenormalizerObjectMappingRegistryTest.php +++ b/tests/Unit/Denormalizer/DenormalizerObjectMappingRegistryTest.php @@ -67,7 +67,7 @@ public function testGetObjectMappingFromDoctrineProxy(): void private function getProxyObject(): object { - return new class() extends AbstractManyModel implements Proxy { + return new class extends AbstractManyModel implements Proxy { /** * Initializes this proxy if its not yet initialized. * diff --git a/tests/Unit/DependencyInjection/DeserializationCompilerPassTest.php b/tests/Unit/DependencyInjection/DeserializationCompilerPassTest.php index 485c4c2..e03a28c 100644 --- a/tests/Unit/DependencyInjection/DeserializationCompilerPassTest.php +++ b/tests/Unit/DependencyInjection/DeserializationCompilerPassTest.php @@ -71,7 +71,7 @@ public function testProcess(): void private function getStdClassMapping() { - return new class() implements DenormalizationObjectMappingInterface { + return new class implements DenormalizationObjectMappingInterface { public function getClass(): string { return \stdClass::class;