diff --git a/README.md b/README.md index b6b1e276..40382031 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ Definition Files and Transfer Object generators have been tested against the fol * [Content API for Shopping](https://developers.google.com/shopping-content/guides/products/products-api?hl=en) * [Frankfurter is a free, open-source currency data API](https://api.frankfurter.dev/v1/latest) * [Tagesschau API](https://tagesschau.api.bund.dev) +* [Statistisches Bundesamt (Destatis)](https://www-genesis.destatis.de/genesisWS/swagger-ui/index.html#/find/findPost) ### Scenario diff --git a/composer.json b/composer.json index 2007d971..b5d122c8 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "license": "MIT", "authors": [ { - "name": "Sergii Pryz" + "name": "Sergii Pryz", + "role": "Developer" }, { "name": "Community", @@ -71,6 +72,7 @@ "prefer-stable": true, "scripts": { "phpunit": "./vendor/bin/phpunit --no-progress", + "phpunit-group": "./vendor/bin/phpunit --no-progress --group", "phpstan": "./vendor/bin/phpstan analyse -c phpstan.neon --no-progress --memory-limit=512M", "transfer-generate": "php ./bin/transfer-generate", "transfer-generate-bulk": "php ./bin/transfer-generate-bulk", @@ -81,6 +83,7 @@ }, "scripts-descriptions": { "phpunit": "Run unit and integration tests.", + "phpunit-group": "Run unit and integration tests assigned to the group.", "phpstan": "Perform static code analysis using PHPStan.", "transfer-generate": "Generate Transfer Objects from YML definition templates.", "transfer-generate-bulk": "Generate Transfer Objects based on configuration list.", diff --git a/composer.lock b/composer.lock index 509ceb66..17bd77b5 100644 --- a/composer.lock +++ b/composer.lock @@ -1423,16 +1423,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", "shasum": "" }, "require": { @@ -1464,22 +1464,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" }, - "time": "2025-07-13T07:04:09+00:00" + "time": "2025-08-30T15:50:23+00:00" }, { "name": "phpstan/phpstan", - "version": "2.1.22", + "version": "2.1.25", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4" + "reference": "4087d28bd252895874e174d65e26b2c202ed893a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4", - "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4087d28bd252895874e174d65e26b2c202ed893a", + "reference": "4087d28bd252895874e174d65e26b2c202ed893a", "shasum": "" }, "require": { @@ -1524,7 +1524,7 @@ "type": "github" } ], - "time": "2025-08-04T19:17:37+00:00" + "time": "2025-09-12T14:26:42+00:00" }, { "name": "phpstan/phpstan-strict-rules", @@ -1576,34 +1576,34 @@ }, { "name": "phpunit/php-code-coverage", - "version": "12.3.4", + "version": "12.3.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7ad0e9bdc72b147600badccd694a2e57ffc9297a" + "reference": "bbede0f5593dad37af3be6a6f8e6ae1885e8a0a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7ad0e9bdc72b147600badccd694a2e57ffc9297a", - "reference": "7ad0e9bdc72b147600badccd694a2e57ffc9297a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bbede0f5593dad37af3be6a6f8e6ae1885e8a0a9", + "reference": "bbede0f5593dad37af3be6a6f8e6ae1885e8a0a9", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.4.0", + "nikic/php-parser": "^5.6.1", "php": ">=8.3", "phpunit/php-file-iterator": "^6.0", "phpunit/php-text-template": "^5.0", "sebastian/complexity": "^5.0", - "sebastian/environment": "^8.0", + "sebastian/environment": "^8.0.3", "sebastian/lines-of-code": "^4.0", "sebastian/version": "^6.0", "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^12.1" + "phpunit/phpunit": "^12.3.7" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -1641,7 +1641,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.4" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.7" }, "funding": [ { @@ -1661,7 +1661,7 @@ "type": "tidelift" } ], - "time": "2025-08-29T11:32:44+00:00" + "time": "2025-09-10T09:59:06+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1910,16 +1910,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.3.7", + "version": "12.3.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e" + "reference": "0d401d0df2e3c1703be425ecdc2d04f5c095938d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b8fa997c49682979ad6bfaa0d7fb25f54954965e", - "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0d401d0df2e3c1703be425ecdc2d04f5c095938d", + "reference": "0d401d0df2e3c1703be425ecdc2d04f5c095938d", "shasum": "" }, "require": { @@ -1933,7 +1933,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.3", - "phpunit/php-code-coverage": "^12.3.3", + "phpunit/php-code-coverage": "^12.3.7", "phpunit/php-file-iterator": "^6.0.0", "phpunit/php-invoker": "^6.0.0", "phpunit/php-text-template": "^5.0.0", @@ -1943,7 +1943,7 @@ "sebastian/diff": "^7.0.0", "sebastian/environment": "^8.0.3", "sebastian/exporter": "^7.0.0", - "sebastian/global-state": "^8.0.0", + "sebastian/global-state": "^8.0.2", "sebastian/object-enumerator": "^7.0.0", "sebastian/type": "^6.0.3", "sebastian/version": "^6.0.0", @@ -1987,7 +1987,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.10" }, "funding": [ { @@ -2011,7 +2011,7 @@ "type": "tidelift" } ], - "time": "2025-08-28T05:15:46+00:00" + "time": "2025-09-11T10:35:19+00:00" }, { "name": "sebastian/cli-parser", @@ -3002,16 +3002,16 @@ }, { "name": "sebastianfeldmann/git", - "version": "3.14.3", + "version": "3.15.1", "source": { "type": "git", "url": "https://github.com/sebastianfeldmann/git.git", - "reference": "22584df8df01d95b0700000cfd855779fae7d8ea" + "reference": "90cb5a32f54dbb0d7dcd87d02e664ec2b50c0c96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/22584df8df01d95b0700000cfd855779fae7d8ea", - "reference": "22584df8df01d95b0700000cfd855779fae7d8ea", + "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/90cb5a32f54dbb0d7dcd87d02e664ec2b50c0c96", + "reference": "90cb5a32f54dbb0d7dcd87d02e664ec2b50c0c96", "shasum": "" }, "require": { @@ -3052,7 +3052,7 @@ ], "support": { "issues": "https://github.com/sebastianfeldmann/git/issues", - "source": "https://github.com/sebastianfeldmann/git/tree/3.14.3" + "source": "https://github.com/sebastianfeldmann/git/tree/3.15.1" }, "funding": [ { @@ -3060,36 +3060,36 @@ "type": "github" } ], - "time": "2025-06-05T16:05:10+00:00" + "time": "2025-09-05T08:07:09+00:00" }, { "name": "slevomat/coding-standard", - "version": "8.20.0", + "version": "8.22.1", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/1dd80bf3b93692bedb21a6623c496887fad05fec", + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", "php": "^7.4 || ^8.0", - "phpstan/phpdoc-parser": "^2.2.0", - "squizlabs/php_codesniffer": "^3.13.2" + "phpstan/phpdoc-parser": "^2.3.0", + "squizlabs/php_codesniffer": "^3.13.4" }, "require-dev": { "phing/phing": "3.0.1|3.1.0", "php-parallel-lint/php-parallel-lint": "1.4.0", - "phpstan/phpstan": "2.1.19", + "phpstan/phpstan": "2.1.24", "phpstan/phpstan-deprecation-rules": "2.0.3", "phpstan/phpstan-phpunit": "2.0.7", "phpstan/phpstan-strict-rules": "2.0.6", - "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.36|12.3.10" }, "type": "phpcodesniffer-standard", "extra": { @@ -3113,7 +3113,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" + "source": "https://github.com/slevomat/coding-standard/tree/8.22.1" }, "funding": [ { @@ -3125,20 +3125,20 @@ "type": "tidelift" } ], - "time": "2025-07-26T15:35:10+00:00" + "time": "2025-09-13T08:53:30+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.2", + "version": "3.13.4", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" + "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ad545ea9c1b7d270ce0fc9cbfb884161cd706119", + "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119", "shasum": "" }, "require": { @@ -3209,7 +3209,7 @@ "type": "thanks_dev" } ], - "time": "2025-06-17T22:17:01+00:00" + "time": "2025-09-05T05:47:09+00:00" }, { "name": "staabm/side-effects-detector", diff --git a/docker/bash/sdk-autocomplete.sh b/docker/bash/sdk-autocomplete.sh index 77477684..6e873038 100644 --- a/docker/bash/sdk-autocomplete.sh +++ b/docker/bash/sdk-autocomplete.sh @@ -8,12 +8,12 @@ _docker_sdk_autocomplete() { prev="${COMP_WORDS[COMP_CWORD-1]}" # define the main commands for docker/sdk - opts="build start stop cli composer phpstan phpunit phpcs phpcbf hook-install hook to-generate to-generate-bulk df-generate" + opts="build start stop cli composer phpstan phpunit phpunit-group phpcs phpcbf hook-install hook to-generate to-generate-bulk df-generate" case "${prev}" in composer) # define subcommands for 'composer' - COMPREPLY=( $(compgen -W "install update why phpunit phpstan transfer-generate transfer-generate-bulk definition-generate captainhook phpcs phpcbf list" -- "${cur}") ) + COMPREPLY=( $(compgen -W "install update why phpunit phpunit-group phpstan transfer-generate transfer-generate-bulk definition-generate captainhook phpcs phpcbf list" -- "${cur}") ) return 0 ;; hook) diff --git a/docker/php/bash/composer-autocomplete.sh b/docker/php/bash/composer-autocomplete.sh index ba68aad5..92249ae1 100644 --- a/docker/php/bash/composer-autocomplete.sh +++ b/docker/php/bash/composer-autocomplete.sh @@ -6,7 +6,7 @@ _composer_autocomplete() { COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="install update why phpunit phpstan transfer-generate transfer-generate-bulk definition-generate captainhook phpcs phpcbf list" + opts="install update why phpunit phpunit-group phpstan transfer-generate transfer-generate-bulk definition-generate captainhook phpcs phpcbf list" if [[ ${prev} == "composer" ]]; then COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) diff --git a/docker/sdk b/docker/sdk index 717488f1..d332c14d 100755 --- a/docker/sdk +++ b/docker/sdk @@ -26,6 +26,7 @@ function show_usage() { echo -e " $(wrap_in_yellow "composer ") Run composer command" echo -e " $(wrap_in_yellow "phpstan") Run PHPStan" echo -e " $(wrap_in_yellow "phpunit") Run PHPUnit" + echo -e " $(wrap_in_yellow "phpunit-group") Run PHPUnit test assigned to the group" echo -e " $(wrap_in_yellow "phpcs") Run PHP CodeSniffer" echo -e " $(wrap_in_yellow "phpcbf") Run PHP Code Beautifier and Fixer" echo -e " $(wrap_in_yellow "hook-install") Install CaptainHook" @@ -91,6 +92,9 @@ case $1 in phpunit) $DOCKER_EXEC composer phpunit ;; + phpunit-group) + $DOCKER_EXEC composer phpunit-group $2 + ;; phpcs) $DOCKER_EXEC composer phpcs ;; diff --git a/src/Command/TransferGeneratorBulkCommand.php b/src/Command/TransferGeneratorBulkCommand.php index 001abd43..8f58a199 100644 --- a/src/Command/TransferGeneratorBulkCommand.php +++ b/src/Command/TransferGeneratorBulkCommand.php @@ -126,10 +126,6 @@ private function advanceProgressBar( ?ProgressBar $progressBar, ): void { $step = $bulkTransfer->progress->progressBytes; - if ($step === 0) { - return; - } - $progressBar?->advance($step); } diff --git a/src/DefinitionGenerator/Builder/DefinitionContentBuilder.php b/src/DefinitionGenerator/Builder/DefinitionContentBuilder.php index e7dfbc4a..34fbc3fb 100644 --- a/src/DefinitionGenerator/Builder/DefinitionContentBuilder.php +++ b/src/DefinitionGenerator/Builder/DefinitionContentBuilder.php @@ -6,11 +6,15 @@ use Picamator\TransferObject\DefinitionGenerator\Builder\Enum\GetTypeEnum; use Picamator\TransferObject\DefinitionGenerator\Exception\DefinitionGeneratorException; +use Picamator\TransferObject\Shared\Validator\VariableValidatorTrait; readonly class DefinitionContentBuilder implements DefinitionContentBuilderInterface { + use VariableValidatorTrait; + public function createBuilderContent(string $propertyName, mixed $propertyValue): BuilderContentInterface { + $this->assertPropertyName($propertyName); $typeEnum = $this->getTypeEnum($propertyName, $propertyValue); return new BuilderContent($typeEnum, $propertyName, $propertyValue); @@ -28,11 +32,21 @@ private function getTypeEnum(string $propertyName, mixed $propertyValue): GetTyp } throw new DefinitionGeneratorException( - sprintf( - 'Property "%s" with type "%s" is not supported.', - $propertyName, - $propertyType, - ), + sprintf('Property "%s" with type "%s" is not supported.', $propertyName, $propertyType), + ); + } + + /** + * @throws \Picamator\TransferObject\DefinitionGenerator\Exception\DefinitionGeneratorException + */ + private function assertPropertyName(string $propertyName): void + { + if ($this->isValidVariable($propertyName)) { + return; + } + + throw new DefinitionGeneratorException( + sprintf('Invalid property name "%s".', $propertyName), ); } } diff --git a/src/DefinitionGenerator/Render/DefinitionRender.php b/src/DefinitionGenerator/Render/DefinitionRender.php index 06e06cbe..8bde458f 100644 --- a/src/DefinitionGenerator/Render/DefinitionRender.php +++ b/src/DefinitionGenerator/Render/DefinitionRender.php @@ -10,31 +10,35 @@ readonly class DefinitionRender implements DefinitionRenderInterface { - private const string SCHEMA = <<<'START' + private const string SCHEMA = <<<'TEMPLATE' # $schema: https://raw.githubusercontent.com/picamator/transfer-object/main/schema/definition.schema.json -START; +TEMPLATE; - private const string CLASS_TEMPLATE = <<<'START' -# %s -%s: -START; + private const string CLASS_TEMPLATE = <<<'TEMPLATE' +# %1$s +%1$s: - private const string TYPE_TEMPLATE = <<<'START' +TEMPLATE; + + private const string TYPE_TEMPLATE = <<<'TEMPLATE' %s: type: %s -START; - private const string COLLECTION_TYPE_TEMPLATE = <<<'START' +TEMPLATE; + + private const string COLLECTION_TYPE_TEMPLATE = <<<'TEMPLATE' %s: collectionType: %s -START; - private const string DATE_TIME_TYPE_TEMPLATE = <<<'START' +TEMPLATE; + + private const string DATE_TIME_TYPE_TEMPLATE = <<<'TEMPLATE' %s: dateTimeType: %s -START; + +TEMPLATE; public function renderSchema(): string { @@ -43,10 +47,9 @@ public function renderSchema(): string public function renderDefinitionContent(DefinitionContentTransfer $contentTransfer): string { - $content = sprintf(self::CLASS_TEMPLATE, $contentTransfer->className, $contentTransfer->className) . PHP_EOL; + $content = sprintf(self::CLASS_TEMPLATE, $contentTransfer->className); foreach ($contentTransfer->properties as $propertyTransfer) { $content .= $this->renderProperty($propertyTransfer); - $content .= PHP_EOL; } $content .= PHP_EOL; @@ -61,22 +64,16 @@ private function renderProperty(DefinitionPropertyTransfer $propertyTransfer): s { return match (true) { $propertyTransfer->buildInType !== null - => $this->renderType($propertyTransfer->propertyName, $propertyTransfer->buildInType->value), + => $this->renderBuildInType($propertyTransfer), $propertyTransfer->transferType !== null - => $this->renderType($propertyTransfer->propertyName, $propertyTransfer->transferType->name), + => $this->renderTransferType($propertyTransfer), $propertyTransfer->collectionType !== null - => $this->renderCollectionType( - $propertyTransfer->propertyName, - $propertyTransfer->collectionType->name, - ), + => $this->renderCollectionType($propertyTransfer), $propertyTransfer->dateTimeType !== null - => $this->renderDateTimeType( - $propertyTransfer->propertyName, - $propertyTransfer->dateTimeType->name, - ), + => $this->renderDateTimeType($propertyTransfer), default => $this->renderDefault($propertyTransfer), }; @@ -95,18 +92,39 @@ private function renderDefault(DefinitionPropertyTransfer $propertyTransfer): ne ); } - private function renderDateTimeType(string $propertyName, string $typeName): string + private function renderDateTimeType(DefinitionPropertyTransfer $propertyTransfer): string { - return sprintf(self::DATE_TIME_TYPE_TEMPLATE, $propertyName, $typeName); + return sprintf( + self::DATE_TIME_TYPE_TEMPLATE, + $propertyTransfer->propertyName, + $propertyTransfer->dateTimeType?->name ?: '', + ); } - private function renderCollectionType(string $propertyName, string $typeName): string + private function renderCollectionType(DefinitionPropertyTransfer $propertyTransfer): string { - return sprintf(self::COLLECTION_TYPE_TEMPLATE, $propertyName, $typeName); + return sprintf( + self::COLLECTION_TYPE_TEMPLATE, + $propertyTransfer->propertyName, + $propertyTransfer->collectionType?->name ?: '', + ); } - private function renderType(string $propertyName, string $typeName): string + private function renderTransferType(DefinitionPropertyTransfer $propertyTransfer): string { - return sprintf(self::TYPE_TEMPLATE, $propertyName, $typeName); + return sprintf( + self::TYPE_TEMPLATE, + $propertyTransfer->propertyName, + $propertyTransfer->transferType?->name ?: '', + ); + } + + private function renderBuildInType(DefinitionPropertyTransfer $propertyTransfer): string + { + return sprintf( + self::TYPE_TEMPLATE, + $propertyTransfer->propertyName, + $propertyTransfer->buildInType?->value ?: '', + ); } } diff --git a/src/Shared/Filesystem/FileReader.php b/src/Shared/Filesystem/FileReader.php index b8d6425e..781e5c53 100644 --- a/src/Shared/Filesystem/FileReader.php +++ b/src/Shared/Filesystem/FileReader.php @@ -81,6 +81,7 @@ private function getFile(string $filename) return $file; } + /** * @return false|resource */ diff --git a/src/Shared/Reader/FileReaderProgress.php b/src/Shared/Reader/FileReaderProgress.php index 67ee816e..b9492112 100644 --- a/src/Shared/Reader/FileReaderProgress.php +++ b/src/Shared/Reader/FileReaderProgress.php @@ -6,6 +6,7 @@ use Generator; use Picamator\TransferObject\Generated\FileReaderProgressTransfer; +use Picamator\TransferObject\Shared\Exception\FileReaderException; use Picamator\TransferObject\Shared\Filesystem\FileReaderInterface; readonly class FileReaderProgress implements FileReaderProgressInterface @@ -17,9 +18,10 @@ public function __construct( public function readFile(string $filename): Generator { - $contentIterator = $this->fileReader->readFile($filename); - $progressTransfer = $this->createProgressTransfer($filename); + $totalBytes = $this->getTotalBytes($filename); + $progressTransfer = $this->createProgressTransfer($totalBytes); + $contentIterator = $this->fileReader->readFile($filename); foreach ($contentIterator as $content) { $progressTransfer->content = $content; $progressTransfer->progressBytes += strlen($content); @@ -28,23 +30,53 @@ public function readFile(string $filename): Generator } } - private function createProgressTransfer(string $filename): FileReaderProgressTransfer + private function createProgressTransfer(int $totalBytes): FileReaderProgressTransfer { - $filesize = (int)$this->filesize($filename); - $progressTransfer = new FileReaderProgressTransfer(); - $progressTransfer->totalBytes = $filesize; + $progressTransfer->totalBytes = $totalBytes; $progressTransfer->progressBytes = 0; return $progressTransfer; } - protected function filesize(string $filename): int|false + /** + * @throws \Picamator\TransferObject\Shared\Exception\FileReaderException + */ + private function getTotalBytes(string $filename): int { - if (!file_exists($filename)) { - return false; + if (!$this->fileExists($filename)) { + throw new FileReaderException( + sprintf('File "%s" is not exist.', $filename), + ); + } + + $fileSize = $this->filesize($filename); + if ($fileSize === 0) { + throw new FileReaderException( + sprintf('File size "%s" is empty.', $filename), + ); + } + + if ($fileSize === false) { + throw new FileReaderException( + sprintf( + 'Failed to get file size "%s". Error: "%s".', + $filename, + error_get_last()['message'] ?? '', + ), + ); } - return filesize($filename); + return $fileSize; + } + + protected function filesize(string $filename): int|false + { + return @filesize($filename); + } + + protected function fileExists(string $filename): bool + { + return file_exists($filename); } } diff --git a/src/Transfer/AbstractTransfer.php b/src/Transfer/AbstractTransfer.php index 1d6eeeca..8e0708e4 100644 --- a/src/Transfer/AbstractTransfer.php +++ b/src/Transfer/AbstractTransfer.php @@ -4,6 +4,7 @@ namespace Picamator\TransferObject\Transfer; +use Deprecated; use SplFixedArray; use Traversable; @@ -94,16 +95,22 @@ final public function __clone(): void final public function toArray(): array { $data = []; + $attributes = $this->getTypeAttributes(); + foreach (static::META_DATA as $metaKey => $metaName) { - $dataItem = $this->{$metaKey}; - $attribute = $this->getConstantAttribute($metaName); + if (isset($attributes[$metaName])) { + $data[$metaKey] = $attributes[$metaName]->toArray($this->{$metaKey}); + + continue; + } - $data[$metaKey] = $attribute !== null ? $attribute->toArray($dataItem) : $dataItem; + $data[$metaKey] = $this->{$metaKey}; } return $data; } + #[Deprecated(message: 'Method will be removed in version 3.0.0. Use FilterArrayTrait instead.', since: '2.3.0')] final public function toFilterArray(?callable $callback = null): array { $data = $this->toArray(); @@ -119,13 +126,19 @@ final public function fromArray(array $data): static return $this; } + $attributes = $this->getTypeAttributes(); foreach (static::META_DATA as $metaKey => $metaName) { if (!isset($data[$metaKey])) { continue; } - $attribute = $this->getConstantAttribute($metaName); - $this->{$metaKey} = $attribute !== null ? $attribute->fromArray($data[$metaKey]) : $data[$metaKey]; + if (isset($attributes[$metaName])) { + $this->{$metaKey} = $attributes[$metaName]->fromArray($data[$metaKey]); + + continue; + } + + $this->{$metaKey} = $data[$metaKey]; } return $this; @@ -145,10 +158,10 @@ private function initData(): void { $this->_data = new SplFixedArray(static::META_DATA_SIZE); - foreach (static::META_DATA as $metaName) { + foreach ($this->getInitialAttributes() as $metaName => $attribute) { $metaIndex = $metaName . self::DATA_INDEX_SUFFIX; // @phpstan-ignore offsetAssign.dimType - $this->_data[static::{$metaIndex}] = $this->getConstantInitialAttribute($metaName)?->getInitialValue(); + $this->_data[static::{$metaIndex}] = $attribute->getInitialValue(); } } } diff --git a/src/Transfer/Attribute/CollectionPropertyTypeAttribute.php b/src/Transfer/Attribute/CollectionPropertyTypeAttribute.php index 2ed6bdce..8ae38921 100644 --- a/src/Transfer/Attribute/CollectionPropertyTypeAttribute.php +++ b/src/Transfer/Attribute/CollectionPropertyTypeAttribute.php @@ -10,6 +10,8 @@ /** * @api + * + * @property class-string<\Picamator\TransferObject\Transfer\AbstractTransfer|TransferInterface> $typeName */ #[Attribute(Attribute::TARGET_CLASS_CONSTANT)] final readonly class CollectionPropertyTypeAttribute implements InitialPropertyTypeAttributeInterface diff --git a/src/Transfer/Attribute/PropertyTypeAttribute.php b/src/Transfer/Attribute/PropertyTypeAttribute.php index 497336ab..866124a6 100644 --- a/src/Transfer/Attribute/PropertyTypeAttribute.php +++ b/src/Transfer/Attribute/PropertyTypeAttribute.php @@ -9,6 +9,8 @@ /** * @api + * + * @property class-string<\Picamator\TransferObject\Transfer\AbstractTransfer|TransferInterface> $typeName */ #[Attribute(Attribute::TARGET_CLASS_CONSTANT)] final readonly class PropertyTypeAttribute implements PropertyTypeAttributeInterface diff --git a/src/Transfer/Attribute/TransferBuilderTrait.php b/src/Transfer/Attribute/TransferBuilderTrait.php index 2b2d698b..0773a269 100644 --- a/src/Transfer/Attribute/TransferBuilderTrait.php +++ b/src/Transfer/Attribute/TransferBuilderTrait.php @@ -6,26 +6,70 @@ use Picamator\TransferObject\Transfer\AbstractTransfer; use Picamator\TransferObject\Transfer\TransferInterface; +use ReflectionClass; +/** + * Specification: + * - Uses lazy loading to postpone initiating embedded transfer objects. + * + * @link https://www.php.net/manual/en/language.oop5.lazy-objects.php + * @link https://wiki.php.net/rfc/lazy-objects + */ trait TransferBuilderTrait { use DataAssertTrait; /** - * @throws \Picamator\TransferObject\Transfer\Exception\PropertyTypeTransferException + * @param class-string $typeName + * + * @throws \ReflectionException */ final protected function createTransfer(string $typeName, mixed $data): TransferInterface { $this->assertArray($data); - /** @var array $data */ - if (is_subclass_of($typeName, AbstractTransfer::class)) { - return new $typeName($data); + $reflection = new ReflectionClass($typeName); + + if ($reflection->isSubclassOf(AbstractTransfer::class)) { + /** @var array $data */ + return $this->createLazyAbstractTransfer($reflection, $data); } - /** @var \Picamator\TransferObject\Transfer\TransferInterface $transfer */ - $transfer = new $typeName(); + /** @var array $data */ + return $this->createLazyTransfer($reflection, $data); + } + + /** + * @param ReflectionClass $reflection + * @param array $data + */ + private function createLazyTransfer(ReflectionClass $reflection, array $data): TransferInterface + { + /** + * @var TransferInterface $transfer + * @phpstan-ignore argument.type + */ + $transfer = $reflection->newLazyGhost(function (TransferInterface $object) use ($data): void { + $object->fromArray($data); + }); + + return $transfer; + } + + /** + * @param ReflectionClass $reflection + * @param array $data + */ + private function createLazyAbstractTransfer(ReflectionClass $reflection, array $data): TransferInterface + { + /** + * @var TransferInterface $transfer + * @phpstan-ignore argument.type + */ + $transfer = $reflection->newLazyGhost(function (AbstractTransfer $object) use ($data): void { + $object->__construct($data); + }); - return $transfer->fromArray($data); + return $transfer; } } diff --git a/src/Transfer/ConstantAttributeTrait.php b/src/Transfer/ConstantAttributeTrait.php index 83357fad..00420ae1 100644 --- a/src/Transfer/ConstantAttributeTrait.php +++ b/src/Transfer/ConstantAttributeTrait.php @@ -4,36 +4,61 @@ namespace Picamator\TransferObject\Transfer; +use Generator; use Picamator\TransferObject\Transfer\Attribute\InitialPropertyTypeAttributeInterface; use Picamator\TransferObject\Transfer\Attribute\PropertyTypeAttributeInterface; use ReflectionAttribute; use ReflectionClassConstant; +use ReflectionObject; trait ConstantAttributeTrait { - final protected function getConstantAttribute(string $constantName): ?PropertyTypeAttributeInterface + /** + * @return array + */ + final protected function getTypeAttributes(): array { - $reflection = new ReflectionClassConstant($this, $constantName); - $attributeReflections = $reflection->getAttributes( - name: PropertyTypeAttributeInterface::class, - flags: ReflectionAttribute::IS_INSTANCEOF - ); + $typeAttributes = []; + foreach ($this->getReflectionConstants() as $reflectionConstant) { + $attributeReflections = $reflectionConstant->getAttributes( + name: PropertyTypeAttributeInterface::class, + flags: ReflectionAttribute::IS_INSTANCEOF, + ); - $attributeReflection = $attributeReflections[0] ?? null; + if (!isset($attributeReflections[0])) { + continue; + } - return $attributeReflection?->newInstance(); + $typeAttributes[$reflectionConstant->getName()] = $attributeReflections[0]->newInstance(); + } + + return $typeAttributes; } - final protected function getConstantInitialAttribute(string $constantName): ?InitialPropertyTypeAttributeInterface + /** + * @return Generator + */ + final protected function getInitialAttributes(): Generator { - $reflection = new ReflectionClassConstant($this, $constantName); - $attributeReflections = $reflection->getAttributes( - name: InitialPropertyTypeAttributeInterface::class, - flags: ReflectionAttribute::IS_INSTANCEOF - ); + foreach ($this->getReflectionConstants() as $reflectionConstant) { + $attributeReflections = $reflectionConstant->getAttributes( + name: InitialPropertyTypeAttributeInterface::class, + flags: ReflectionAttribute::IS_INSTANCEOF, + ); + + if (!isset($attributeReflections[0])) { + continue; + } - $attributeReflection = $attributeReflections[0] ?? null; + yield $reflectionConstant->getName() => $attributeReflections[0]->newInstance(); + } + } - return $attributeReflection?->newInstance(); + /** + * @return array + */ + private function getReflectionConstants(): array + { + return new ReflectionObject($this)->getReflectionConstants(ReflectionClassConstant::IS_PUBLIC); } } diff --git a/src/Transfer/DummyTransferAdapterTrait.php b/src/Transfer/DummyTransferAdapterTrait.php index ad3035ce..fb6f964f 100644 --- a/src/Transfer/DummyTransferAdapterTrait.php +++ b/src/Transfer/DummyTransferAdapterTrait.php @@ -4,6 +4,7 @@ namespace Picamator\TransferObject\Transfer; +use Deprecated; use EmptyIterator; use Traversable; @@ -45,6 +46,7 @@ public function toArray(): array /** * @return array */ + #[Deprecated(message: 'Method will be removed in version 3.0.0. Use FilterArrayTrait instead.', since: '2.3.0')] public function toFilterArray(?callable $callback = null): array { $data = $this->toArray(); diff --git a/src/Transfer/TransferAdapterTrait.php b/src/Transfer/TransferAdapterTrait.php index 73c1b1a2..4d93d4e1 100644 --- a/src/Transfer/TransferAdapterTrait.php +++ b/src/Transfer/TransferAdapterTrait.php @@ -10,6 +10,7 @@ use DateTime; use DateTimeImmutable; use DateTimeInterface; +use Deprecated; use ReflectionClass; use ReflectionProperty; use stdClass; @@ -89,6 +90,7 @@ public function toArray(): array /** * @return array */ + #[Deprecated(message: 'Method will be removed in version 3.0.0. Use FilterArrayTrait instead.', since: '2.3.0')] public function toFilterArray(?callable $callback = null): array { $data = $this->toArray(); diff --git a/src/Transfer/TransferInterface.php b/src/Transfer/TransferInterface.php index 014a30af..f9ecde01 100644 --- a/src/Transfer/TransferInterface.php +++ b/src/Transfer/TransferInterface.php @@ -5,6 +5,7 @@ namespace Picamator\TransferObject\Transfer; use Countable; +use Deprecated; use IteratorAggregate; use JsonSerializable; @@ -36,10 +37,13 @@ public function toArray(): array; * * @api * + * @deprecated Method will be removed in version 3.0.0. Use FilterArrayTrait instead. + * * @param callable|null $callback Optional. A callback function to apply to each property. * If null, empty entries will be removed. * @return array */ + #[Deprecated(message: 'Method will be removed in version 3.0.0. Use FilterArrayTrait instead.', since: '2.3.0')] public function toFilterArray(?callable $callback = null): array; /** diff --git a/src/TransferGenerator/Definition/Parser/ContentBuilder.php b/src/TransferGenerator/Definition/Parser/ContentBuilder.php index 1a1e28ce..0efdb107 100644 --- a/src/TransferGenerator/Definition/Parser/ContentBuilder.php +++ b/src/TransferGenerator/Definition/Parser/ContentBuilder.php @@ -11,7 +11,7 @@ readonly class ContentBuilder implements ContentBuilderInterface { - private const TypeSuffixEnum CLASS_SUFFIX = TypeSuffixEnum::TRANSFER; + private const TypeSuffixEnum TYPE_SUFFIX = TypeSuffixEnum::TRANSFER; public function __construct( private PropertyExpanderInterface $propertyExpander, @@ -21,7 +21,7 @@ public function __construct( public function createContentTransfer(string $className, array $properties): DefinitionContentTransfer { $contentTransfer = new DefinitionContentTransfer(); - $contentTransfer->className = self::CLASS_SUFFIX->getClassName($className); + $contentTransfer->className = self::TYPE_SUFFIX->getClassName($className); foreach ($properties as $propertyName => $propertyType) { $contentTransfer->properties[] = $this->createPropertyTransfer((string)$propertyName, $propertyType); diff --git a/src/TransferGenerator/Definition/Parser/Filter/PropertyFilterTrait.php b/src/TransferGenerator/Definition/Parser/Filter/PropertyFilterTrait.php index f8bd33f4..d9034ec3 100644 --- a/src/TransferGenerator/Definition/Parser/Filter/PropertyFilterTrait.php +++ b/src/TransferGenerator/Definition/Parser/Filter/PropertyFilterTrait.php @@ -36,7 +36,7 @@ private function filterPropertyType(mixed $propertyType): array $filteredType = []; foreach ($propertyType as $key => $typeItem) { - if (!is_string($key)) { + if (is_int($key)) { continue; } diff --git a/src/TransferGenerator/Definition/Validator/Content/Property/CollectionTypePropertyValidator.php b/src/TransferGenerator/Definition/Validator/Content/Property/CollectionTypePropertyValidator.php index c3a64fa4..ce5b5ca7 100644 --- a/src/TransferGenerator/Definition/Validator/Content/Property/CollectionTypePropertyValidator.php +++ b/src/TransferGenerator/Definition/Validator/Content/Property/CollectionTypePropertyValidator.php @@ -8,15 +8,12 @@ use Picamator\TransferObject\Generated\ValidatorMessageTransfer; use Picamator\TransferObject\Shared\Validator\ClassNameValidatorInterface; use Picamator\TransferObject\Shared\Validator\NamespaceValidatorInterface; -use Picamator\TransferObject\Shared\Validator\ValidatorMessageTrait; -class CollectionTypePropertyValidator implements PropertyValidatorInterface +readonly class CollectionTypePropertyValidator implements PropertyValidatorInterface { - use ValidatorMessageTrait; - public function __construct( - private readonly ClassNameValidatorInterface $classNameValidator, - private readonly NamespaceValidatorInterface $namespaceValidator, + private ClassNameValidatorInterface $classNameValidator, + private NamespaceValidatorInterface $namespaceValidator, ) { } diff --git a/src/TransferGenerator/Generator/Enum/AttributeEmbeddedTemplateEnum.php b/src/TransferGenerator/Generator/Enum/AttributeEmbeddedTemplateEnum.php new file mode 100644 index 00000000..c6772c24 --- /dev/null +++ b/src/TransferGenerator/Generator/Enum/AttributeEmbeddedTemplateEnum.php @@ -0,0 +1,21 @@ +value, $embeddedTypeTransfer->name); + } +} diff --git a/src/TransferGenerator/Generator/Enum/AttributeTemplateEnum.php b/src/TransferGenerator/Generator/Enum/AttributeTemplateEnum.php index b0153571..7c2e21e7 100644 --- a/src/TransferGenerator/Generator/Enum/AttributeTemplateEnum.php +++ b/src/TransferGenerator/Generator/Enum/AttributeTemplateEnum.php @@ -6,11 +6,6 @@ enum AttributeTemplateEnum: string { - case TYPE_ATTRIBUTE = '#[PropertyTypeAttribute(%s::class)]'; - case COLLECTION_TYPE_ATTRIBUTE = '#[CollectionPropertyTypeAttribute(%s::class)]'; - case ENUM_TYPE_ATTRIBUTE = '#[EnumPropertyTypeAttribute(%s::class)]'; case ARRAY_OBJECT_TYPE_ATTRIBUTE = '#[ArrayObjectPropertyTypeAttribute]'; case ARRAY_TYPE_ATTRIBUTE = '#[ArrayPropertyTypeAttribute]'; - case DATE_TIME_TYPE_ATTRIBUTE = '#[DateTimePropertyTypeAttribute(%s::class)]'; - case NUMBER_TYPE_ATTRIBUTE = '#[NumberPropertyTypeAttribute(%s::class)]'; } diff --git a/src/TransferGenerator/Generator/Render/Expander/BuildInTypeTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/BuildInTypeTemplateExpander.php index 61e7ac30..78051756 100644 --- a/src/TransferGenerator/Generator/Render/Expander/BuildInTypeTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/BuildInTypeTemplateExpander.php @@ -13,6 +13,8 @@ final class BuildInTypeTemplateExpander extends AbstractTemplateExpander { + use TemplateExpanderTrait; + protected function isApplicable(DefinitionPropertyTransfer $propertyTransfer): bool { return $propertyTransfer->buildInType !== null; @@ -22,17 +24,20 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { + /** @var \Picamator\TransferObject\TransferGenerator\Definition\Enum\BuildInTypeEnum $buildInType */ + $buildInType = $propertyTransfer->buildInType; + $propertyName = $propertyTransfer->propertyName; - $templateTransfer->properties[$propertyName] = $propertyTransfer->buildInType?->value; + $templateTransfer->properties[$propertyName] = $buildInType->value; $templateTransfer->nullables[$propertyName] = $propertyTransfer->isNullable; - if ($propertyTransfer->buildInType?->isArrayObject()) { + if ($buildInType->isArrayObject()) { $this->expandArrayObjectType($propertyTransfer, $templateTransfer); return; } - if ($propertyTransfer->buildInType?->isArray()) { + if ($buildInType->isArray()) { $this->expandArrayType($propertyTransfer, $templateTransfer); } } @@ -41,11 +46,9 @@ private function expandArrayType( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $propertyName = $propertyTransfer->propertyName; - - $templateTransfer->imports[AttributeEnum::ARRAY_TYPE_ATTRIBUTE->value] - ??= AttributeEnum::ARRAY_TYPE_ATTRIBUTE->value; + $this->expandImports(AttributeEnum::ARRAY_TYPE_ATTRIBUTE, $templateTransfer); + $propertyName = $propertyTransfer->propertyName; $templateTransfer->attributes[$propertyName] = AttributeTemplateEnum::ARRAY_TYPE_ATTRIBUTE->value; $templateTransfer->dockBlocks[$propertyName] = DockBlockTemplateEnum::ARRAY->value; $templateTransfer->nullables[$propertyName] = false; @@ -55,12 +58,10 @@ private function expandArrayObjectType( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $propertyName = $propertyTransfer->propertyName; - - $templateTransfer->imports[BuildInTypeEnum::ARRAY_OBJECT->value] ??= BuildInTypeEnum::ARRAY_OBJECT->value; - $templateTransfer->imports[AttributeEnum::ARRAY_OBJECT_TYPE_ATTRIBUTE->value] - ??= AttributeEnum::ARRAY_OBJECT_TYPE_ATTRIBUTE->value; + $this->expandImports(BuildInTypeEnum::ARRAY_OBJECT, $templateTransfer); + $this->expandImports(AttributeEnum::ARRAY_OBJECT_TYPE_ATTRIBUTE, $templateTransfer); + $propertyName = $propertyTransfer->propertyName; $templateTransfer->attributes[$propertyName] = AttributeTemplateEnum::ARRAY_OBJECT_TYPE_ATTRIBUTE->value; $templateTransfer->dockBlocks[$propertyName] = DockBlockTemplateEnum::ARRAY_OBJECT->value; $templateTransfer->nullables[$propertyName] = false; diff --git a/src/TransferGenerator/Generator/Render/Expander/CollectionTypeTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/CollectionTypeTemplateExpander.php index 149de1fb..ef6885b6 100644 --- a/src/TransferGenerator/Generator/Render/Expander/CollectionTypeTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/CollectionTypeTemplateExpander.php @@ -4,11 +4,12 @@ namespace Picamator\TransferObject\TransferGenerator\Generator\Render\Expander; +use Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer; use Picamator\TransferObject\Generated\DefinitionPropertyTransfer; use Picamator\TransferObject\Generated\TemplateTransfer; use Picamator\TransferObject\TransferGenerator\Definition\Enum\BuildInTypeEnum; +use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEmbeddedTemplateEnum; use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEnum; -use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeTemplateEnum; use Picamator\TransferObject\TransferGenerator\Generator\Enum\DockBlockTemplateEnum; final class CollectionTypeTemplateExpander extends AbstractTemplateExpander @@ -24,33 +25,29 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $templateTransfer->imports[BuildInTypeEnum::ARRAY_OBJECT->value] ??= BuildInTypeEnum::ARRAY_OBJECT->value; - $templateTransfer->imports[AttributeEnum::COLLECTION_TYPE_ATTRIBUTE->value] - ??= AttributeEnum::COLLECTION_TYPE_ATTRIBUTE->value; + $this->expandImports(BuildInTypeEnum::ARRAY_OBJECT, $templateTransfer); + $this->expandImports(AttributeEnum::COLLECTION_TYPE_ATTRIBUTE, $templateTransfer); + + /** @var \Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer */ + $embeddedTypeTransfer = $propertyTransfer->collectionType; $propertyName = $propertyTransfer->propertyName; $templateTransfer->properties[$propertyName] = BuildInTypeEnum::ARRAY_OBJECT->value; - $templateTransfer->attributes[$propertyName] = $this->getPropertyAttribute($propertyTransfer); - $templateTransfer->dockBlocks[$propertyName] = $this->getPropertyDockBlock($propertyTransfer); + $templateTransfer->dockBlocks[$propertyName] = $this->getPropertyDockBlock($embeddedTypeTransfer); $templateTransfer->nullables[$propertyName] = false; + + $templateTransfer->attributes[$propertyName] + = AttributeEmbeddedTemplateEnum::COLLECTION_TYPE_ATTRIBUTE->renderTemplate($embeddedTypeTransfer); } - private function getPropertyDockBlock(DefinitionPropertyTransfer $propertyTransfer): string + private function getPropertyDockBlock(DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer): string { - $propertyType = $propertyTransfer->collectionType?->name ?: ''; - $namespaceTransfer = $propertyTransfer->collectionType?->namespace; + $propertyType = $embeddedTypeTransfer->name; - if ($namespaceTransfer !== null) { + if ($embeddedTypeTransfer->namespace !== null) { $propertyType = $this->enforceTransferInterface($propertyType); } return sprintf(DockBlockTemplateEnum::COLLECTION->value, $propertyType); } - - private function getPropertyAttribute(DefinitionPropertyTransfer $propertyTransfer): string - { - $transferType = $propertyTransfer->collectionType?->name ?: ''; - - return sprintf(AttributeTemplateEnum::COLLECTION_TYPE_ATTRIBUTE->value, $transferType); - } } diff --git a/src/TransferGenerator/Generator/Render/Expander/DateTimeTypeTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/DateTimeTypeTemplateExpander.php index 53275ca6..3614098f 100644 --- a/src/TransferGenerator/Generator/Render/Expander/DateTimeTypeTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/DateTimeTypeTemplateExpander.php @@ -4,13 +4,15 @@ namespace Picamator\TransferObject\TransferGenerator\Generator\Render\Expander; +use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEmbeddedTemplateEnum; use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEnum; -use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeTemplateEnum; use Picamator\TransferObject\Generated\DefinitionPropertyTransfer; use Picamator\TransferObject\Generated\TemplateTransfer; final class DateTimeTypeTemplateExpander extends AbstractTemplateExpander { + use TemplateExpanderTrait; + protected function isApplicable(DefinitionPropertyTransfer $propertyTransfer): bool { return $propertyTransfer->dateTimeType !== null; @@ -20,23 +22,13 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $templateTransfer->imports[AttributeEnum::DATE_TIME_TYPE_ATTRIBUTE->value] - ??= AttributeEnum::DATE_TIME_TYPE_ATTRIBUTE->value; - - $importDateTime = $propertyTransfer->dateTimeType?->namespace?->fullName ?: ''; - - $templateTransfer->imports[$importDateTime] ??= $importDateTime; + $this->expandImports(AttributeEnum::DATE_TIME_TYPE_ATTRIBUTE, $templateTransfer); - $propertyName = $propertyTransfer->propertyName; - $dateTimeClassName = $propertyTransfer->dateTimeType?->name ?: ''; + /** @var \Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer */ + $embeddedTypeTransfer = $propertyTransfer->dateTimeType; + $this->expandEmbeddedType($propertyTransfer, $embeddedTypeTransfer, $templateTransfer); - $templateTransfer->properties[$propertyName] = $dateTimeClassName; - $templateTransfer->attributes[$propertyName] = $this->getPropertyAttribute($dateTimeClassName); - $templateTransfer->nullables[$propertyName] = $propertyTransfer->isNullable; - } - - private function getPropertyAttribute(string $dateTimeClassName): string - { - return sprintf(AttributeTemplateEnum::DATE_TIME_TYPE_ATTRIBUTE->value, $dateTimeClassName); + $templateTransfer->attributes[$propertyTransfer->propertyName] + = AttributeEmbeddedTemplateEnum::DATE_TIME_TYPE_ATTRIBUTE->renderTemplate($embeddedTypeTransfer); } } diff --git a/src/TransferGenerator/Generator/Render/Expander/EnumTypeTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/EnumTypeTemplateExpander.php index e8fcfa6c..20d236e4 100644 --- a/src/TransferGenerator/Generator/Render/Expander/EnumTypeTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/EnumTypeTemplateExpander.php @@ -4,13 +4,15 @@ namespace Picamator\TransferObject\TransferGenerator\Generator\Render\Expander; +use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEmbeddedTemplateEnum; use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEnum; -use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeTemplateEnum; use Picamator\TransferObject\Generated\DefinitionPropertyTransfer; use Picamator\TransferObject\Generated\TemplateTransfer; final class EnumTypeTemplateExpander extends AbstractTemplateExpander { + use TemplateExpanderTrait; + protected function isApplicable(DefinitionPropertyTransfer $propertyTransfer): bool { return $propertyTransfer->enumType !== null; @@ -20,22 +22,13 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $templateTransfer->imports[AttributeEnum::ENUM_TYPE_ATTRIBUTE->value] - ??= AttributeEnum::ENUM_TYPE_ATTRIBUTE->value; - - $importEnum = $propertyTransfer->enumType?->namespace?->fullName ?: ''; - $templateTransfer->imports[$importEnum] ??= $importEnum; + $this->expandImports(AttributeEnum::ENUM_TYPE_ATTRIBUTE, $templateTransfer); - $propertyName = $propertyTransfer->propertyName; - $enumClassName = $propertyTransfer->enumType?->name ?: ''; + /** @var \Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer */ + $embeddedTypeTransfer = $propertyTransfer->enumType; + $this->expandEmbeddedType($propertyTransfer, $embeddedTypeTransfer, $templateTransfer); - $templateTransfer->properties[$propertyName] = $enumClassName; - $templateTransfer->attributes[$propertyName] = $this->getPropertyAttribute($enumClassName); - $templateTransfer->nullables[$propertyName] = $propertyTransfer->isNullable; - } - - private function getPropertyAttribute(string $enumClassName): string - { - return sprintf(AttributeTemplateEnum::ENUM_TYPE_ATTRIBUTE->value, $enumClassName); + $templateTransfer->attributes[$propertyTransfer->propertyName] + = AttributeEmbeddedTemplateEnum::ENUM_TYPE_ATTRIBUTE->renderTemplate($embeddedTypeTransfer); } } diff --git a/src/TransferGenerator/Generator/Render/Expander/NamespaceTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/NamespaceTemplateExpander.php index 6d69ba11..bcf3b631 100644 --- a/src/TransferGenerator/Generator/Render/Expander/NamespaceTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/NamespaceTemplateExpander.php @@ -11,20 +11,23 @@ final class NamespaceTemplateExpander extends AbstractTemplateExpander { + use TemplateExpanderTrait; + protected function isApplicable(DefinitionPropertyTransfer $propertyTransfer): bool { - return $this->getNamespaceTransfer($propertyTransfer) !== null; + return $propertyTransfer->transferType?->namespace !== null + || $propertyTransfer->collectionType?->namespace !== null; } protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { + /** @var \Picamator\TransferObject\Generated\DefinitionNamespaceTransfer $namespaceTransfer */ $namespaceTransfer = $this->getNamespaceTransfer($propertyTransfer); - $namespace = $namespaceTransfer?->fullName ?: ''; - $templateTransfer->imports[$namespace] ??= $namespace; - $templateTransfer->imports[TransferEnum::INTERFACE->value] ??= TransferEnum::INTERFACE->value; + $this->expandImports($namespaceTransfer->fullName, $templateTransfer); + $this->expandImports(TransferEnum::INTERFACE, $templateTransfer); } private function getNamespaceTransfer(DefinitionPropertyTransfer $propertyTransfer): ?DefinitionNamespaceTransfer diff --git a/src/TransferGenerator/Generator/Render/Expander/NumberTypeTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/NumberTypeTemplateExpander.php index 01ea58ca..a0dda601 100644 --- a/src/TransferGenerator/Generator/Render/Expander/NumberTypeTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/NumberTypeTemplateExpander.php @@ -4,13 +4,15 @@ namespace Picamator\TransferObject\TransferGenerator\Generator\Render\Expander; +use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEmbeddedTemplateEnum; use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEnum; -use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeTemplateEnum; use Picamator\TransferObject\Generated\DefinitionPropertyTransfer; use Picamator\TransferObject\Generated\TemplateTransfer; final class NumberTypeTemplateExpander extends AbstractTemplateExpander { + use TemplateExpanderTrait; + protected function isApplicable(DefinitionPropertyTransfer $propertyTransfer): bool { return $propertyTransfer->numberType !== null; @@ -20,23 +22,13 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $templateTransfer->imports[AttributeEnum::NUMBER_TYPE_ATTRIBUTE->value] - ??= AttributeEnum::NUMBER_TYPE_ATTRIBUTE->value; - - $importNumber = $propertyTransfer->numberType?->namespace?->fullName ?: ''; - - $templateTransfer->imports[$importNumber] ??= $importNumber; + $this->expandImports(AttributeEnum::NUMBER_TYPE_ATTRIBUTE, $templateTransfer); - $propertyName = $propertyTransfer->propertyName; - $numberClassName = $propertyTransfer->numberType?->name ?: ''; + /** @var \Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer */ + $embeddedTypeTransfer = $propertyTransfer->numberType; + $this->expandEmbeddedType($propertyTransfer, $embeddedTypeTransfer, $templateTransfer); - $templateTransfer->properties[$propertyName] = $numberClassName; - $templateTransfer->attributes[$propertyName] = $this->getPropertyAttribute($numberClassName); - $templateTransfer->nullables[$propertyName] = $propertyTransfer->isNullable; - } - - private function getPropertyAttribute(string $numberClassName): string - { - return sprintf(AttributeTemplateEnum::NUMBER_TYPE_ATTRIBUTE->value, $numberClassName); + $templateTransfer->attributes[$propertyTransfer->propertyName] + = AttributeEmbeddedTemplateEnum::NUMBER_TYPE_ATTRIBUTE->renderTemplate($embeddedTypeTransfer); } } diff --git a/src/TransferGenerator/Generator/Render/Expander/ProtectedTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/ProtectedTemplateExpander.php index ffbd235f..81e9f7a2 100644 --- a/src/TransferGenerator/Generator/Render/Expander/ProtectedTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/ProtectedTemplateExpander.php @@ -21,7 +21,6 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $propertyName = $propertyTransfer->propertyName; - $templateTransfer->protects[$propertyName] = $propertyTransfer->isProtected; + $templateTransfer->protects[$propertyTransfer->propertyName] = $propertyTransfer->isProtected; } } diff --git a/src/TransferGenerator/Generator/Render/Expander/TemplateExpanderTrait.php b/src/TransferGenerator/Generator/Render/Expander/TemplateExpanderTrait.php index ed0d9280..c5836e6f 100644 --- a/src/TransferGenerator/Generator/Render/Expander/TemplateExpanderTrait.php +++ b/src/TransferGenerator/Generator/Render/Expander/TemplateExpanderTrait.php @@ -4,10 +4,37 @@ namespace Picamator\TransferObject\TransferGenerator\Generator\Render\Expander; +use BackedEnum; +use Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer; +use Picamator\TransferObject\Generated\DefinitionPropertyTransfer; +use Picamator\TransferObject\Generated\TemplateTransfer; + trait TemplateExpanderTrait { final protected function enforceTransferInterface(string $propertyType): string { return 'TransferInterface&' . $propertyType; } + + final protected function expandImports(string|BackedEnum $className, TemplateTransfer $templateTransfer): void + { + if ($className instanceof BackedEnum) { + $className = $className->value; + } + + $templateTransfer->imports[$className] ??= $className; + } + + final protected function expandEmbeddedType( + DefinitionPropertyTransfer $propertyTransfer, + DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer, + TemplateTransfer $templateTransfer, + ): void { + $className = $embeddedTypeTransfer->namespace?->fullName ?: ''; + $this->expandImports($className, $templateTransfer); + + $propertyName = $propertyTransfer->propertyName; + $templateTransfer->properties[$propertyName] = $embeddedTypeTransfer->name; + $templateTransfer->nullables[$propertyName] = $propertyTransfer->isNullable; + } } diff --git a/src/TransferGenerator/Generator/Render/Expander/TransferTypeTemplateExpander.php b/src/TransferGenerator/Generator/Render/Expander/TransferTypeTemplateExpander.php index c7416bfe..9fccdd1c 100644 --- a/src/TransferGenerator/Generator/Render/Expander/TransferTypeTemplateExpander.php +++ b/src/TransferGenerator/Generator/Render/Expander/TransferTypeTemplateExpander.php @@ -4,10 +4,11 @@ namespace Picamator\TransferObject\TransferGenerator\Generator\Render\Expander; +use Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer; use Picamator\TransferObject\Generated\DefinitionPropertyTransfer; use Picamator\TransferObject\Generated\TemplateTransfer; +use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEmbeddedTemplateEnum; use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeEnum; -use Picamator\TransferObject\TransferGenerator\Generator\Enum\AttributeTemplateEnum; final class TransferTypeTemplateExpander extends AbstractTemplateExpander { @@ -22,30 +23,25 @@ protected function handleExpander( DefinitionPropertyTransfer $propertyTransfer, TemplateTransfer $templateTransfer, ): void { - $templateTransfer->imports[AttributeEnum::TYPE_ATTRIBUTE->value] ??= AttributeEnum::TYPE_ATTRIBUTE->value; + $this->expandImports(AttributeEnum::TYPE_ATTRIBUTE, $templateTransfer); + + /** @var \Picamator\TransferObject\Generated\DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer */ + $embeddedTypeTransfer = $propertyTransfer->transferType; $propertyName = $propertyTransfer->propertyName; - $templateTransfer->properties[$propertyName] = $this->getPropertyType($propertyTransfer); - $templateTransfer->attributes[$propertyName] = $this->getPropertyAttribute($propertyTransfer); + $templateTransfer->properties[$propertyName] = $this->getPropertyType($embeddedTypeTransfer); $templateTransfer->nullables[$propertyName] = $propertyTransfer->isNullable; - } - private function getPropertyAttribute(DefinitionPropertyTransfer $propertyTransfer): string - { - $transferType = $propertyTransfer->transferType?->name ?: ''; - - return sprintf(AttributeTemplateEnum::TYPE_ATTRIBUTE->value, $transferType); + $templateTransfer->attributes[$propertyName] + = AttributeEmbeddedTemplateEnum::TYPE_ATTRIBUTE->renderTemplate($embeddedTypeTransfer); } - private function getPropertyType(DefinitionPropertyTransfer $propertyTransfer): string + private function getPropertyType(DefinitionEmbeddedTypeTransfer $embeddedTypeTransfer): string { - $propertyType = $propertyTransfer->transferType?->name ?: ''; - $namespaceTransfer = $propertyTransfer->transferType?->namespace; - - if ($namespaceTransfer === null) { - return $propertyType; + if ($embeddedTypeTransfer->namespace === null) { + return $embeddedTypeTransfer->name; } - return $this->enforceTransferInterface($propertyType); + return $this->enforceTransferInterface($embeddedTypeTransfer->name); } } diff --git a/src/TransferGenerator/Generator/Render/Template/Template.php b/src/TransferGenerator/Generator/Render/Template/Template.php index aadf14db..13596ecb 100644 --- a/src/TransferGenerator/Generator/Render/Template/Template.php +++ b/src/TransferGenerator/Generator/Render/Template/Template.php @@ -6,9 +6,6 @@ use Picamator\TransferObject\Generated\TemplateTransfer; -/** - * phpcs:disable Generic.Files.LineLength - */ readonly class Template { public function __construct(private TemplateHelperInterface $helper) @@ -19,14 +16,14 @@ public function __invoke(TemplateTransfer $templateTransfer): string { $this->helper->setTemplateTransfer($templateTransfer); - $fileContent = <<