diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml new file mode 100644 index 0000000..0c6c9a8 --- /dev/null +++ b/.github/workflows/pint.yml @@ -0,0 +1,34 @@ +name: Pint + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + pint: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.5' + + - name: Get composer cache + uses: actions/cache@v4 + with: + path: ~/.composer/cache + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + + - name: Install composer deps + run: composer install --no-progress --no-suggest --prefer-dist + + - name: Run Laravel Pint (test) + run: ./vendor/bin/pint --test diff --git a/.gitignore b/.gitignore index 0d884c8..a2a61fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /vendor -/.phpunit.result.cache \ No newline at end of file +/.phpunit.result.cache +/node_modules \ No newline at end of file diff --git a/composer.json b/composer.json index 16d3fad..d02474f 100644 --- a/composer.json +++ b/composer.json @@ -24,9 +24,31 @@ "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^12" + "phpunit/phpunit": "^12", + "laravel/pint": "^1.27", + "brainmaestro/composer-git-hooks": "^3.0" }, "scripts": { - "test": "phpunit" + "test": "phpunit", + "cghooks": "vendor/bin/cghooks", + "post-install-cmd": [ + "cghooks add --ignore-lock" + ], + "post-update-cmd": [ + "cghooks update" + ] + }, + "extra": { + "hooks": { + "pre-commit": [ + "./vendor/bin/pint --dirty", + "git add -A" + ] + } + }, + "config": { + "platform": { + "php": "8.3.30" + } } } diff --git a/composer.lock b/composer.lock index 981a2e3..504a249 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,149 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8d019dd40dabba605d62613558f070cf", + "content-hash": "7bc039a9e147a3ad7ec690d58fb5785b", "packages": [], "packages-dev": [ + { + "name": "brainmaestro/composer-git-hooks", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/BrainMaestro/composer-git-hooks.git", + "reference": "684dc85f480268baf5e13f39a3cc494eeb2536e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/684dc85f480268baf5e13f39a3cc494eeb2536e8", + "reference": "684dc85f480268baf5e13f39a3cc494eeb2536e8", + "shasum": "" + }, + "require": { + "php": "^8.0", + "symfony/console": "^5.0|^6.0|^7.0" + }, + "require-dev": { + "ext-json": "*", + "friendsofphp/php-cs-fixer": "^3.0", + "phpunit/phpunit": "^9|^10|^11" + }, + "bin": [ + "cghooks" + ], + "type": "library", + "extra": { + "hooks": { + "pre-push": [ + "composer test", + "appver=$(grep -o -E '[0-9]+\\.[0-9]+\\.[0-9]+(-alpha\\.[0-9]+)?' cghooks)", + "tag=$(git tag | tail -n 1)", + "tag=${tag#v}", + "if [ \"$tag\" != \"$appver\" ]; then", + "echo \"The most recent tag $tag does not match the application version $appver\\n\"", + "sed -i -E \"s/$appver/$tag/\" cghooks", + "exit 1", + "fi" + ], + "pre-commit": "composer check-style" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "BrainMaestro\\GitHooks\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ezinwa Okpoechi", + "email": "brainmaestro@outlook.com" + } + ], + "description": "Easily manage git hooks in your composer config", + "keywords": [ + "HOOK", + "composer", + "git" + ], + "support": { + "issues": "https://github.com/BrainMaestro/composer-git-hooks/issues", + "source": "https://github.com/BrainMaestro/composer-git-hooks/tree/v3.0.0" + }, + "time": "2024-06-22T09:17:59+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.27.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5", + "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.93.1", + "illuminate/view": "^12.51.0", + "larastan/larastan": "^3.9.2", + "laravel-zero/framework": "^12.0.5", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3.3", + "pestphp/pest": "^3.8.5" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "dev", + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2026-02-10T20:00:20+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.13.4", @@ -695,6 +835,59 @@ ], "time": "2026-02-18T12:38:40+00:00" }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, { "name": "sebastian/cli-parser", "version": "4.2.0", @@ -1645,64 +1838,745 @@ "time": "2024-10-20T05:08:20+00:00" }, { - "name": "theseer/tokenizer", - "version": "2.0.1", + "name": "symfony/console", + "version": "v7.4.7", "source": { "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" + "url": "https://github.com/symfony/console.git", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", - "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^8.1" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2|^8.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/2.0.1" + "source": "https://github.com/symfony/console/tree/v7.4.7" }, "funding": [ { - "url": "https://github.com/theseer", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-12-08T11:19:18+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=8.3" - }, - "platform-dev": {}, + "time": "2026-03-06T14:06:20+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:30:57+00:00" + }, + { + "name": "symfony/string", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.33", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-09T09:33:46+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-12-08T11:19:18+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.3" + }, + "platform-dev": {}, + "platform-overrides": { + "php": "8.3.30" + }, "plugin-api-version": "2.9.0" } diff --git a/package.json b/package.json new file mode 100644 index 0000000..258a5a4 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": {}, + "devDependencies": {}, + "scripts": {} +} diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..acf4398 --- /dev/null +++ b/pint.json @@ -0,0 +1,3 @@ +{ + "preset": "symfony" +} diff --git a/src/Attribute/Cast/CastDateTime.php b/src/Attribute/Cast/CastDateTime.php index 1970063..dc4545a 100644 --- a/src/Attribute/Cast/CastDateTime.php +++ b/src/Attribute/Cast/CastDateTime.php @@ -2,31 +2,29 @@ namespace Luimedi\Remap\Attribute\Cast; -use Attribute; -use DateTime; -use DateTimeInterface; use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class CastDateTime implements CastInterface { - public function __construct(protected ?string $format = DateTime::ATOM) + public function __construct(protected ?string $format = \DateTime::ATOM) { } public function cast(mixed $value, ContextInterface $context, MappingTargetInterface $mappingTarget): mixed { - if ($value instanceof DateTimeInterface) { - return $value->format(DateTime::ATOM); + if ($value instanceof \DateTimeInterface) { + return $value->format(\DateTime::ATOM); } if (is_string($value)) { - $date = new DateTime($value); - return $date->format(DateTime::ATOM); + $date = new \DateTime($value); + + return $date->format(\DateTime::ATOM); } return null; } -} \ No newline at end of file +} diff --git a/src/Attribute/Cast/CastDefault.php b/src/Attribute/Cast/CastDefault.php index e142d90..369ab9b 100644 --- a/src/Attribute/Cast/CastDefault.php +++ b/src/Attribute/Cast/CastDefault.php @@ -2,19 +2,16 @@ namespace Luimedi\Remap\Attribute\Cast; -use Attribute; -use DateTime; -use DateTimeInterface; use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class CastDefault implements CastInterface { /** - * @param mixed $default The default value to return if the input is null or empty. - * @param bool $strict If strict is true, only null values will be replaced by the default value. + * @param mixed $default the default value to return if the input is null or empty + * @param bool $strict If strict is true, only null values will be replaced by the default value. * Otherwise if strict is false, empty values (null, '', 0, false) will be replaced by the default value. */ public function __construct(protected mixed $default = null, protected bool $strict = false) @@ -24,16 +21,17 @@ public function __construct(protected mixed $default = null, protected bool $str public function cast(mixed $value, ContextInterface $context, MappingTargetInterface $mappingTarget): mixed { if ($this->strict) { - if (is_null($value) ) { + if (is_null($value)) { return $this->default; } + return $value; } if (empty($value)) { return $this->default; } - + return $value; } } diff --git a/src/Attribute/Cast/CastIterable.php b/src/Attribute/Cast/CastIterable.php index b9f9c4c..f07e703 100644 --- a/src/Attribute/Cast/CastIterable.php +++ b/src/Attribute/Cast/CastIterable.php @@ -2,13 +2,11 @@ namespace Luimedi\Remap\Attribute\Cast; -use ArrayIterator; -use Attribute; use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class CastIterable implements CastInterface { public function __construct(private string $class, private array $args = []) @@ -26,4 +24,4 @@ public function cast(mixed $value, ContextInterface $context, MappingTargetInter return $output; } -} \ No newline at end of file +} diff --git a/src/Attribute/Cast/CastTransformer.php b/src/Attribute/Cast/CastTransformer.php index b4e4e8e..8c9c2dd 100644 --- a/src/Attribute/Cast/CastTransformer.php +++ b/src/Attribute/Cast/CastTransformer.php @@ -2,13 +2,11 @@ namespace Luimedi\Remap\Attribute\Cast; -use Attribute; use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; -use Luimedi\Remap\Contracts\TransformerInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class CastTransformer implements CastInterface { public function cast(mixed $value, ContextInterface $context, MappingTargetInterface $mappingTarget): mixed @@ -18,9 +16,9 @@ public function cast(mixed $value, ContextInterface $context, MappingTargetInter $targetType = is_string($mappingTarget->getType()) && class_exists($mappingTarget->getType()) ? $mappingTarget->getType() : null; - + // If the value is null, nothing to map. - if ($value === null) { + if (null === $value) { return null; } diff --git a/src/Attribute/ConstructorMapper.php b/src/Attribute/ConstructorMapper.php index b173edf..1cc1b7d 100644 --- a/src/Attribute/ConstructorMapper.php +++ b/src/Attribute/ConstructorMapper.php @@ -5,14 +5,12 @@ use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MapInterface; +use Luimedi\Remap\Contracts\MappingTargetInterface; use Luimedi\Remap\Contracts\TransformerInterface; use Luimedi\Remap\Exception\MappingExecutionException; use Luimedi\Remap\Exception\MissingMappedValueException; use Luimedi\Remap\Exception\RemapException; use Luimedi\Remap\MappingTarget; -use Luimedi\Remap\Contracts\MappingTargetInterface; -use ReflectionClass; -use Throwable; #[\Attribute(\Attribute::TARGET_CLASS)] class ConstructorMapper implements TransformerInterface @@ -22,8 +20,8 @@ class ConstructorMapper implements TransformerInterface */ public function transform(mixed $source, mixed $target, ContextInterface $context, MappingTargetInterface $mappingTarget): mixed { - $reflectionClass = new ReflectionClass($target); - + $reflectionClass = new \ReflectionClass($target); + // If transform is invoked with an existing target object, populate it // rather than creating a new instance. This allows Engine to pre-register // placeholder instances for recursive mappings. @@ -37,12 +35,13 @@ public function transform(mixed $source, mixed $target, ContextInterface $contex /** * Creates a new instance of the target class by mapping its constructor parameters. * - * @param mixed $from The source object to map from. - * @param ReflectionClass $reflectionClass The reflection of the target class. - * @param ContextInterface $context The contextual information for the mapping process. - * @return mixed A new instance of the target class with mapped parameters. + * @param mixed $from the source object to map from + * @param \ReflectionClass $reflectionClass the reflection of the target class + * @param ContextInterface $context the contextual information for the mapping process + * + * @return mixed a new instance of the target class with mapped parameters */ - private function newInstance(mixed $from, ReflectionClass $reflectionClass, ContextInterface $context): mixed + private function newInstance(mixed $from, \ReflectionClass $reflectionClass, ContextInterface $context): mixed { $constructor = $reflectionClass->getConstructor(); $parameters = $constructor->getParameters(); @@ -56,7 +55,7 @@ private function newInstance(mixed $from, ReflectionClass $reflectionClass, Cont foreach ($attributes as $attribute) { $instance = $attribute->newInstance(); - + if ($instance instanceof MapInterface) { $type = null; $paramType = $parameter->getType(); @@ -67,7 +66,7 @@ private function newInstance(mixed $from, ReflectionClass $reflectionClass, Cont try { $parameterValues[$name] = $instance->map($from, $context, $target); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { $this->throwWithTrace($exception, $context, [ 'phase' => 'constructor.parameter.map', 'parameter' => $name, @@ -76,7 +75,7 @@ private function newInstance(mixed $from, ReflectionClass $reflectionClass, Cont } } } - }; + } return $reflectionClass->newInstanceArgs( $this->applyCasters($parameterValues, $parameters, $context)); @@ -85,7 +84,7 @@ private function newInstance(mixed $from, ReflectionClass $reflectionClass, Cont /** * Populate an existing instance (created without constructor) with mapped values. */ - private function populateInstance(mixed $from, ReflectionClass $reflectionClass, object $instance, ContextInterface $context): mixed + private function populateInstance(mixed $from, \ReflectionClass $reflectionClass, object $instance, ContextInterface $context): mixed { $constructor = $reflectionClass->getConstructor(); $parameters = $constructor->getParameters(); @@ -105,11 +104,11 @@ private function populateInstance(mixed $from, ReflectionClass $reflectionClass, if ($paramType && method_exists($paramType, 'getName')) { $type = $paramType->getName(); } - $target = new \Luimedi\Remap\MappingTarget($name, $type); + $target = new MappingTarget($name, $type); try { $parameterValues[$name] = $attrInstance->map($from, $context, $target); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { $this->throwWithTrace($exception, $context, [ 'phase' => 'constructor.parameter.map', 'parameter' => $name, @@ -151,11 +150,11 @@ private function populateInstance(mixed $from, ReflectionClass $reflectionClass, /** * Applies casters to the parameter values based on their attributes. * - * @param array $values The current parameter values. - * @param array<\ReflectionParameter> $parameters The constructor parameters. - * @param ContextInterface $context The context for the mapping process. - * - * @return array The parameter values after applying casters. + * @param array $values the current parameter values + * @param array<\ReflectionParameter> $parameters the constructor parameters + * @param ContextInterface $context the context for the mapping process + * + * @return array the parameter values after applying casters */ protected function applyCasters(array $values, array $parameters, ContextInterface $context): array { @@ -165,7 +164,7 @@ protected function applyCasters(array $values, array $parameters, ContextInterfa foreach ($attributes as $attribute) { $instance = $attribute->newInstance(); - + if ($instance instanceof CastInterface) { if (!array_key_exists($name, $values)) { $this->throwWithTrace( @@ -190,7 +189,7 @@ protected function applyCasters(array $values, array $parameters, ContextInterfa try { $values[$name] = $instance->cast($values[$name], $context, $target); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { $this->throwWithTrace($exception, $context, [ 'phase' => 'constructor.parameter.cast', 'parameter' => $name, @@ -207,7 +206,7 @@ protected function applyCasters(array $values, array $parameters, ContextInterfa /** * @param array $step */ - private function throwWithTrace(Throwable $exception, ContextInterface $context, array $step): never + private function throwWithTrace(\Throwable $exception, ContextInterface $context, array $step): never { $trace = $context->get('__mapping_trace__', []); $trace[] = $step; diff --git a/src/Attribute/MapGetter.php b/src/Attribute/MapGetter.php index 5c73655..77fb4eb 100644 --- a/src/Attribute/MapGetter.php +++ b/src/Attribute/MapGetter.php @@ -2,26 +2,24 @@ namespace Luimedi\Remap\Attribute; -use Attribute; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MapInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; use Luimedi\Remap\Exception\MapGetterResolutionException; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class MapGetter implements MapInterface { public function __construct(protected ?string $source = null) { - // } public function map(mixed $from, ContextInterface $context, MappingTargetInterface $target): mixed { $method = $this->source; - if ($method === null) { - $getterMethod = 'get' . ucfirst($target->getName()); + if (null === $method) { + $getterMethod = 'get'.ucfirst($target->getName()); if (is_object($from) && method_exists($from, $getterMethod)) { $method = $getterMethod; diff --git a/src/Attribute/MapProperty.php b/src/Attribute/MapProperty.php index 12f5b67..6918e68 100644 --- a/src/Attribute/MapProperty.php +++ b/src/Attribute/MapProperty.php @@ -2,18 +2,16 @@ namespace Luimedi\Remap\Attribute; -use Attribute; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MapInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; use Luimedi\Remap\Helpers\Data; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class MapProperty implements MapInterface { public function __construct(protected ?string $source = null) { - // } public function map(mixed $from, ContextInterface $context, MappingTargetInterface $target): mixed diff --git a/src/Attribute/PropertyMapper.php b/src/Attribute/PropertyMapper.php index 0f8736f..97be7d8 100644 --- a/src/Attribute/PropertyMapper.php +++ b/src/Attribute/PropertyMapper.php @@ -5,14 +5,11 @@ use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MapInterface; +use Luimedi\Remap\Contracts\MappingTargetInterface; use Luimedi\Remap\Contracts\TransformerInterface; use Luimedi\Remap\Exception\MappingExecutionException; use Luimedi\Remap\Exception\RemapException; use Luimedi\Remap\MappingTarget; -use Luimedi\Remap\Contracts\MappingTargetInterface; -use ReflectionClass; -use ReflectionProperty; -use Throwable; #[\Attribute(\Attribute::TARGET_CLASS)] class PropertyMapper implements TransformerInterface @@ -22,8 +19,8 @@ class PropertyMapper implements TransformerInterface */ public function transform(mixed $source, mixed $target, ContextInterface $context, MappingTargetInterface $mappingTarget): mixed { - $reflectionClass = new ReflectionClass($target); - $properties = $reflectionClass->getProperties(ReflectionProperty::IS_PUBLIC); + $reflectionClass = new \ReflectionClass($target); + $properties = $reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC); $instance = is_string($target) ? new $target() : $target; foreach ($properties as $property) { @@ -42,7 +39,7 @@ public function transform(mixed $source, mixed $target, ContextInterface $contex if ($attribute instanceof CastInterface) { try { $value = $attribute->cast($value, $context, $propTarget); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { $this->throwWithTrace($exception, $context, [ 'phase' => 'property.cast', 'property' => $property->getName(), @@ -52,7 +49,7 @@ public function transform(mixed $source, mixed $target, ContextInterface $contex } elseif ($attribute instanceof MapInterface) { try { $value = $attribute->map($source, $context, $propTarget); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { $this->throwWithTrace($exception, $context, [ 'phase' => 'property.map', 'property' => $property->getName(), @@ -64,7 +61,7 @@ public function transform(mixed $source, mixed $target, ContextInterface $contex try { $property->setValue($instance, $value); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { $this->throwWithTrace($exception, $context, [ 'phase' => 'property.set', 'property' => $property->getName(), @@ -78,10 +75,10 @@ public function transform(mixed $source, mixed $target, ContextInterface $contex /** * Retrieves valid mapping and casting attributes from a property. * It sort them so that MapInterface are before CastInterface. - * + * * @return array */ - private function getValidAttributes(ReflectionProperty $property): array + private function getValidAttributes(\ReflectionProperty $property): array { $validAttributes = []; $attributes = $property->getAttributes(); @@ -90,7 +87,7 @@ private function getValidAttributes(ReflectionProperty $property): array $instance = $attribute->newInstance(); if ( - $instance instanceof MapInterface + $instance instanceof MapInterface || $instance instanceof CastInterface ) { $validAttributes[] = $instance; @@ -103,6 +100,7 @@ private function getValidAttributes(ReflectionProperty $property): array } elseif ($a instanceof MapInterface && $b instanceof CastInterface) { return -1; // Maps before Casts } + return 0; }); @@ -112,7 +110,7 @@ private function getValidAttributes(ReflectionProperty $property): array /** * @param array $step */ - private function throwWithTrace(Throwable $exception, ContextInterface $context, array $step): never + private function throwWithTrace(\Throwable $exception, ContextInterface $context, array $step): never { $trace = $context->get('__mapping_trace__', []); $trace[] = $step; diff --git a/src/Context.php b/src/Context.php index 7d7f43c..9404756 100644 --- a/src/Context.php +++ b/src/Context.php @@ -2,11 +2,8 @@ namespace Luimedi\Remap; -use ArrayIterator; use Luimedi\Remap\Contracts\ContextInterface; -use Traversable; - class Context implements ContextInterface { protected array $data = []; @@ -36,9 +33,9 @@ public function count(): int return count($this->data); } - public function getIterator(): Traversable + public function getIterator(): \Traversable { - return new ArrayIterator($this->data); + return new \ArrayIterator($this->data); } public function offsetExists(mixed $offset): bool diff --git a/src/Contracts/CastInterface.php b/src/Contracts/CastInterface.php index 7661de9..95ff0a0 100644 --- a/src/Contracts/CastInterface.php +++ b/src/Contracts/CastInterface.php @@ -2,9 +2,6 @@ namespace Luimedi\Remap\Contracts; -use Luimedi\Remap\Contracts\ContextInterface; -use Luimedi\Remap\Contracts\MappingTargetInterface; - interface CastInterface { public function cast(mixed $value, ContextInterface $context, MappingTargetInterface $mappingTarget): mixed; diff --git a/src/Contracts/ContextInterface.php b/src/Contracts/ContextInterface.php index ea0a563..320cac3 100644 --- a/src/Contracts/ContextInterface.php +++ b/src/Contracts/ContextInterface.php @@ -4,9 +4,8 @@ use Countable; use IteratorAggregate; -use ArrayAccess; -interface ContextInterface extends ArrayAccess, IteratorAggregate, Countable +interface ContextInterface extends \ArrayAccess, IteratorAggregate, Countable { public function set(string $key, mixed $value): void; diff --git a/src/Contracts/EngineInterface.php b/src/Contracts/EngineInterface.php index ac8cb9f..39a9495 100644 --- a/src/Contracts/EngineInterface.php +++ b/src/Contracts/EngineInterface.php @@ -10,26 +10,26 @@ interface EngineInterface { /** * Binds a source type to a target type or a resolver function. - * - * @param string $abstract The source type (class name or 'type:'). - * @param string|callable($object, ContextInterface $context):string $resolver The target type (class name) or a resolver function. - * + * + * @param string $abstract the source type (class name or 'type:') + * @param string|callable($object, ContextInterface $context):string $resolver The target type (class name) or a resolver function + * * @return $this */ public function bind(string $abstract, string|callable $resolver): static; /** * Resolves the target type for the given object. - * - * @throws BindingNotFoundException if no binding is found. - * @throws BindingResolutionException if a binding cannot be resolved. + * + * @throws BindingNotFoundException if no binding is found + * @throws BindingResolutionException if a binding cannot be resolved */ public function resolve(mixed $object, ContextInterface $context): string; /** * Executes the mapping from the source object to an instance of the target type. - * - * @throws InvalidTargetTypeException if the target type cannot be instantiated. + * + * @throws InvalidTargetTypeException if the target type cannot be instantiated */ public function execute(mixed $from, string $type, ContextInterface $context): mixed; } diff --git a/src/Contracts/MapInterface.php b/src/Contracts/MapInterface.php index 4fc81d4..9d0404a 100644 --- a/src/Contracts/MapInterface.php +++ b/src/Contracts/MapInterface.php @@ -2,9 +2,6 @@ namespace Luimedi\Remap\Contracts; -use Luimedi\Remap\Contracts\ContextInterface; -use Luimedi\Remap\Contracts\MappingTargetInterface; - interface MapInterface { public function map(mixed $from, ContextInterface $context, MappingTargetInterface $target): mixed; diff --git a/src/Contracts/TransformerInterface.php b/src/Contracts/TransformerInterface.php index 780b029..f704464 100644 --- a/src/Contracts/TransformerInterface.php +++ b/src/Contracts/TransformerInterface.php @@ -2,9 +2,6 @@ namespace Luimedi\Remap\Contracts; -use Luimedi\Remap\Contracts\ContextInterface; -use Luimedi\Remap\Contracts\MappingTargetInterface; - interface TransformerInterface { /** diff --git a/src/Engine.php b/src/Engine.php index aad5957..bbee5a4 100644 --- a/src/Engine.php +++ b/src/Engine.php @@ -2,18 +2,14 @@ namespace Luimedi\Remap; +use Luimedi\Remap\Contracts\ContextInterface; +use Luimedi\Remap\Contracts\EngineInterface; +use Luimedi\Remap\Contracts\TransformerInterface; use Luimedi\Remap\Exception\BindingNotFoundException; use Luimedi\Remap\Exception\BindingResolutionException; use Luimedi\Remap\Exception\InvalidTargetTypeException; use Luimedi\Remap\Exception\MappingExecutionException; use Luimedi\Remap\Exception\RemapException; -use Luimedi\Remap\Contracts\EngineInterface; -use Luimedi\Remap\Contracts\TransformerInterface; -use Luimedi\Remap\Contracts\ContextInterface; -use Luimedi\Remap\MappingTarget; -use ReflectionClass; -use ReflectionException; -use Throwable; class Engine implements EngineInterface { @@ -24,27 +20,28 @@ class Engine implements EngineInterface /** * Binds a source type to a target type or a resolver function. - * - * @param string $abstract The source type (class name or 'type:'). - * @param string|callable($object, ContextInterface $context):string $resolver The target type (class name) or a resolver function. - * + * + * @param string $abstract the source type (class name or 'type:') + * @param string|callable($object, ContextInterface $context):string $resolver The target type (class name) or a resolver function + * * @return $this */ public function bind(string $abstract, string|callable $resolver): static { $this->bindings[$abstract] = $resolver; + return $this; } /** * Resolves the target type for the given object. - * - * @throws BindingNotFoundException if no binding is found. - * @throws BindingResolutionException if a binding cannot be resolved to a valid class name. + * + * @throws BindingNotFoundException if no binding is found + * @throws BindingResolutionException if a binding cannot be resolved to a valid class name */ public function resolve(mixed $object, ContextInterface $context): string { - $type = is_object($object) ? get_class($object) : 'type:' . gettype($object); + $type = is_object($object) ? get_class($object) : 'type:'.gettype($object); $trace = [[ 'phase' => 'resolve', 'sourceType' => $type, @@ -63,8 +60,7 @@ public function resolve(mixed $object, ContextInterface $context): string return $resolvedType; } - throw BindingResolutionException::forType($type, $resolvedType) - ->appendMappingTrace($trace); + throw BindingResolutionException::forType($type, $resolvedType)->appendMappingTrace($trace); } if (is_string($resolver) && class_exists($resolver)) { @@ -76,8 +72,8 @@ public function resolve(mixed $object, ContextInterface $context): string /** * Executes the mapping process from the source object to an instance of the target type. - * - * @throws InvalidTargetTypeException if the target type cannot be instantiated. + * + * @throws InvalidTargetTypeException if the target type cannot be instantiated */ public function execute(mixed $from, string $type, ContextInterface $context): mixed { @@ -87,8 +83,8 @@ public function execute(mixed $from, string $type, ContextInterface $context): m 'sourceType' => is_object($from) ? get_class($from) : gettype($from), ], function () use ($from, $type, $context) { try { - $reflectionClass = new ReflectionClass($type); - } catch (ReflectionException $exception) { + $reflectionClass = new \ReflectionClass($type); + } catch (\ReflectionException $exception) { throw InvalidTargetTypeException::forType($type, $exception); } @@ -96,8 +92,8 @@ public function execute(mixed $from, string $type, ContextInterface $context): m $instance = null; - // If the source is an object, prepare a registry mapping so recursive - // references can return the already-created target instance. + // If the source is an object, prepare a registry mapping so recursive + // references can return the already-created target instance. if (is_object($from)) { $id = spl_object_hash($from); $registry = $context->get('__mapping_registry__', []); @@ -110,7 +106,7 @@ public function execute(mixed $from, string $type, ContextInterface $context): m // it can be returned for recursive references during mapping. try { $instance = $reflectionClass->newInstanceWithoutConstructor(); - } catch (ReflectionException $exception) { + } catch (\ReflectionException $exception) { throw InvalidTargetTypeException::forType($type, $exception); } @@ -166,7 +162,7 @@ private function withMappingStep(ContextInterface $context, array $step, callabl try { return $callback(); - } catch (Throwable $exception) { + } catch (\Throwable $exception) { throw $this->enrichException($exception, $trace); } finally { $finalTrace = $context->get('__mapping_trace__', []); @@ -178,7 +174,7 @@ private function withMappingStep(ContextInterface $context, array $step, callabl /** * @param array> $trace */ - private function enrichException(Throwable $exception, array $trace): RemapException + private function enrichException(\Throwable $exception, array $trace): RemapException { if ($exception instanceof RemapException) { return $exception->appendMappingTrace($trace); @@ -186,4 +182,4 @@ private function enrichException(Throwable $exception, array $trace): RemapExcep return MappingExecutionException::fromThrowable($exception, $trace); } -} \ No newline at end of file +} diff --git a/src/Exception/InvalidTargetTypeException.php b/src/Exception/InvalidTargetTypeException.php index 25317ea..4584154 100644 --- a/src/Exception/InvalidTargetTypeException.php +++ b/src/Exception/InvalidTargetTypeException.php @@ -2,11 +2,9 @@ namespace Luimedi\Remap\Exception; -use Throwable; - class InvalidTargetTypeException extends RemapException { - public static function forType(string $type, ?Throwable $previous = null): self + public static function forType(string $type, ?\Throwable $previous = null): self { return new self("Cannot instantiate mapping target type '{$type}'", 0, $previous); } diff --git a/src/Exception/MappingExecutionException.php b/src/Exception/MappingExecutionException.php index d20e8fc..846fa36 100644 --- a/src/Exception/MappingExecutionException.php +++ b/src/Exception/MappingExecutionException.php @@ -2,18 +2,16 @@ namespace Luimedi\Remap\Exception; -use Throwable; - class MappingExecutionException extends RemapException { /** * @param array> $mappingTrace */ - public static function fromThrowable(Throwable $previous, array $mappingTrace = []): self + public static function fromThrowable(\Throwable $previous, array $mappingTrace = []): self { $message = sprintf( 'Mapping execution failed: %s', - $previous->getMessage() !== '' ? $previous->getMessage() : $previous::class + '' !== $previous->getMessage() ? $previous->getMessage() : $previous::class ); return new self($message, 0, $previous, $mappingTrace); diff --git a/src/Exception/RemapException.php b/src/Exception/RemapException.php index 360d89b..0d35bb2 100644 --- a/src/Exception/RemapException.php +++ b/src/Exception/RemapException.php @@ -2,10 +2,7 @@ namespace Luimedi\Remap\Exception; -use RuntimeException; -use Throwable; - -abstract class RemapException extends RuntimeException +abstract class RemapException extends \RuntimeException { /** * @var array> @@ -15,7 +12,7 @@ abstract class RemapException extends RuntimeException /** * @param array> $mappingTrace */ - public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null, array $mappingTrace = []) + public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, array $mappingTrace = []) { parent::__construct($message, $code, $previous); $this->mappingTrace = $mappingTrace; @@ -26,7 +23,7 @@ public function __construct(string $message = '', int $code = 0, ?Throwable $pre */ public function appendMappingTrace(array $trace): static { - if ($trace === []) { + if ([] === $trace) { return $this; } diff --git a/src/Mapper.php b/src/Mapper.php index 1733fe8..121969d 100644 --- a/src/Mapper.php +++ b/src/Mapper.php @@ -2,13 +2,12 @@ namespace Luimedi\Remap; -use ArrayIterator; use Iterator; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\EngineInterface; use Luimedi\Remap\Exception\RemapException; -class Mapper +class Mapper { /** * This holds contextual information for the mapping process. @@ -17,7 +16,7 @@ class Mapper protected ContextInterface $context; /** - * The engine responsible for executing the mapping reading + * The engine responsible for executing the mapping reading * the attributes from the target class. */ protected EngineInterface $engine; @@ -33,15 +32,16 @@ public function __construct(?ContextInterface $context = null, ?EngineInterface /** * Binds a source type to a target type or a resolver function. - * - * @param string $abstract The source type (class name or 'type:'). - * @param string|callable($object, Context $context):string $resolver The target type (class name) or a resolver function. - * + * + * @param string $abstract the source type (class name or 'type:') + * @param string|callable($object, Context $context):string $resolver The target type (class name) or a resolver function + * * @return $this */ public function bind(string $abstract, string|callable $resolver): static { $this->engine->bind($abstract, $resolver); + return $this; } @@ -51,6 +51,7 @@ public function bind(string $abstract, string|callable $resolver): static public function withContext(string $key, mixed $value): static { $this->context->set($key, $value); + return $this; } @@ -75,11 +76,11 @@ public function getContext(): ContextInterface /** * Maps the given object to its target type. - * - * @param mixed $from The source object to be mapped. - * @param array $data Additional contextual data for this mapping operation. - * - * @throws RemapException if mapping cannot be resolved or executed. + * + * @param mixed $from the source object to be mapped + * @param array $data additional contextual data for this mapping operation + * + * @throws RemapException if mapping cannot be resolved or executed */ public function map(mixed $from, array $data = []): mixed { @@ -91,11 +92,10 @@ public function map(mixed $from, array $data = []): mixed /** * Maps the given iterable to its target type, returning an iterator. - * - * @param mixed $iterable The source iterable to be mapped. - * @param array $data Additional contextual data for this mapping operation. - * - * @throws RemapException if mapping cannot be resolved or executed. + * + * @param array $data additional contextual data for this mapping operation + * + * @throws RemapException if mapping cannot be resolved or executed */ public function mapAsIterable(iterable $from, array $data = []): array { diff --git a/src/MappingTarget.php b/src/MappingTarget.php index 0e01191..9c4f470 100644 --- a/src/MappingTarget.php +++ b/src/MappingTarget.php @@ -8,8 +8,9 @@ class MappingTarget implements MappingTargetInterface { public function __construct( private string $name, - private ?string $type = null - ) {} + private ?string $type = null, + ) { + } public function getName(): string { diff --git a/tests/ArrayRecursiveTest/ArrayInput.php b/tests/ArrayRecursiveTest/ArrayInput.php index 02d4027..4b8397e 100644 --- a/tests/ArrayRecursiveTest/ArrayInput.php +++ b/tests/ArrayRecursiveTest/ArrayInput.php @@ -8,9 +8,9 @@ class ArrayInput public array $children = []; public function __construct( - public string $name, - ?ArrayInput $parent = null, - array $children = [] + public string $name, + ?ArrayInput $parent = null, + array $children = [], ) { $this->parent = $parent; $this->children = $children; diff --git a/tests/ArrayRecursiveTest/ArrayOutput.php b/tests/ArrayRecursiveTest/ArrayOutput.php index d6caa3b..68e87c2 100644 --- a/tests/ArrayRecursiveTest/ArrayOutput.php +++ b/tests/ArrayRecursiveTest/ArrayOutput.php @@ -2,10 +2,10 @@ namespace Tests\ArrayRecursiveTest; -use Luimedi\Remap\Attribute\PropertyMapper; -use Luimedi\Remap\Attribute\MapProperty; use Luimedi\Remap\Attribute\Cast\CastIterable; use Luimedi\Remap\Attribute\Cast\CastTransformer; +use Luimedi\Remap\Attribute\MapProperty; +use Luimedi\Remap\Attribute\PropertyMapper; #[PropertyMapper] class ArrayOutput diff --git a/tests/ArrayRecursiveTest/ArrayRecursiveTest.php b/tests/ArrayRecursiveTest/ArrayRecursiveTest.php index fb83fa9..b779566 100644 --- a/tests/ArrayRecursiveTest/ArrayRecursiveTest.php +++ b/tests/ArrayRecursiveTest/ArrayRecursiveTest.php @@ -2,8 +2,8 @@ namespace Tests\ArrayRecursiveTest; -use PHPUnit\Framework\TestCase; use Luimedi\Remap\Mapper; +use PHPUnit\Framework\TestCase; class ArrayRecursiveTest extends TestCase { diff --git a/tests/ArrayRecursiveTest/MixedArrayTest.php b/tests/ArrayRecursiveTest/MixedArrayTest.php index 21ef1d4..a6fa418 100644 --- a/tests/ArrayRecursiveTest/MixedArrayTest.php +++ b/tests/ArrayRecursiveTest/MixedArrayTest.php @@ -2,8 +2,8 @@ namespace Tests\ArrayRecursiveTest; -use PHPUnit\Framework\TestCase; use Luimedi\Remap\Mapper; +use PHPUnit\Framework\TestCase; class MixedArrayTest extends TestCase { diff --git a/tests/CastDefaultTest/CastDefaultTest.php b/tests/CastDefaultTest/CastDefaultTest.php index e5aab47..ae75dd4 100644 --- a/tests/CastDefaultTest/CastDefaultTest.php +++ b/tests/CastDefaultTest/CastDefaultTest.php @@ -7,11 +7,6 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use Tests\CastDefaultTest\Input; -use Tests\CastDefaultTest\OutputNonStrict; -use Tests\CastDefaultTest\OutputStrict; -use Tests\CastDefaultTest\OutputCasterMissing; - class CastDefaultTest extends TestCase { #[DataProvider('nonStrictEmptyValuesProvider')] diff --git a/tests/CastDefaultTest/Input.php b/tests/CastDefaultTest/Input.php index b93ca37..1d38290 100644 --- a/tests/CastDefaultTest/Input.php +++ b/tests/CastDefaultTest/Input.php @@ -4,5 +4,7 @@ class Input { - public function __construct(public mixed $maybe) {} + public function __construct(public mixed $maybe) + { + } } diff --git a/tests/CastDefaultTest/OutputCasterMissing.php b/tests/CastDefaultTest/OutputCasterMissing.php index 2587e9c..9aacbac 100644 --- a/tests/CastDefaultTest/OutputCasterMissing.php +++ b/tests/CastDefaultTest/OutputCasterMissing.php @@ -2,14 +2,15 @@ namespace Tests\CastDefaultTest; -use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\Cast\CastDefault; +use Luimedi\Remap\Attribute\ConstructorMapper; #[ConstructorMapper] class OutputCasterMissing { public function __construct( #[CastDefault(default: 'fallback')] - public mixed $maybe - ) {} + public mixed $maybe, + ) { + } } diff --git a/tests/CastDefaultTest/OutputNonStrict.php b/tests/CastDefaultTest/OutputNonStrict.php index ce7e2ea..6a3400f 100644 --- a/tests/CastDefaultTest/OutputNonStrict.php +++ b/tests/CastDefaultTest/OutputNonStrict.php @@ -2,8 +2,8 @@ namespace Tests\CastDefaultTest; -use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\Cast\CastDefault; +use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\MapProperty; #[ConstructorMapper] @@ -12,6 +12,7 @@ class OutputNonStrict public function __construct( #[MapProperty(source: 'maybe')] #[CastDefault(default: 'fallback', strict: false)] - public string $maybe - ) {} + public string $maybe, + ) { + } } diff --git a/tests/CastDefaultTest/OutputStrict.php b/tests/CastDefaultTest/OutputStrict.php index 4fa301c..08d5f42 100644 --- a/tests/CastDefaultTest/OutputStrict.php +++ b/tests/CastDefaultTest/OutputStrict.php @@ -2,8 +2,8 @@ namespace Tests\CastDefaultTest; -use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\Cast\CastDefault; +use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\MapProperty; #[ConstructorMapper] @@ -12,6 +12,7 @@ class OutputStrict public function __construct( #[MapProperty(source: 'maybe')] #[CastDefault(default: 'fallback', strict: true)] - public mixed $maybe - ) {} + public mixed $maybe, + ) { + } } diff --git a/tests/DataObjectTest/DataObjectTest.php b/tests/DataObjectTest/DataObjectTest.php index 51a5655..426d468 100644 --- a/tests/DataObjectTest/DataObjectTest.php +++ b/tests/DataObjectTest/DataObjectTest.php @@ -5,10 +5,6 @@ use Luimedi\Remap\Helpers\Data; use PHPUnit\Framework\TestCase; -use Tests\DataObjectTest\Inner; -use Tests\DataObjectTest\User; -use Tests\DataObjectTest\Root; - class DataObjectTest extends TestCase { public function testGetObjectNestedProperty() diff --git a/tests/DataTest.php b/tests/DataTest.php index 1ec1e2b..5adda57 100644 --- a/tests/DataTest.php +++ b/tests/DataTest.php @@ -12,9 +12,9 @@ public function testGetData() 'user' => [ 'name' => 'Alice', 'address' => [ - 'city' => 'Wonderland' - ] - ] + 'city' => 'Wonderland', + ], + ], ]; $city = Data::get($data, 'user.address.city'); @@ -28,4 +28,4 @@ public function testGetData() $this->assertSame($data['user']['address']['city'], 'Wonderland'); } -} \ No newline at end of file +} diff --git a/tests/EngineTest/EngineTest.php b/tests/EngineTest/EngineTest.php index 0971484..081ac49 100644 --- a/tests/EngineTest/EngineTest.php +++ b/tests/EngineTest/EngineTest.php @@ -25,7 +25,7 @@ public static function callableResolverProvider(): array { return [ 'simple resolver' => [ - fn($obj, $ctx) => Output::class, + fn ($obj, $ctx) => Output::class, Output::class, ], 'context-aware resolver' => [ @@ -48,7 +48,7 @@ public function testResolveThrowsWhenNoBinding() } catch (BindingNotFoundException $exception) { // Verify exception details $this->assertStringContainsString('No binding found', $exception->getMessage()); - + // Verify mapping trace $trace = $exception->getMappingTrace(); $this->assertNotEmpty($trace); @@ -67,7 +67,7 @@ public function testLibraryExceptionsCanBeCaughtByBaseRemapException() } catch (RemapException $exception) { $this->assertInstanceOf(RemapException::class, $exception); $this->assertInstanceOf(BindingNotFoundException::class, $exception); - + // Verify we can get trace and previous exception info $this->assertIsArray($exception->getMappingTrace()); } @@ -82,7 +82,7 @@ public function testContextPreservationAcrossMappings() $result = $mapper->map(new Input()); $this->assertInstanceOf(Output::class, $result); - + // Context should be preserved in the mapper $context = $mapper->getContext(); $this->assertSame('test_value', $context->get('test_key')); diff --git a/tests/ExceptionTest/ExceptionTest.php b/tests/ExceptionTest/ExceptionTest.php index bef9407..026d5d1 100644 --- a/tests/ExceptionTest/ExceptionTest.php +++ b/tests/ExceptionTest/ExceptionTest.php @@ -77,7 +77,7 @@ public function testBindingResolutionExceptionWithCallableReturningNonString() $this->fail('Expected BindingResolutionException'); } catch (BindingResolutionException $exception) { $this->assertStringContainsString('Cannot resolve binding', $exception->getMessage()); - + $trace = $exception->getMappingTrace(); $this->assertNotEmpty($trace); } @@ -86,7 +86,7 @@ public function testBindingResolutionExceptionWithCallableReturningNonString() public function testInvalidTargetTypeException() { $mapper = new Mapper(); - + // Bind to an abstract class that cannot be instantiated // This will throw MappingExecutionException wrapping the Error from newInstanceWithoutConstructor $mapper->bind(ValidSource::class, AbstractTarget::class); @@ -105,7 +105,7 @@ public function testInvalidTargetTypeException() $trace = $exception->getMappingTrace(); $this->assertNotEmpty($trace); - $executeStep = array_values(array_filter($trace, fn($s) => ($s['phase'] ?? null) === 'execute')); + $executeStep = array_values(array_filter($trace, fn ($s) => ($s['phase'] ?? null) === 'execute')); $this->assertNotEmpty($executeStep); $this->assertArrayHasKey('targetType', $executeStep[0]); } @@ -114,16 +114,16 @@ public function testInvalidTargetTypeException() public function testInvalidTargetTypeExceptionForInternalClass() { $mapper = new Mapper(); - + // Try to map to an internal class that may cause reflection issues // Using a callable to bypass initial class_exists check - $mapper->bind(ValidSource::class, fn() => \PDO::class); + $mapper->bind(ValidSource::class, fn () => \PDO::class); try { $result = $mapper->map(new ValidSource()); // PDO might actually work, so we just verify it doesn't throw our custom exception $this->assertInstanceOf(\PDO::class, $result); - } catch (InvalidTargetTypeException | MappingExecutionException $exception) { + } catch (InvalidTargetTypeException|MappingExecutionException $exception) { // Either exception is acceptable for this edge case $this->assertNotEmpty($exception->getMappingTrace()); } @@ -145,8 +145,7 @@ public function testMapGetterResolutionException() $trace = $exception->getMappingTrace(); $this->assertNotEmpty($trace); - $propertyMapStep = array_values(array_filter($trace, fn($s) => - ($s['phase'] ?? null) === 'property.map' + $propertyMapStep = array_values(array_filter($trace, fn ($s) => ($s['phase'] ?? null) === 'property.map' )); $this->assertNotEmpty($propertyMapStep); $this->assertSame('missingMethod', $propertyMapStep[0]['property'] ?? null); @@ -167,8 +166,7 @@ public function testMissingMappedValueException() $trace = $exception->getMappingTrace(); $this->assertNotEmpty($trace); - $castStep = array_values(array_filter($trace, fn($s) => - ($s['phase'] ?? null) === 'constructor.parameter.cast' + $castStep = array_values(array_filter($trace, fn ($s) => ($s['phase'] ?? null) === 'constructor.parameter.cast' )); $this->assertNotEmpty($castStep); $this->assertArrayHasKey('parameter', $castStep[0]); @@ -195,10 +193,9 @@ public function testMappingExecutionExceptionWrapsUnknownErrors() // Verify trace $trace = $exception->getMappingTrace(); $this->assertNotEmpty($trace); - + // Should have the cast phase where it failed - $castStep = array_values(array_filter($trace, fn($s) => - str_contains($s['phase'] ?? '', 'cast') + $castStep = array_values(array_filter($trace, fn ($s) => str_contains($s['phase'] ?? '', 'cast') )); $this->assertNotEmpty($castStep, 'Should have a cast step in trace'); } @@ -229,7 +226,7 @@ public static function allExceptionClassesProvider(): array public function testMappingTraceCanBeAppended() { $exception = BindingNotFoundException::forType('SomeType'); - + $this->assertEmpty($exception->getMappingTrace()); $exception->appendMappingTrace([ @@ -255,7 +252,7 @@ public function testMappingTraceCanBeAppended() public function testMappingTraceDeduplicatesSteps() { $exception = BindingNotFoundException::forType('SomeType'); - + $step = ['phase' => 'duplicate', 'data' => 'same']; $exception->appendMappingTrace([$step]); diff --git a/tests/ExceptionTest/TargetThatThrowsInConstructor.php b/tests/ExceptionTest/TargetThatThrowsInConstructor.php index cf86336..8cba38d 100644 --- a/tests/ExceptionTest/TargetThatThrowsInConstructor.php +++ b/tests/ExceptionTest/TargetThatThrowsInConstructor.php @@ -10,7 +10,7 @@ class TargetThatThrowsInConstructor { public function __construct( #[MapProperty(source: 'data')] - public string $data + public string $data, ) { throw new \RuntimeException('Constructor error'); } diff --git a/tests/ExceptionTest/TargetWithCasterOnly.php b/tests/ExceptionTest/TargetWithCasterOnly.php index 750bc8f..e86d535 100644 --- a/tests/ExceptionTest/TargetWithCasterOnly.php +++ b/tests/ExceptionTest/TargetWithCasterOnly.php @@ -10,6 +10,7 @@ class TargetWithCasterOnly { public function __construct( #[CastDefault(default: 'fallback')] - public string $value - ) {} + public string $value, + ) { + } } diff --git a/tests/ExceptionTest/TargetWithPropertyThatThrows.php b/tests/ExceptionTest/TargetWithPropertyThatThrows.php index 905fd35..bc49658 100644 --- a/tests/ExceptionTest/TargetWithPropertyThatThrows.php +++ b/tests/ExceptionTest/TargetWithPropertyThatThrows.php @@ -11,6 +11,7 @@ class TargetWithPropertyThatThrows public function __construct( #[MapProperty(source: 'data')] #[ThrowingCaster] - public string $data - ) {} + public string $data, + ) { + } } diff --git a/tests/ExceptionTest/ThrowingCaster.php b/tests/ExceptionTest/ThrowingCaster.php index 10eaf80..77162fc 100644 --- a/tests/ExceptionTest/ThrowingCaster.php +++ b/tests/ExceptionTest/ThrowingCaster.php @@ -2,12 +2,11 @@ namespace Tests\ExceptionTest; -use Attribute; use Luimedi\Remap\Contracts\CastInterface; use Luimedi\Remap\Contracts\ContextInterface; use Luimedi\Remap\Contracts\MappingTargetInterface; -#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::TARGET_PROPERTY)] class ThrowingCaster implements CastInterface { public function cast(mixed $value, ContextInterface $context, MappingTargetInterface $target): mixed diff --git a/tests/MapperTest/Input.php b/tests/MapperTest/Input.php index bd985bf..7241f15 100644 --- a/tests/MapperTest/Input.php +++ b/tests/MapperTest/Input.php @@ -2,18 +2,17 @@ namespace Tests\MapperTest; -use DateTimeInterface; - class Input { public $nested = [ - 'body' => 'example body' + 'body' => 'example body', ]; - + public function __construct( public string $name, - public DateTimeInterface $birthdate, - ) {} + public \DateTimeInterface $birthdate, + ) { + } public function type(): string { diff --git a/tests/MapperTest/MapperTest.php b/tests/MapperTest/MapperTest.php index fd1c5cd..d4946ea 100644 --- a/tests/MapperTest/MapperTest.php +++ b/tests/MapperTest/MapperTest.php @@ -2,7 +2,6 @@ namespace Tests\MapperTest; -use DateTimeImmutable; use Luimedi\Remap\Mapper; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -10,13 +9,13 @@ class MapperTest extends TestCase { #[DataProvider('mappingInputProvider')] - public function testGeneralBinding(string $name, DateTimeImmutable $birthdate, string $expectedDate) + public function testGeneralBinding(string $name, \DateTimeImmutable $birthdate, string $expectedDate) { $mapper = new Mapper(); $mapper->bind(Input::class, Output::class); $result = $mapper->map(new Input(name: $name, birthdate: $birthdate)); - + $this->assertInstanceOf(Output::class, $result); $this->assertSame($name, $result->name); $this->assertSame($expectedDate, $result->birthdate); @@ -26,10 +25,10 @@ public function testGeneralBinding(string $name, DateTimeImmutable $birthdate, s public static function mappingInputProvider(): array { return [ - 'basic date' => ['Luis', new DateTimeImmutable('1988-01-01'), '1988-01-01T00:00:00+00:00'], - 'with time' => ['Ana', new DateTimeImmutable('1990-05-15 14:30:00'), '1990-05-15T14:30:00+00:00'], - 'leap year' => ['Pedro', new DateTimeImmutable('2020-02-29'), '2020-02-29T00:00:00+00:00'], - 'end of year' => ['Maria', new DateTimeImmutable('2025-12-31 23:59:59'), '2025-12-31T23:59:59+00:00'], + 'basic date' => ['Luis', new \DateTimeImmutable('1988-01-01'), '1988-01-01T00:00:00+00:00'], + 'with time' => ['Ana', new \DateTimeImmutable('1990-05-15 14:30:00'), '1990-05-15T14:30:00+00:00'], + 'leap year' => ['Pedro', new \DateTimeImmutable('2020-02-29'), '2020-02-29T00:00:00+00:00'], + 'end of year' => ['Maria', new \DateTimeImmutable('2025-12-31 23:59:59'), '2025-12-31T23:59:59+00:00'], ]; } @@ -40,7 +39,7 @@ public function testIterableMapping(array $inputs, int $expectedCount) $mapper->bind(Input::class, Output::class); $results = $mapper->mapAsIterable($inputs); - + $this->assertIsArray($results); $this->assertCount($expectedCount, $results); @@ -61,21 +60,21 @@ public static function iterableMappingProvider(): array return [ 'two items' => [ [ - new Input(name: 'Luis', birthdate: new DateTimeImmutable('1988-01-01')), - new Input(name: 'Ana', birthdate: new DateTimeImmutable('1990-05-15')), + new Input(name: 'Luis', birthdate: new \DateTimeImmutable('1988-01-01')), + new Input(name: 'Ana', birthdate: new \DateTimeImmutable('1990-05-15')), ], 2, ], 'single item' => [ - [new Input(name: 'Solo', birthdate: new DateTimeImmutable('2000-01-01'))], + [new Input(name: 'Solo', birthdate: new \DateTimeImmutable('2000-01-01'))], 1, ], 'empty array' => [[], 0], 'three items' => [ [ - new Input(name: 'First', birthdate: new DateTimeImmutable('2020-01-01')), - new Input(name: 'Second', birthdate: new DateTimeImmutable('2021-02-02')), - new Input(name: 'Third', birthdate: new DateTimeImmutable('2022-03-03')), + new Input(name: 'First', birthdate: new \DateTimeImmutable('2020-01-01')), + new Input(name: 'Second', birthdate: new \DateTimeImmutable('2021-02-02')), + new Input(name: 'Third', birthdate: new \DateTimeImmutable('2022-03-03')), ], 3, ], @@ -85,14 +84,14 @@ public static function iterableMappingProvider(): array public function testCastIterable() { $mapper = new Mapper(); - + $mapper ->bind(SecondaryInput::class, SecondaryOutput::class); $input = new SecondaryInput(dates: [ - new DateTimeImmutable('2020-01-01'), - new DateTimeImmutable('2021-02-02'), - new DateTimeImmutable('2022-03-03'), + new \DateTimeImmutable('2020-01-01'), + new \DateTimeImmutable('2021-02-02'), + new \DateTimeImmutable('2022-03-03'), ]); $result = $mapper->map($input); @@ -100,9 +99,9 @@ public function testCastIterable() $this->assertInstanceOf(SecondaryOutput::class, $result); $this->assertIsArray($result->dates); $this->assertCount(3, $result->dates); - + $this->assertSame('2020-01-01T00:00:00+00:00', $result->dates[0]); $this->assertSame('2021-02-02T00:00:00+00:00', $result->dates[1]); $this->assertSame('2022-03-03T00:00:00+00:00', $result->dates[2]); } -} \ No newline at end of file +} diff --git a/tests/MapperTest/NestedOutput.php b/tests/MapperTest/NestedOutput.php index 7b26cee..9be7607 100644 --- a/tests/MapperTest/NestedOutput.php +++ b/tests/MapperTest/NestedOutput.php @@ -10,6 +10,7 @@ class NestedOutput { public function __construct( #[MapProperty(source: 'body')] - public string $body - ) {} + public string $body, + ) { + } } diff --git a/tests/MapperTest/Output.php b/tests/MapperTest/Output.php index 988bb89..80b309a 100644 --- a/tests/MapperTest/Output.php +++ b/tests/MapperTest/Output.php @@ -2,7 +2,6 @@ namespace Tests\MapperTest; -use Luimedi\Remap\Attribute\Cast\CastDateTime; use Luimedi\Remap\Attribute\Cast\CastTransformer; use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\MapGetter; @@ -22,6 +21,7 @@ public function __construct( public string $type, #[MapProperty] #[CastTransformer] - public NestedOutput $nested - ) {} + public NestedOutput $nested, + ) { + } } diff --git a/tests/MapperTest/SecondaryInput.php b/tests/MapperTest/SecondaryInput.php index 08e0043..b9c9716 100644 --- a/tests/MapperTest/SecondaryInput.php +++ b/tests/MapperTest/SecondaryInput.php @@ -2,12 +2,11 @@ namespace Tests\MapperTest; -use DateTimeInterface; - class SecondaryInput { - /** @var DateTimeInterface[] */ + /** @var \DateTimeInterface[] */ public function __construct( public array $dates, - ) {} + ) { + } } diff --git a/tests/MapperTest/SecondaryOutput.php b/tests/MapperTest/SecondaryOutput.php index adaebd7..a802073 100644 --- a/tests/MapperTest/SecondaryOutput.php +++ b/tests/MapperTest/SecondaryOutput.php @@ -15,5 +15,6 @@ public function __construct( #[MapProperty(source: 'dates')] #[CastIterable(class: CastDateTime::class)] public array $dates, - ) {} + ) { + } } diff --git a/tests/PropertyMapperTest/Input.php b/tests/PropertyMapperTest/Input.php index 6f36fa5..889818a 100644 --- a/tests/PropertyMapperTest/Input.php +++ b/tests/PropertyMapperTest/Input.php @@ -2,9 +2,7 @@ namespace Tests\PropertyMapperTest; -use DateTime; - class Input { - public DateTime $birthdate; + public \DateTime $birthdate; } diff --git a/tests/PropertyMapperTest/Output.php b/tests/PropertyMapperTest/Output.php index 1f3f9d0..e562227 100644 --- a/tests/PropertyMapperTest/Output.php +++ b/tests/PropertyMapperTest/Output.php @@ -12,4 +12,4 @@ class Output #[MapProperty] #[CastDateTime()] public string $birthdate; -} \ No newline at end of file +} diff --git a/tests/PropertyMapperTest/PropertyMapperTest.php b/tests/PropertyMapperTest/PropertyMapperTest.php index 242026f..05c370b 100644 --- a/tests/PropertyMapperTest/PropertyMapperTest.php +++ b/tests/PropertyMapperTest/PropertyMapperTest.php @@ -2,12 +2,8 @@ namespace Tests\PropertyMapperTest; -use DateTime; use Luimedi\Remap\Mapper; use PHPUnit\Framework\TestCase; -use Luimedi\Remap\Attribute\MapProperty; -use Luimedi\Remap\Attribute\PropertyMapper; -use Luimedi\Remap\Attribute\Cast\CastDateTime; class PropertyMapperTest extends TestCase { @@ -17,7 +13,7 @@ public function testPropertyMapping() $mapper->bind(Input::class, Output::class); $input = new Input(); - $input->birthdate = new DateTime('2000-01-01'); + $input->birthdate = new \DateTime('2000-01-01'); $output = $mapper->map($input); diff --git a/tests/RecursivePropertyTest/RecursiveOutputProp.php b/tests/RecursivePropertyTest/RecursiveOutputProp.php index b533674..e0814c0 100644 --- a/tests/RecursivePropertyTest/RecursiveOutputProp.php +++ b/tests/RecursivePropertyTest/RecursiveOutputProp.php @@ -2,9 +2,9 @@ namespace Tests\RecursivePropertyTest; -use Luimedi\Remap\Attribute\PropertyMapper; -use Luimedi\Remap\Attribute\MapProperty; use Luimedi\Remap\Attribute\Cast\CastTransformer; +use Luimedi\Remap\Attribute\MapProperty; +use Luimedi\Remap\Attribute\PropertyMapper; #[PropertyMapper] class RecursiveOutputProp diff --git a/tests/RecursivePropertyTest/RecursivePropertyTest.php b/tests/RecursivePropertyTest/RecursivePropertyTest.php index 801dca4..2cae306 100644 --- a/tests/RecursivePropertyTest/RecursivePropertyTest.php +++ b/tests/RecursivePropertyTest/RecursivePropertyTest.php @@ -2,8 +2,8 @@ namespace Tests\RecursivePropertyTest; -use PHPUnit\Framework\TestCase; use Luimedi\Remap\Mapper; +use PHPUnit\Framework\TestCase; use Tests\RecursiveTest\RecursiveInput; class RecursivePropertyTest extends TestCase diff --git a/tests/RecursiveTest/RecursiveOutput.php b/tests/RecursiveTest/RecursiveOutput.php index ba73ab1..fe9706d 100644 --- a/tests/RecursiveTest/RecursiveOutput.php +++ b/tests/RecursiveTest/RecursiveOutput.php @@ -2,9 +2,9 @@ namespace Tests\RecursiveTest; +use Luimedi\Remap\Attribute\Cast\CastTransformer; use Luimedi\Remap\Attribute\ConstructorMapper; use Luimedi\Remap\Attribute\MapProperty; -use Luimedi\Remap\Attribute\Cast\CastTransformer; #[ConstructorMapper] class RecursiveOutput @@ -15,6 +15,7 @@ public function __construct( #[MapProperty(source: 'parent')] #[CastTransformer] - public ?RecursiveOutput $parent = null - ) {} + public ?RecursiveOutput $parent = null, + ) { + } } diff --git a/tests/RecursiveTest/RecursiveTest.php b/tests/RecursiveTest/RecursiveTest.php index 53166af..8291293 100644 --- a/tests/RecursiveTest/RecursiveTest.php +++ b/tests/RecursiveTest/RecursiveTest.php @@ -2,8 +2,8 @@ namespace Tests\RecursiveTest; -use PHPUnit\Framework\TestCase; use Luimedi\Remap\Mapper; +use PHPUnit\Framework\TestCase; class RecursiveTest extends TestCase { @@ -31,7 +31,7 @@ public function testRecursiveMappingDoesNotLoop() // Because of the guard, the grand-parent (which would point back to child) should be left as the original source object // or remain unmapped (in our current implementation the guard returns the original value), so ensure we don't get infinite loop $this->assertTrue( - $result->parent->parent === $child || $result->parent->parent === null || $result->parent->parent instanceof RecursiveOutput + $result->parent->parent === $child || null === $result->parent->parent || $result->parent->parent instanceof RecursiveOutput ); } }