From 83182df18b7f8dd45711336b3ba7e33415c6096d Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 24 Aug 2026 15:25:22 +1000 Subject: [PATCH 1/8] Adopt the phpdb-qa-tools toolchain; drop PHP 8.2 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces laminas-coding-standard and PHPStan with mago via php-db/phpdb-qa-tools 0.1.x-dev, and turns on the shared workflow's codecov and mutation-test jobs, which need secrets: inherit and a coverage-php-version to nominate the canonical matrix leg — without the latter no clover artifact is produced and both jobs break. Infection 0.33+ requires PHP ^8.3, so 8.2 goes: the php constraint, config.platform.php, mago.toml and the CI matrix all move with it. mago.toml extends the shared config. infection.json5.dist sets staticAnalysisTool: "mago" and badges the versioned release branches. codecov.yml reports project and patch status at target: auto. Composer scripts follow the shared convention of cs-check/cs-fix, static-analysis and mutation-test. phpcs.xml.dist, phpstan.neon.dist, phpstan-baseline.neon, stubs/ (PHPStan-only), .laminas-ci.json and coveralls.yml go, with the phpcs and phpstan dev dependencies. test-env-json points TESTS_PHPDB_PGSQL_HOSTNAME at 127.0.0.1 for CI, since the jobs are not containerised, leaving phpunit.xml.dist on the Compose default for local dev. Schema seeding stays with the ListenerExtension bootstrap. composer.lock moves for the new dev dependencies only. Current php-db/phpdb 0.6.x-dev adds ResultInterface::getQueryResult(), which Pgsql\Result does not implement, so a wholesale update fatals before any test runs. Also applies mago formatting and the safe lint fixes across src and test. --- .gitattributes | 11 +- .github/workflows/continuous-integration.yml | 65 +- .gitignore | 8 +- .laminas-ci.json | 12 - codecov.yml | 20 + composer.json | 29 +- composer.lock | 3942 ++++++++++++----- coveralls.yml | 2 - infection.json5.dist | 22 + mago.toml | 7 + phpcs.xml.dist | 27 - phpstan-baseline.neon | 19 - phpstan.neon.dist | 17 - src/AdapterPlatform.php | 37 +- src/ConfigProvider.php | 16 +- src/Connection.php | 198 +- src/Container/ConnectionInterfaceFactory.php | 6 +- src/Container/DriverInterfaceFactory.php | 6 +- src/Container/MetadataInterfaceFactory.php | 4 +- .../PdoConnectionInterfaceFactory.php | 10 +- src/Container/PdoDriverInterfaceFactory.php | 8 +- src/Container/PdoStatementFactory.php | 4 +- src/Container/PlatformInterfaceFactory.php | 6 +- src/Container/StatementInterfaceFactory.php | 4 +- src/Driver.php | 100 +- src/Metadata/Source.php | 381 +- src/Pdo/Connection.php | 66 +- src/Result.php | 62 +- src/Statement.php | 157 +- .../Factory/AbstractFactoryInterface.stub | 19 - .../Factory/DelegatorFactoryInterface.stub | 27 - .../Factory/FactoryInterface.stub | 21 - .../Factory/InvokableFactory.stub | 22 - .../Initializer/InitializerInterface.stub | 19 - stubs/Psr/Container/ContainerInterface.stub | 22 - test/asset/SetupTrait.php | 82 +- test/integration/AdapterPlatformTest.php | 17 +- test/integration/AdapterTest.php | 20 +- .../IntegrationTestStoppedListener.php | 2 +- .../Extension/ListenerExtension.php | 2 +- .../FixtureLoader/PgsqlFixtureLoader.php | 18 +- test/integration/Pdo/AdapterTest.php | 20 +- test/unit/Adapter/ConfigProviderTest.php | 12 +- 43 files changed, 3706 insertions(+), 1843 deletions(-) delete mode 100644 .laminas-ci.json create mode 100644 codecov.yml delete mode 100644 coveralls.yml create mode 100644 infection.json5.dist create mode 100644 mago.toml delete mode 100644 phpcs.xml.dist delete mode 100644 phpstan-baseline.neon delete mode 100644 phpstan.neon.dist delete mode 100644 stubs/Laminas/ServiceManager/Factory/AbstractFactoryInterface.stub delete mode 100644 stubs/Laminas/ServiceManager/Factory/DelegatorFactoryInterface.stub delete mode 100644 stubs/Laminas/ServiceManager/Factory/FactoryInterface.stub delete mode 100644 stubs/Laminas/ServiceManager/Factory/InvokableFactory.stub delete mode 100644 stubs/Laminas/ServiceManager/Initializer/InitializerInterface.stub delete mode 100644 stubs/Psr/Container/ContainerInterface.stub diff --git a/.gitattributes b/.gitattributes index 4368bd2..03e07ab 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,11 +1,12 @@ /.gitattributes export-ignore /.github/ export-ignore /.gitignore export-ignore -/phpcs.xml export-ignore /renovate.json export-ignore -/.laminas-ci.json export-ignore -/.laminas-ci/ export-ignore -/.ci/ export-ignore /phpunit.xml.dist export-ignore /test/ export-ignore -/clover.xml export-ignore \ No newline at end of file +/clover.xml export-ignore +/codecov.yml export-ignore +/infection.json5.dist export-ignore +/mago.toml export-ignore +/compose.yml export-ignore +/docker/ export-ignore diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 53978b8..c4bca50 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -1,44 +1,39 @@ name: "Continuous Integration" +# Branch protection blocks direct pushes to release branches, and pull_request +# already re-triggers on every commit pushed to a PR branch (synchronize), so +# there's no push:branches trigger here — only PRs (targeting numbered +# release branches) and pushed version tags. on: pull_request: - push: branches: + - "[0-9]+.[0-9]+.x" + push: tags: + - "[0-9]+.[0-9]+.[0-9]+" jobs: - matrix: - name: Generate job matrix - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.matrix.outputs.matrix }} - steps: - - name: Gather CI configuration - id: matrix - uses: laminas/laminas-ci-matrix-action@v1 - qa: - name: QA Checks - needs: [matrix] - runs-on: ${{ matrix.operatingSystem }} - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.matrix.outputs.matrix) }} - steps: - - name: ${{ matrix.name }} - uses: laminas/laminas-continuous-integration-action@v1 - with: - job: ${{ matrix.job }} - services: - postgres: - image: postgres - env: - POSTGRES_PASSWORD: 'password' - POSTGRES_DB: 'phpdb_test' - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 3 - ports: - - 5432 + uses: php-db/phpdb-qa-tools/.github/workflows/continuous-integration.yml@0.1.x + # CODECOV_TOKEN (org-wide) and INFECTION_DASHBOARD_API_KEY (per-repo) both + # come through here, whichever scope actually defines each one. + secrets: inherit + with: + php-versions: '["8.3", "8.4", "8.5"]' + run-integration: true + # Postgres container for the integration suite; the schema itself is + # seeded by the ListenerExtension PHPUnit bootstrap, not this workflow. + db-image: "postgres:17-alpine" + db-port: "5432" + db-env-json: '{"POSTGRES_DB":"phpdb_test","POSTGRES_USER":"postgres","POSTGRES_PASSWORD":"password"}' + db-health-cmd: "pg_isready -U postgres -d phpdb_test" + # The test/mutation-test jobs run directly on the runner VM (no + # container:), so the DB is only reachable via 127.0.0.1 + the mapped + # port, not the container name. phpunit.xml.dist defaults this to + # "postgres" for local Docker Compose dev (container-to-container); this + # overrides it for CI without touching that file. + test-env-json: '{"TESTS_PHPDB_PGSQL_HOSTNAME":"127.0.0.1"}' + enable-codecov: true + enable-infection: true + # Canonical leg for coverage + mutation testing (highest supported PHP). + coverage-php-version: "8.5" diff --git a/.gitignore b/.gitignore index 0088c44..811cd36 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ -/.phpcs-cache -/.phpstan-cache -/phpstan.neon /.phpunit.cache /.phpunit.result.cache /phpunit.xml /vendor/ /xdebug_filter.php -/clover.xml \ No newline at end of file +/clover.xml +/infection.json5 +/infection.log +/summary.log diff --git a/.laminas-ci.json b/.laminas-ci.json deleted file mode 100644 index 10c530b..0000000 --- a/.laminas-ci.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "additional_checks": [ - { - "name": "PhpStan", - "job": { - "php": "8.2", - "dependencies": "latest", - "command": "composer require --dev phpstan/phpstan && vendor/bin/phpstan analyse" - } - } - ] -} \ No newline at end of file diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..8668e78 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,20 @@ +coverage: + status: + project: + default: + target: auto + threshold: 0% + base: auto + patch: + default: + target: auto + threshold: 0% + base: auto + +comment: + layout: "diff, flags, files" + behavior: default + require_changes: false + require_base: false + require_head: true + hide_project_coverage: false diff --git a/composer.json b/composer.json index e97c8a7..5fb3cf1 100644 --- a/composer.json +++ b/composer.json @@ -18,10 +18,10 @@ "config": { "sort-packages": true, "platform": { - "php": "8.2.99" + "php": "8.3.99" }, "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true + "infection/extension-installer": true } }, "extra": { @@ -30,15 +30,14 @@ } }, "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "php": "~8.3.0 || ~8.4.0 || ~8.5.0", "php-db/phpdb": "^0.6.0" }, "require-dev": { "ext-pdo_pgsql": "*", "ext-pgsql": "*", - "laminas/laminas-coding-standard": "^3.0.1", - "phpstan/phpstan": "^2.1", - "phpstan/phpstan-phpunit": "^2.0", + "infection/infection": "^0.34.1", + "php-db/phpdb-qa-tools": "0.1.x-dev", "phpunit/phpunit": "^11.5.42" }, "suggest": { @@ -61,18 +60,22 @@ "scripts": { "check": [ "@cs-check", - "@sa", + "@static-analysis", "@test", "@test-integration" ], - "cs-check": "phpcs", - "cs-fix": "phpcbf", + "cs-check": [ + "mago format --check", + "mago lint" + ], + "cs-fix": [ + "mago format", + "mago lint --fix" + ], "test": "phpunit --colors=always --testsuite \"unit test\"", "test-coverage": "phpunit --colors=always --coverage-clover clover.xml", "test-integration": "phpunit --colors=always --testsuite \"integration test\"", - "sa": "vendor/bin/phpstan analyse --memory-limit=256M", - "sa-gen-baseline": "vendor/bin/phpstan analyse --memory-limit=256M --generate-baseline", - "sa-verbose": "vendor/bin/phpstan analyse --memory-limit=256M -vv", - "upload-coverage": "coveralls -v" + "static-analysis": "mago analyze", + "mutation-test": "infection" } } diff --git a/composer.lock b/composer.lock index 7e4a8d7..07a0166 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7c98d39a182766356052ff8f400e7623", + "content-hash": "31a58cde9b61cae57b793514ce86a163", "packages": [ { "name": "brick/varexporter", @@ -382,39 +382,47 @@ ], "packages-dev": [ { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.2.0", + "name": "colinodell/json5", + "version": "v3.0.0", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" + "url": "https://github.com/colinodell/json5.git", + "reference": "5724d21bc5c910c2560af1b8915f0cc0163579c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", - "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", + "url": "https://api.github.com/repos/colinodell/json5/zipball/5724d21bc5c910c2560af1b8915f0cc0163579c8", + "reference": "5724d21bc5c910c2560af1b8915f0cc0163579c8", "shasum": "" }, "require": { - "composer-plugin-api": "^2.2", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.0" }, "require-dev": { - "composer/composer": "^2.2", - "ext-json": "*", - "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", - "yoast/phpunit-polyfills": "^1.0" + "mikehaertl/php-shellcommand": "^1.7.0", + "phpstan/phpstan": "^1.10.57", + "scrutinizer/ocular": "^1.9", + "squizlabs/php_codesniffer": "^3.8.1", + "symfony/finder": "^6.0|^7.0", + "symfony/phpunit-bridge": "^7.0.3" }, - "type": "composer-plugin", + "bin": [ + "bin/json5" + ], + "type": "library", "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "branch-alias": { + "dev-main": "4.0-dev" + } }, "autoload": { + "files": [ + "src/global.php" + ], "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "ColinODell\\Json5\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -423,262 +431,276 @@ ], "authors": [ { - "name": "Franck Nijhof", - "email": "opensource@frenck.dev", - "homepage": "https://frenck.dev", - "role": "Open source developer" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Developer" } ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "description": "UTF-8 compatible JSON5 parser for PHP", + "homepage": "https://github.com/colinodell/json5", "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcbf", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" + "JSON5", + "json", + "json5_decode", + "json_decode" ], "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", - "source": "https://github.com/PHPCSStandards/composer-installer" + "issues": "https://github.com/colinodell/json5/issues", + "source": "https://github.com/colinodell/json5/tree/v3.0.0" }, "funding": [ { - "url": "https://github.com/PHPCSStandards", - "type": "github" + "url": "https://www.colinodell.com/sponsor", + "type": "custom" }, { - "url": "https://github.com/jrfnl", - "type": "github" + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" }, { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" + "url": "https://github.com/colinodell", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" + "url": "https://www.patreon.com/colinodell", + "type": "patreon" } ], - "time": "2025-11-11T04:32:07+00:00" + "time": "2024-02-09T13:06:12+00:00" }, { - "name": "laminas/laminas-coding-standard", - "version": "3.1.0", + "name": "composer/pcre", + "version": "3.4.0", "source": { "type": "git", - "url": "https://github.com/laminas/laminas-coding-standard.git", - "reference": "d4412caba9ed16c93cdcf301759f5ee71f9d9aea" + "url": "https://github.com/composer/pcre.git", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-coding-standard/zipball/d4412caba9ed16c93cdcf301759f5ee71f9d9aea", - "reference": "d4412caba9ed16c93cdcf301759f5ee71f9d9aea", + "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", - "php": "^7.4 || ^8.0", - "slevomat/coding-standard": "^8.15.0", - "squizlabs/php_codesniffer": "^3.10", - "webimpress/coding-standard": "^1.3" + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<2.2.2" + }, + "require-dev": { + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } }, - "type": "phpcodesniffer-standard", "autoload": { "psr-4": { - "LaminasCodingStandard\\": "src/LaminasCodingStandard/" + "Composer\\Pcre\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "description": "Laminas Coding Standard", - "homepage": "https://laminas.dev", + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", "keywords": [ - "Coding Standard", - "laminas" + "PCRE", + "preg", + "regex", + "regular expression" ], "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-coding-standard/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-coding-standard/issues", - "rss": "https://github.com/laminas/laminas-coding-standard/releases.atom", - "source": "https://github.com/laminas/laminas-coding-standard" + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.4.0" }, "funding": [ { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" } ], - "time": "2025-05-13T08:37:04+00:00" + "time": "2026-06-07T11:47:49+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.13.4", + "name": "composer/xdebug-handler", + "version": "3.0.5", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" }, "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], "psr-4": { - "DeepCopy\\": "src/DeepCopy/" + "Composer\\XdebugHandler\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "Xdebug", + "performance" ], "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", "type": "tidelift" } ], - "time": "2025-08-01T08:46:24+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { - "name": "phar-io/manifest", - "version": "2.0.4", + "name": "fidry/cpu-core-counter", + "version": "1.3.0", "source": { "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", "php": "^7.2 || ^8.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" }, + "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" } ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, "funding": [ { - "url": "https://github.com/theseer", + "url": "https://github.com/theofidry", "type": "github" } ], - "time": "2024-03-03T12:33:53+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { - "name": "phar-io/version", - "version": "3.2.1", + "name": "infection/abstract-testframework-adapter", + "version": "0.5.1", "source": { "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + "url": "https://github.com/infection/abstract-testframework-adapter.git", + "reference": "b24bf3e850f70cd20a10621f08c3cef66f147ac8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "url": "https://api.github.com/repos/infection/abstract-testframework-adapter/zipball/b24bf3e850f70cd20a10621f08c3cef66f147ac8", + "reference": "b24bf3e850f70cd20a10621f08c3cef66f147ac8", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^8.3" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.18", + "fidry/makefile": "^1.0", + "friendsofphp/php-cs-fixer": "^3.95.2", + "phpunit/phpunit": "^12.0 || ^13.0", + "rector/rector": "^2.4.5" }, "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Infection\\AbstractTestFramework\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -686,224 +708,1809 @@ ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Abstract Test Framework Adapter for Infection", + "support": { + "issues": "https://github.com/infection/abstract-testframework-adapter/issues", + "source": "https://github.com/infection/abstract-testframework-adapter/tree/0.5.1" + }, + "funding": [ { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "url": "https://github.com/infection", + "type": "github" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "url": "https://opencollective.com/infection", + "type": "open_collective" } ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" + "time": "2026-05-28T19:10:29+00:00" }, { - "name": "phpstan/phpdoc-parser", - "version": "2.3.2", + "name": "infection/extension-installer", + "version": "0.1.2", "source": { "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" + "url": "https://github.com/infection/extension-installer.git", + "reference": "9b351d2910b9a23ab4815542e93d541e0ca0cdcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", - "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", + "url": "https://api.github.com/repos/infection/extension-installer/zipball/9b351d2910b9a23ab4815542e93d541e0ca0cdcf", + "reference": "9b351d2910b9a23ab4815542e93d541e0ca0cdcf", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0" + "composer-plugin-api": "^1.1 || ^2.0" }, "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", + "composer/composer": "^1.9 || ^2.0", + "friendsofphp/php-cs-fixer": "^2.18, <2.19", + "infection/infection": "^0.15.2", + "php-coveralls/php-coveralls": "^2.4", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" + "phpstan/phpstan": "^0.12.10", + "phpstan/phpstan-phpunit": "^0.12.6", + "phpstan/phpstan-strict-rules": "^0.12.2", + "phpstan/phpstan-webmozart-assert": "^0.12.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.8" + }, + "type": "composer-plugin", + "extra": { + "class": "Infection\\ExtensionInstaller\\Plugin" }, - "type": "library", "autoload": { "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] + "Infection\\ExtensionInstaller\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", + "description": "Infection Extension Installer", "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" + "issues": "https://github.com/infection/extension-installer/issues", + "source": "https://github.com/infection/extension-installer/tree/0.1.2" }, - "time": "2026-01-25T14:56:51+00:00" + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2021-10-20T22:08:34+00:00" }, { - "name": "phpstan/phpstan", - "version": "2.1.46", + "name": "infection/include-interceptor", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/infection/include-interceptor.git", + "reference": "c083331bc0cd1cd319ac1b7a08e3ad4a34aa7992" + }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a193923fc2d6325ef4e741cf3af8c3e8f54dbf25", - "reference": "a193923fc2d6325ef4e741cf3af8c3e8f54dbf25", + "url": "https://api.github.com/repos/infection/include-interceptor/zipball/c083331bc0cd1cd319ac1b7a08e3ad4a34aa7992", + "reference": "c083331bc0cd1cd319ac1b7a08e3ad4a34aa7992", "shasum": "" }, - "require": { - "php": "^7.4|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "infection/infection": "^0.19.0", + "phan/phan": "^2.4 || ^3", + "php-coveralls/php-coveralls": "^2.2", + "phpstan/phpstan": "^0.12.8", + "phpunit/phpunit": "^8.5", + "vimeo/psalm": "^3.8" }, - "bin": [ - "phpstan", - "phpstan.phar" - ], "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ] + "psr-4": { + "Infection\\StreamWrapper\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } ], + "description": "Stream Wrapper: Include Interceptor. Allows to replace included (autoloaded) file with another one.", "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" + "issues": "https://github.com/infection/include-interceptor/issues", + "source": "https://github.com/infection/include-interceptor/tree/1.0.0" }, "funding": [ { - "url": "https://github.com/ondrejmirtes", + "url": "https://github.com/infection", "type": "github" }, { - "url": "https://github.com/phpstan", - "type": "github" + "url": "https://opencollective.com/infection", + "type": "open_collective" } ], - "time": "2026-04-01T09:25:14+00:00" + "time": "2024-05-03T21:48:06+00:00" }, { - "name": "phpstan/phpstan-phpunit", - "version": "2.0.16", + "name": "infection/infection", + "version": "0.34.2", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32" + "url": "https://github.com/infection/infection.git", + "reference": "18d9bef39fae250f202920d1453ab96e793e6637" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6ab598e1bc106e6827fd346ae4a12b4a5d634c32", - "reference": "6ab598e1bc106e6827fd346ae4a12b4a5d634c32", + "url": "https://api.github.com/repos/infection/infection/zipball/18d9bef39fae250f202920d1453ab96e793e6637", + "reference": "18d9bef39fae250f202920d1453ab96e793e6637", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.1.32" + "colinodell/json5": "^3.0", + "composer-runtime-api": "^2.0", + "composer/xdebug-handler": "^3.0", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "fidry/cpu-core-counter": "^1.0", + "infection/abstract-testframework-adapter": "^0.5.0", + "infection/extension-installer": "^0.1.0", + "infection/include-interceptor": "^0.2.5 || ^1.0.0", + "infection/mutator": "^0.4", + "justinrainbow/json-schema": "^6.0", + "nikic/php-parser": "^5.6.2", + "ondram/ci-detector": "^4.1.0", + "php": "^8.3", + "psr/log": "^2.0 || ^3.0", + "sanmai/di-container": "^0.1.16", + "sanmai/duoclock": "^0.1.0", + "sanmai/later": "^0.1.7", + "sanmai/pipeline": "^7.2", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0", + "symfony/console": "^6.4 || ^7.4 || ^8.0", + "symfony/filesystem": "^6.4 || ^7.4 || ^8.0", + "symfony/finder": "^6.4 || ^7.4 || ^8.0", + "symfony/polyfill-php85": "^1.33", + "symfony/process": "^6.4 || ^7.4 || ^8.0", + "thecodingmachine/safe": "^v3.0", + "webmozart/assert": "^1.11 || ^2.0" }, "conflict": { - "phpunit/phpunit": "<7.0" + "antecedent/patchwork": "<2.1.25", + "dg/bypass-finals": "<1.4.1" }, "require-dev": { - "nikic/php-parser": "^5", - "php-parallel-lint/php-parallel-lint": "^1.2", + "carthage-software/mago": "^1.20", + "ext-simplexml": "*", + "fidry/makefile": "^1.0", + "fig/log-test": "^1.2", + "phpat/phpat": "^0.12.4", + "phpbench/phpbench": "^1.4", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon", - "rules.neon" - ] - } + "phpstan/phpstan-webmozart-assert": "^2.0", + "phpunit/phpunit": "^12.5.29", + "rector/rector": "^2.2.4", + "shipmonk/dead-code-detector": "^1.3", + "shipmonk/name-collision-detector": "^2.1", + "sidz/phpstan-rules": "^0.5.1", + "symfony/yaml": "^6.4 || ^7.4 || ^8.0", + "thecodingmachine/phpstan-safe-rule": "^1.4", + "webmozarts/strict-phpunit": "^7.15" }, + "bin": [ + "bin/infection" + ], + "type": "library", "autoload": { "psr-4": { - "PHPStan\\": "src/" + "Infection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" - ], - "description": "PHPUnit extensions and rules for PHPStan", - "keywords": [ - "static analysis" + "BSD-3-Clause" ], - "support": { - "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.16" - }, - "time": "2026-02-14T09:05:21+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "11.0.12", - "source": { - "type": "git", + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com", + "homepage": "https://twitter.com/maks_rafalko" + }, + { + "name": "Oleg Zhulnev", + "homepage": "https://github.com/sidz" + }, + { + "name": "Gert de Pagter", + "homepage": "https://github.com/BackEndTea" + }, + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com", + "homepage": "https://twitter.com/tfidry" + }, + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "homepage": "https://www.alexeykopytko.com" + }, + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.", + "keywords": [ + "coverage", + "mutant", + "mutation framework", + "mutation testing", + "testing", + "unit testing" + ], + "support": { + "issues": "https://github.com/infection/infection/issues", + "source": "https://github.com/infection/infection/tree/0.34.2" + }, + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2026-08-07T12:59:47+00:00" + }, + { + "name": "infection/mutator", + "version": "0.4.1", + "source": { + "type": "git", + "url": "https://github.com/infection/mutator.git", + "reference": "3c976d721b02b32f851ee4e15d553ef1e9186d1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/infection/mutator/zipball/3c976d721b02b32f851ee4e15d553ef1e9186d1d", + "reference": "3c976d721b02b32f851ee4e15d553ef1e9186d1d", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Infection\\Mutator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Maks Rafalko", + "email": "maks.rafalko@gmail.com" + } + ], + "description": "Mutator interface to implement custom mutators (mutation operators) for Infection", + "support": { + "issues": "https://github.com/infection/mutator/issues", + "source": "https://github.com/infection/mutator/tree/0.4.1" + }, + "funding": [ + { + "url": "https://github.com/infection", + "type": "github" + }, + { + "url": "https://opencollective.com/infection", + "type": "open_collective" + } + ], + "time": "2025-04-29T08:19:52+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "6.11.0", + "source": { + "type": "git", + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "7e420a943a6fbc95e60e3cf67acfbee85b3b4da7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/7e420a943a6fbc95e60e3cf67acfbee85b3b4da7", + "reference": "7e420a943a6fbc95e60e3cf67acfbee85b3b4da7", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "ext-json": "*", + "marc-mabe/php-enum": "^4.4", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.3.0", + "json-schema/json-schema-test-suite": "dev-main", + "marc-mabe/php-enum-phpstan": "^2.0", + "phpspec/prophecy": "^1.19", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^8.5" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Danny van der Sluijs", + "email": "danny.vandersluijs@icloud.com", + "role": "Maintainer" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/jsonrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/6.11.0" + }, + "time": "2026-08-21T10:30:42+00:00" + }, + { + "name": "marc-mabe/php-enum", + "version": "v4.7.2", + "source": { + "type": "git", + "url": "https://github.com/marc-mabe/php-enum.git", + "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/bb426fcdd65c60fb3638ef741e8782508fda7eef", + "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef", + "shasum": "" + }, + "require": { + "ext-reflection": "*", + "php": "^7.1 | ^8.0" + }, + "require-dev": { + "phpbench/phpbench": "^0.16.10 || ^1.0.4", + "phpstan/phpstan": "^1.3.1", + "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11", + "vimeo/psalm": "^4.17.0 | ^5.26.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.2-dev", + "dev-master": "4.7-dev" + } + }, + "autoload": { + "psr-4": { + "MabeEnum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Marc Bennewitz", + "email": "dev@mabe.berlin", + "homepage": "https://mabe.berlin/", + "role": "Lead" + } + ], + "description": "Simple and fast implementation of enumerations with native PHP", + "homepage": "https://github.com/marc-mabe/php-enum", + "keywords": [ + "enum", + "enum-map", + "enum-set", + "enumeration", + "enumerator", + "enummap", + "enumset", + "map", + "set", + "type", + "type-hint", + "typehint" + ], + "support": { + "issues": "https://github.com/marc-mabe/php-enum/issues", + "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.2" + }, + "time": "2025-09-14T11:18:39+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "ondram/ci-detector", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/OndraM/ci-detector.git", + "reference": "8b0223b5ed235fd377c75fdd1bfcad05c0f168b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/OndraM/ci-detector/zipball/8b0223b5ed235fd377c75fdd1bfcad05c0f168b8", + "reference": "8b0223b5ed235fd377c75fdd1bfcad05c0f168b8", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.13.2", + "lmc/coding-standard": "^3.0.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpunit/phpunit": "^9.6.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "OndraM\\CiDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Machulda", + "email": "ondrej.machulda@gmail.com" + } + ], + "description": "Detect continuous integration environment and provide unified access to properties of current build", + "keywords": [ + "CircleCI", + "Codeship", + "Wercker", + "adapter", + "appveyor", + "aws", + "aws codebuild", + "azure", + "azure devops", + "azure pipelines", + "bamboo", + "bitbucket", + "buddy", + "ci-info", + "codebuild", + "continuous integration", + "continuousphp", + "devops", + "drone", + "github", + "gitlab", + "interface", + "jenkins", + "pipelines", + "sourcehut", + "teamcity", + "travis" + ], + "support": { + "issues": "https://github.com/OndraM/ci-detector/issues", + "source": "https://github.com/OndraM/ci-detector/tree/4.2.0" + }, + "time": "2024-03-12T13:22:30+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "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" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "php-db/phpdb-qa-tools", + "version": "0.1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/php-db/phpdb-qa-tools.git", + "reference": "f2323423deac77dd719f3f2ca7a9b2a7e21c93f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-db/phpdb-qa-tools/zipball/f2323423deac77dd719f3f2ca7a9b2a7e21c93f6", + "reference": "f2323423deac77dd719f3f2ca7a9b2a7e21c93f6", + "shasum": "" + }, + "require": { + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "suggest": { + "phpunit/phpunit": "To run the shared test configuration (^11.5 || ^12.0)" + }, + "default-branch": true, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Shared QA toolchain for php-db components: Mago formatting, linting and static analysis, plus the PHPUnit baseline and CI workflow.", + "homepage": "https://github.com/php-db/phpdb-qa-tools", + "keywords": [ + "coding-standards", + "formatter", + "linter", + "mago", + "phpdb", + "qa", + "static-analysis" + ], + "support": { + "forum": "https://github.com/php-db/phpdb-qa-tools/discussions", + "issues": "https://github.com/php-db/phpdb-qa-tools/issues", + "source": "https://github.com/php-db/phpdb-qa-tools" + }, + "time": "2026-08-10T01:10:13+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.12", + "source": { + "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", - "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.46" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "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/11.0.12" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T13:52:54+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.55", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2026-02-18T12:37:06+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "sanmai/di-container", + "version": "0.1.23", + "source": { + "type": "git", + "url": "https://github.com/sanmai/di-container.git", + "reference": "8cf59c091f33297389d0a5a27ea0d688df15c376" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/di-container/zipball/8cf59c091f33297389d0a5a27ea0d688df15c376", + "reference": "8cf59c091f33297389d0a5a27ea0d688df15c376", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1.2 || ^2.0", + "sanmai/pipeline": "^7.10" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^3.17", + "infection/infection": ">=0.31", + "php-coveralls/php-coveralls": "^2.4.1", + "phpbench/phpbench": "^1.4", + "phpstan/extension-installer": "^1.4", + "phpunit/phpunit": "^11.5.25", + "sanmai/phpstan-rules": "^0.3.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.1.x-dev" + }, + "preferred-install": "dist" + }, + "autoload": { + "psr-4": { + "DIContainer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "homepage": "https://github.com/sanmai" + }, + { + "name": "Maks Rafalko", + "homepage": "https://twitter.com/maks_rafalko" + }, + { + "name": "Théo FIDRY", + "homepage": "https://twitter.com/tfidry" + } + ], + "description": "dependency injection container with automatic constructor dependency resolution", + "keywords": [ + "Autowiring", + "constructor di", + "di container", + "psr 11" + ], + "support": { + "issues": "https://github.com/sanmai/di-container/issues", + "source": "https://github.com/sanmai/di-container/tree/0.1.23" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2026-08-11T00:58:41+00:00" + }, + { + "name": "sanmai/duoclock", + "version": "0.1.3", + "source": { + "type": "git", + "url": "https://github.com/sanmai/DuoClock.git", + "reference": "47461e3ff65b7308635047831a55615652e7be1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/DuoClock/zipball/47461e3ff65b7308635047831a55615652e7be1a", + "reference": "47461e3ff65b7308635047831a55615652e7be1a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^3.17", + "infection/infection": ">=0.29", + "php-coveralls/php-coveralls": "^2.4.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^11.5.25", + "sanmai/phpstan-rules": "^0.3.1" + }, + "type": "library", + "extra": { + "preferred-install": "dist" + }, + "autoload": { + "psr-4": { + "DuoClock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" + } + ], + "description": "PHP time mocking for tests - PSR-20 clock with mockable sleep(), time(), and TimeSpy for PHPUnit testing", + "support": { + "issues": "https://github.com/sanmai/DuoClock/issues", + "source": "https://github.com/sanmai/DuoClock/tree/0.1.3" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2025-12-26T06:12:34+00:00" + }, + { + "name": "sanmai/later", + "version": "0.1.8", + "source": { + "type": "git", + "url": "https://github.com/sanmai/later.git", + "reference": "c56aeb8fa7fdf81eda2640a68b51884685963d13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/later/zipball/c56aeb8fa7fdf81eda2640a68b51884685963d13", + "reference": "c56aeb8fa7fdf81eda2640a68b51884685963d13", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "friendsofphp/php-cs-fixer": "^3.35.1", + "infection/infection": ">=0.27.6", + "phan/phan": ">=2", + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": ">=1.4.5", + "phpunit/phpunit": ">=9.5 <10", + "vimeo/psalm": ">=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.1.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Later\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" + } + ], + "description": "Later: deferred wrapper object", + "support": { + "issues": "https://github.com/sanmai/later/issues", + "source": "https://github.com/sanmai/later/tree/0.1.8" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2026-06-29T07:24:33+00:00" + }, + { + "name": "sanmai/pipeline", + "version": "7.10", + "source": { + "type": "git", + "url": "https://github.com/sanmai/pipeline.git", + "reference": "a8e4e57a6031efc7a92defd13fed9c1c4c73fc71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sanmai/pipeline/zipball/a8e4e57a6031efc7a92defd13fed9c1c4c73fc71", + "reference": "a8e4e57a6031efc7a92defd13fed9c1c4c73fc71", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.8", + "esi/phpunit-coverage-check": ">2", + "friendsofphp/php-cs-fixer": "^3.17", + "infection/infection": ">=0.32.3", + "league/pipeline": "^0.3 || ^1.0", + "php-coveralls/php-coveralls": "^2.4.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^11 || ^12", + "sanmai/phpstan-rules": "^0.3.11", + "sanmai/phpunit-double-colon-syntax": "^0.1.1", + "vimeo/psalm": ">=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Pipeline\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com" + } + ], + "description": "General-purpose collections pipeline", + "support": { + "issues": "https://github.com/sanmai/pipeline/issues", + "source": "https://github.com/sanmai/pipeline/tree/7.10" + }, + "funding": [ + { + "url": "https://github.com/sanmai", + "type": "github" + } + ], + "time": "2026-08-03T04:56:22+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^5.7.0", + "ext-mbstring": "*", "php": ">=8.2", - "phpunit/php-file-iterator": "^5.1.0", - "phpunit/php-text-template": "^4.0.1", - "sebastian/code-unit-reverse-lookup": "^4.0.1", - "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.1", - "sebastian/lines-of-code": "^3.0.1", - "sebastian/version": "^5.0.2", - "theseer/tokenizer": "^1.3.1" + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^11.5.46" + "phpunit/phpunit": "^11.4" }, "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0.x-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -918,21 +2525,32 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" } ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ - "coverage", - "testing", - "xunit" + "comparator", + "compare", + "equality" ], "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/11.0.12" + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -948,36 +2566,37 @@ "type": "thanks_dev" }, { - "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", "type": "tidelift" } ], - "time": "2025-12-24T07:01:01+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { - "name": "phpunit/php-file-iterator", - "version": "5.1.1", + "name": "sebastian/complexity", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", - "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", "shasum": "" }, "require": { + "nikic/php-parser": "^5.0", "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -996,65 +2615,115 @@ "role": "lead" } ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" - }, + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", - "type": "tidelift" + "url": "https://github.com/sebastianbergmann", + "type": "github" } ], - "time": "2026-02-02T13:52:54+00:00" + "time": "2024-07-03T04:53:05+00:00" }, { - "name": "phpunit/php-invoker", - "version": "5.0.1", + "name": "sebastian/environment", + "version": "7.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", - "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "suggest": { - "ext-pcntl": "*" + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "7.2-dev" } }, "autoload": { @@ -1069,52 +2738,67 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ - "process" + "Xdebug", + "environment", + "hhvm" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2024-07-03T05:07:44+00:00" + "time": "2025-05-21T11:55:47+00:00" }, { - "name": "phpunit/php-text-template", - "version": "4.0.1", + "name": "sebastian/exporter", + "version": "6.3.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", - "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", "shasum": "" }, "require": { - "php": ">=8.2" + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -1129,46 +2813,77 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ - "template" + "export", + "exporter" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2024-07-03T05:08:43+00:00" + "time": "2025-09-24T06:12:51+00:00" }, { - "name": "phpunit/php-timer", - "version": "7.0.1", + "name": "sebastian/global-state", + "version": "7.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", - "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { + "ext-dom": "*", "phpunit/phpunit": "^11.0" }, "type": "library", @@ -1189,19 +2904,18 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ - "timer" + "global state" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "security": "https://github.com/sebastianbergmann/php-timer/security/policy", - "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" }, "funding": [ { @@ -1209,67 +2923,36 @@ "type": "github" } ], - "time": "2024-07-03T05:09:35+00:00" + "time": "2024-07-03T04:57:36+00:00" }, { - "name": "phpunit/phpunit", - "version": "11.5.55", + "name": "sebastian/lines-of-code", + "version": "3.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.4", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.12", - "phpunit/php-file-iterator": "^5.1.1", - "phpunit/php-invoker": "^5.0.1", - "phpunit/php-text-template": "^4.0.1", - "phpunit/php-timer": "^7.0.1", - "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.3", - "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.1", - "sebastian/exporter": "^6.3.2", - "sebastian/global-state": "^7.0.2", - "sebastian/object-enumerator": "^6.0.1", - "sebastian/recursion-context": "^6.0.3", - "sebastian/type": "^5.1.3", - "sebastian/version": "^5.0.2", - "staabm/side-effects-detector": "^1.0.5" + "nikic/php-parser": "^5.0", + "php": ">=8.2" }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" + "require-dev": { + "phpunit/phpunit": "^11.0" }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-main": "11.5-dev" + "dev-main": "3.0-dev" } }, "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], "classmap": [ "src/" ] @@ -1285,58 +2968,39 @@ "role": "lead" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" }, "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, { "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" } ], - "time": "2026-02-18T12:37:06+00:00" + "time": "2024-07-03T04:58:38+00:00" }, { - "name": "sebastian/cli-parser", - "version": "3.0.2", + "name": "sebastian/object-enumerator", + "version": "6.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", - "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { "phpunit/phpunit": "^11.0" @@ -1344,7 +3008,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1359,16 +3023,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" }, "funding": [ { @@ -1376,32 +3039,32 @@ "type": "github" } ], - "time": "2024-07-03T04:41:36+00:00" + "time": "2024-07-03T05:00:13+00:00" }, { - "name": "sebastian/code-unit", - "version": "3.0.3", + "name": "sebastian/object-reflector", + "version": "4.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", - "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.5" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1416,16 +3079,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "security": "https://github.com/sebastianbergmann/code-unit/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" }, "funding": [ { @@ -1433,32 +3095,32 @@ "type": "github" } ], - "time": "2025-03-19T07:56:08+00:00" + "time": "2024-07-03T05:01:32+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", - "version": "4.0.1", + "name": "sebastian/recursion-context", + "version": "6.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", - "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1474,54 +3136,67 @@ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2024-07-03T04:45:54+00:00" + "time": "2025-08-13T04:42:22+00:00" }, { - "name": "sebastian/comparator", - "version": "6.3.3", + "name": "sebastian/type", + "version": "5.1.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", - "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "php": ">=8.2", - "sebastian/diff": "^6.0", - "sebastian/exporter": "^6.0" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.4" - }, - "suggest": { - "ext-bcmath": "For comparing BcMath\\Number objects" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.3-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1536,32 +3211,16 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" }, "funding": [ { @@ -1577,37 +3236,33 @@ "type": "thanks_dev" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", "type": "tidelift" } ], - "time": "2026-01-24T09:26:40+00:00" + "time": "2025-08-09T06:55:48+00:00" }, { - "name": "sebastian/complexity", - "version": "4.0.1", + "name": "sebastian/version", + "version": "5.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", - "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", "php": ">=8.2" }, - "require-dev": { - "phpunit/phpunit": "^11.0" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1626,12 +3281,12 @@ "role": "lead" } ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" }, "funding": [ { @@ -1639,869 +3294,1167 @@ "type": "github" } ], - "time": "2024-07-03T04:49:50+00:00" + "time": "2024-10-09T05:16:32+00:00" }, { - "name": "sebastian/diff", - "version": "6.0.2", + "name": "staabm/side-effects-detector", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", - "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", "shasum": "" }, "require": { - "php": ">=8.2" + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^11.0", - "symfony/process": "^4.2 || ^5" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/console", + "version": "v7.4.17", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "962e18f09ebe68a49039b4c82fc0ea4871824fca" }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/962e18f09ebe68a49039b4c82fc0ea4871824fca", + "reference": "962e18f09ebe68a49039b4c82fc0ea4871824fca", + "shasum": "" + }, + "require": { + "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": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" + "cli", + "command-line", + "console", + "terminal" ], "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + "source": "https://github.com/symfony/console/tree/v7.4.17" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "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-07-03T04:53:05+00:00" + "time": "2026-08-21T12:09:28+00:00" }, { - "name": "sebastian/environment", - "version": "7.2.1", + "name": "symfony/deprecation-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", - "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.3" - }, - "suggest": { - "ext-posix": "*" + "php": ">=8.1" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-main": "7.2-dev" + "dev-main": "3.7-dev" } }, "autoload": { - "classmap": [ - "src/" + "files": [ + "function.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "https://github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-21T11:55:47+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { - "name": "sebastian/exporter", - "version": "6.3.2", + "name": "symfony/filesystem", + "version": "v7.4.17", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + "url": "https://github.com/symfony/filesystem.git", + "reference": "ee7bc7bca4c7079b88e57d5000aeeb20df570c8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", - "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ee7bc7bca4c7079b88e57d5000aeeb20df570c8d", + "reference": "ee7bc7bca4c7079b88e57d5000aeeb20df570c8d", "shasum": "" }, "require": { - "ext-mbstring": "*", "php": ">=8.2", - "sebastian/recursion-context": "^6.0" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "phpunit/phpunit": "^11.3" + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.3-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.4.17" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-09-24T06:12:51+00:00" + "time": "2026-08-21T12:09:28+00:00" }, { - "name": "sebastian/global-state", - "version": "7.0.2", + "name": "symfony/finder", + "version": "v7.4.17", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + "url": "https://github.com/symfony/finder.git", + "reference": "5ce28827081f6d1f0c32eaf3882750f19cb5bbe6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", - "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "url": "https://api.github.com/repos/symfony/finder/zipball/5ce28827081f6d1f0c32eaf3882750f19cb5bbe6", + "reference": "5ce28827081f6d1f0c32eaf3882750f19cb5bbe6", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=8.2" }, "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^11.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "7.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Snapshotting of global state", - "homepage": "https://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + "source": "https://github.com/symfony/finder/tree/v7.4.17" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "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-07-03T04:57:36+00:00" + "time": "2026-08-21T12:09:28+00:00" }, { - "name": "sebastian/lines-of-code", - "version": "3.0.1", + "name": "symfony/polyfill-ctype", + "version": "v1.37.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", - "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.2" + "php": ">=7.2" }, - "require-dev": { - "phpunit/phpunit": "^11.0" + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.0-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "classmap": [ - "src/" - ] + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "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-07-03T04:58:38+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "6.0.1", + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.41.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", - "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", "shasum": "" }, "require": { - "php": ">=8.2", - "sebastian/object-reflector": "^4.0", - "sebastian/recursion-context": "^6.0" + "php": ">=7.2" }, - "require-dev": { - "phpunit/phpunit": "^11.0" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "6.0-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "classmap": [ - "src/" - ] + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "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-07-03T05:00:13+00:00" + "time": "2026-07-28T08:25:59+00:00" }, { - "name": "sebastian/object-reflector", - "version": "4.0.1", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.38.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", - "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=7.2" }, - "require-dev": { - "phpunit/phpunit": "^11.0" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "4.0-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ - "src/" + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "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-07-03T05:01:32+00:00" + "time": "2026-05-25T13:48:31+00:00" }, { - "name": "sebastian/recursion-context", - "version": "6.0.3", + "name": "symfony/polyfill-mbstring", + "version": "v1.38.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", - "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { - "php": ">=8.2" + "ext-iconv": "*", + "php": ">=7.2" }, - "require-dev": { - "phpunit/phpunit": "^11.3" + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "6.0-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "classmap": [ - "src/" - ] + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-13T04:42:22+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { - "name": "sebastian/type", - "version": "5.1.3", + "name": "symfony/polyfill-php85", + "version": "v1.41.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "255fab485aaa1006ed411040c42aecd7b5302d7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", - "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/255fab485aaa1006ed411040c42aecd7b5302d7a", + "reference": "255fab485aaa1006ed411040c42aecd7b5302d7a", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "require-dev": { - "phpunit/phpunit": "^11.3" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "5.1-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, "classmap": [ - "src/" + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.41.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-09T06:55:48+00:00" + "time": "2026-07-01T12:47:55+00:00" }, { - "name": "sebastian/version", - "version": "5.0.2", + "name": "symfony/process", + "version": "v7.4.17", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + "url": "https://github.com/symfony/process.git", + "reference": "058d17fc284cce14efb2385783b55014a461b176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", - "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "url": "https://api.github.com/repos/symfony/process/zipball/058d17fc284cce14efb2385783b55014a461b176", + "reference": "058d17fc284cce14efb2385783b55014a461b176", "shasum": "" }, "require": { "php": ">=8.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "security": "https://github.com/sebastianbergmann/version/security/policy", - "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + "source": "https://github.com/symfony/process/tree/v7.4.17" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "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-10-09T05:16:32+00:00" + "time": "2026-08-21T17:40:08+00:00" }, { - "name": "slevomat/coding-standard", - "version": "8.22.1", + "name": "symfony/service-contracts", + "version": "v3.7.1", "source": { "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/1dd80bf3b93692bedb21a6623c496887fad05fec", - "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", - "php": "^7.4 || ^8.0", - "phpstan/phpdoc-parser": "^2.3.0", - "squizlabs/php_codesniffer": "^3.13.4" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, - "require-dev": { - "phing/phing": "3.0.1|3.1.0", - "php-parallel-lint/php-parallel-lint": "1.4.0", - "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.36|12.3.10" - }, - "type": "phpcodesniffer-standard", + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-master": "8.x-dev" + "dev-main": "3.7-dev" } }, "autoload": { "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard/" - } + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "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": [ - "dev", - "phpcs" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.22.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { - "url": "https://github.com/kukulich", + "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/slevomat/coding-standard", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-09-13T08:53:30+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { - "name": "squizlabs/php_codesniffer", - "version": "3.13.5", + "name": "symfony/string", + "version": "v7.4.15", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" + "url": "https://github.com/symfony/string.git", + "reference": "e394af32256bf9e7bf80849d95e589167c10097b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "url": "https://api.github.com/repos/symfony/string/zipball/e394af32256bf9e7bf80849d95e589167c10097b", + "reference": "e394af32256bf9e7bf80849d95e589167c10097b", "shasum": "" }, "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" + "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": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + "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" }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "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": [ - "phpcs", - "standards", - "static analysis" + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" ], "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + "source": "https://github.com/symfony/string/tree/v7.4.15" }, "funding": [ { - "url": "https://github.com/PHPCSStandards", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://github.com/jrfnl", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-11-04T16:30:35+00:00" + "time": "2026-07-28T07:33:02+00:00" }, { - "name": "staabm/side-effects-detector", - "version": "1.0.5", + "name": "thecodingmachine/safe", + "version": "v3.4.0", "source": { "type": "git", - "url": "https://github.com/staabm/side-effects-detector.git", - "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", - "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": "^7.4 || ^8.0" + "php": "^8.1" }, "require-dev": { - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.6", - "phpunit/phpunit": "^9.6.21", - "symfony/var-dumper": "^5.4.43", - "tomasvotruba/type-coverage": "1.0.0", - "tomasvotruba/unused-public": "1.0.0" + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10", + "squizlabs/php_codesniffer": "^3.2" }, "type": "library", "autoload": { + "files": [ + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rnp.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], "classmap": [ - "lib/" + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "generated/Exceptions/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "A static analysis tool to detect side effects in PHP code", - "keywords": [ - "static analysis" - ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", "support": { - "issues": "https://github.com/staabm/side-effects-detector/issues", - "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" }, "funding": [ + { + "url": "https://github.com/OskarStark", + "type": "github" + }, + { + "url": "https://github.com/shish", + "type": "github" + }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, { "url": "https://github.com/staabm", "type": "github" } ], - "time": "2024-10-20T05:08:20+00:00" + "time": "2026-02-04T18:08:13+00:00" }, { "name": "theseer/tokenizer", @@ -2554,75 +4507,88 @@ "time": "2025-11-17T20:03:58+00:00" }, { - "name": "webimpress/coding-standard", - "version": "1.4.0", + "name": "webmozart/assert", + "version": "2.4.1", "source": { "type": "git", - "url": "https://github.com/webimpress/coding-standard.git", - "reference": "6f6a1a90bd9e18fc8bee0660dd1d1ce68cf9fc53" + "url": "https://github.com/webmozarts/assert.git", + "reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webimpress/coding-standard/zipball/6f6a1a90bd9e18fc8bee0660dd1d1ce68cf9fc53", - "reference": "6f6a1a90bd9e18fc8bee0660dd1d1ce68cf9fc53", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/2ccb7c2e821038c03a3e6e1700c570c158c55f70", + "reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70", "shasum": "" }, "require": { - "php": "^7.3 || ^8.0", - "squizlabs/php_codesniffer": "^3.10.3" + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^8.2" }, - "require-dev": { - "phpunit/phpunit": "^9.6.15" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, - "type": "phpcodesniffer-standard", + "type": "library", "extra": { - "dev-master": "1.2.x-dev", - "dev-develop": "1.3.x-dev" + "psalm": { + "pluginClass": "Webmozart\\Assert\\PsalmPlugin" + }, + "branch-alias": { + "dev-master": "2.0-dev", + "dev-feature/2-0": "2.0-dev" + } }, "autoload": { "psr-4": { - "WebimpressCodingStandard\\": "src/WebimpressCodingStandard/" + "Webmozart\\Assert\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" + } ], - "description": "Webimpress Coding Standard", + "description": "Assertions to validate method input/output with nice error messages.", "keywords": [ - "Coding Standard", - "PSR-2", - "phpcs", - "psr-12", - "webimpress" + "assert", + "check", + "validate" ], "support": { - "issues": "https://github.com/webimpress/coding-standard/issues", - "source": "https://github.com/webimpress/coding-standard/tree/1.4.0" + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/2.4.1" }, - "funding": [ - { - "url": "https://github.com/michalbundyra", - "type": "github" - } - ], - "time": "2024-10-16T06:55:17+00:00" + "time": "2026-06-15T15:31:57+00:00" } ], "aliases": [], "minimum-stability": "dev", - "stability-flags": {}, + "stability-flags": { + "php-db/phpdb-qa-tools": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + "php": "~8.3.0 || ~8.4.0 || ~8.5.0" }, "platform-dev": { "ext-pdo_pgsql": "*", "ext-pgsql": "*" }, "platform-overrides": { - "php": "8.2.99" + "php": "8.3.99" }, "plugin-api-version": "2.9.0" } diff --git a/coveralls.yml b/coveralls.yml deleted file mode 100644 index bc71b62..0000000 --- a/coveralls.yml +++ /dev/null @@ -1,2 +0,0 @@ -coverage_clover: clover.xml -json_path: coveralls-upload.json diff --git a/infection.json5.dist b/infection.json5.dist new file mode 100644 index 0000000..71b82aa --- /dev/null +++ b/infection.json5.dist @@ -0,0 +1,22 @@ +{ + "$schema": "vendor/infection/infection/resources/schema.json", + "source": { + "directories": [ + "src" + ] + }, + "timeout": 10, + "threads": "max", + "logs": { + "text": "infection.log", + "summary": "summary.log", + "stryker": { + // matches versioned release branches, e.g. "0.1.x", "0.2.x" + "badge": "/^\\d+\\.\\d+\\.x$/" + } + }, + "mutators": { + "@default": true + }, + "staticAnalysisTool": "mago" +} diff --git a/mago.toml b/mago.toml new file mode 100644 index 0000000..4e2bc2b --- /dev/null +++ b/mago.toml @@ -0,0 +1,7 @@ +#:schema https://mago.carthage.software/1.45.0/schema.json +extends = "vendor/php-db/phpdb-qa-tools/mago.toml" +php-version = "8.3.0" + +[source] +paths = ["src", "test"] +includes = ["vendor"] diff --git a/phpcs.xml.dist b/phpcs.xml.dist deleted file mode 100644 index 38effcf..0000000 --- a/phpcs.xml.dist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - src - test - - - - - - - diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index ddb8f5c..0000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,19 +0,0 @@ -parameters: - ignoreErrors: - - - message: '#^PHPDoc tag @throws with type PhpDb\\Adapter\\Exception\\InvalidConnectionParametersException\|PhpDb\\Adapter\\Pgsql\\Exception\\ContainerException is not subtype of Throwable$#' - identifier: throws.notThrowable - count: 1 - path: src/Container/ConnectionInterfaceFactory.php - - - - message: '#^Parameter \#2 \$array of function implode expects array\, array\\> given\.$#' - identifier: argument.type - count: 1 - path: src/Metadata/Source.php - - - - message: '#^Parameter \#2 \$array of function implode expects array\, array\\> given\.$#' - identifier: argument.type - count: 1 - path: src/Metadata/Source.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist deleted file mode 100644 index 4b4e3f6..0000000 --- a/phpstan.neon.dist +++ /dev/null @@ -1,17 +0,0 @@ -includes: - - phpstan-baseline.neon -parameters: - level: 5 - paths: - - src - - test - universalObjectCratesClasses: - - Laminas\Stdlib\ArrayObject - stubFiles: - - stubs/Laminas/ServiceManager/Factory/AbstractFactoryInterface.stub - - stubs/Laminas/ServiceManager/Factory/DelegatorFactoryInterface.stub - - stubs/Laminas/ServiceManager/Factory/FactoryInterface.stub - - stubs/Laminas/ServiceManager/Factory/InvokableFactory.stub - - stubs/Laminas/ServiceManager/Initializer/InitializerInterface.stub - - stubs/Psr/Container/ContainerInterface.stub - treatPhpDocTypesAsCertain: false \ No newline at end of file diff --git a/src/AdapterPlatform.php b/src/AdapterPlatform.php index c245e41..2e05ee4 100644 --- a/src/AdapterPlatform.php +++ b/src/AdapterPlatform.php @@ -20,7 +20,7 @@ class AdapterPlatform extends AbstractPlatform { - public final const PLATFORM_NAME = 'PostgreSQL'; + final public const PLATFORM_NAME = 'PostgreSQL'; /** * Overrides value from AbstractPlatform to use proper escaping for Postgres @@ -29,8 +29,7 @@ class AdapterPlatform extends AbstractPlatform public function __construct( private readonly DriverInterface|PdoDriverInterface|PDO $driver, - ) { - } + ) {} /** * {@inheritDoc} @@ -41,24 +40,19 @@ public function getName(): string return self::PLATFORM_NAME; } - /** - * {@inheritDoc} - */ #[Override] - public function quoteIdentifierChain($identifierChain): string + public function getSqlPlatformDecorator(): PlatformDecoratorInterface { - return '"' . implode('"."', (array) str_replace('"', '""', $identifierChain)) . '"'; + return new SqlPlatformDecorator($this); } /** * {@inheritDoc} */ #[Override] - public function quoteValue($value): string + public function quoteIdentifierChain($identifierChain): string { - $quotedViaDriverValue = $this->quoteViaDriver($value); - - return $quotedViaDriverValue ?? 'E' . parent::quoteValue($value); + return '"' . implode('"."', (array) str_replace('"', '""', $identifierChain)) . '"'; } /** @@ -71,13 +65,24 @@ public function quoteTrustedValue($value): string { $quotedViaDriverValue = $this->quoteViaDriver($value); - if ($quotedViaDriverValue === null) { + if (null === $quotedViaDriverValue) { return 'E' . parent::quoteTrustedValue($value); } return $quotedViaDriverValue; } + /** + * {@inheritDoc} + */ + #[Override] + public function quoteValue($value): string + { + $quotedViaDriverValue = $this->quoteViaDriver($value); + + return $quotedViaDriverValue ?? 'E' . parent::quoteValue($value); + } + /** * @param string $value */ @@ -98,10 +103,4 @@ protected function quoteViaDriver($value): ?string return null; } - - #[Override] - public function getSqlPlatformDecorator(): PlatformDecoratorInterface - { - return new SqlPlatformDecorator($this); - } } diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 5af1c8c..43889fa 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -21,14 +21,6 @@ */ final readonly class ConfigProvider { - public function __invoke(): array - { - return [ - 'dependencies' => $this->getDependencies(), - //AdapterInterface::class => $this->getConfig(), - ]; - } - public function getConfig(): array { return [ @@ -97,4 +89,12 @@ public function getDependencies(): array ], ]; } + + public function __invoke(): array + { + return [ + 'dependencies' => $this->getDependencies(), + //AdapterInterface::class => $this->getConfig(), + ]; + } } diff --git a/src/Connection.php b/src/Connection.php index 0085a7b..323a32b 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -50,39 +50,22 @@ public function __construct(PgSqlConnection|array $connectionInfo) } } - public function setResource( - PgSqlConnection $resource - ): ConnectionInterface&DriverAwareInterface { - $this->resource = $resource; - - return $this; - } - - /** @phpstan-ignore method.childReturnType */ + /** + * {@inheritDoc} + */ #[Override] - public function getResource(): ?PgSqlConnection + public function beginTransaction(): static { - return $this->resource; - } - - #[Override] - public function setDriver( - DriverInterface|Driver $driver - ): ConnectionInterface&DriverAwareInterface { - $this->driver = $driver; - - return $this; - } + if ($this->inTransaction()) { + throw new Exception\RuntimeException('Nested transactions are not supported'); + } - public function setType(?int $type): ConnectionInterface&DriverAwareInterface - { - $invalidConectionType = $type !== PGSQL_CONNECT_FORCE_NEW; - if ($invalidConectionType) { - throw new Exception\InvalidArgumentException( - 'Connection type is not valid. (See: https://php.net/manual/en/function.pg-connect.php)' - ); + if (! $this->isConnected()) { + $this->connect(); } - $this->type = $type; + + pg_query($this->resource, 'BEGIN'); + $this->inTransaction = true; return $this; } @@ -91,18 +74,20 @@ public function setType(?int $type): ConnectionInterface&DriverAwareInterface * {@inheritDoc} */ #[Override] - public function getCurrentSchema(): string|false + public function commit(): static { if (! $this->isConnected()) { $this->connect(); } - $result = pg_query($this->resource, 'SELECT CURRENT_SCHEMA AS "currentschema"'); - if ($result === false) { - return false; + if (! $this->inTransaction()) { + return $this; // We ignore attempts to commit non-existing transaction } - return pg_fetch_result($result, 0, 'currentschema'); + pg_query($this->resource, 'COMMIT'); + $this->inTransaction = false; + + return $this; } /** @@ -118,11 +103,11 @@ public function connect(): static } $connection = $this->getConnectionString(); - set_error_handler(function ($number, $string) { + set_error_handler(static function ($number, $string) { throw new Exception\RuntimeException( self::class . '::connect: Unable to connect to database', $number, - new Exception\ErrorException($string, $number) + new Exception\ErrorException($string, $number), ); }); try { @@ -131,10 +116,10 @@ public function connect(): static restore_error_handler(); } - if ($this->resource === false) { + if (false === $this->resource) { throw new Exception\RuntimeException(sprintf( '%s: Unable to connect to database', - __METHOD__ + __METHOD__, )); } @@ -143,7 +128,7 @@ public function connect(): static throw new Exception\RuntimeException(sprintf( "%s: Unable to set client encoding '%s'", __METHOD__, - $this->connectionParameters['charset'] + $this->connectionParameters['charset'], )); } } @@ -151,15 +136,6 @@ public function connect(): static return $this; } - /** - * {@inheritDoc} - */ - #[Override] - public function isConnected(): bool - { - return $this->resource instanceof PgSqlConnection; - } - /** * {@inheritDoc} */ @@ -173,42 +149,80 @@ public function disconnect(): static /** * {@inheritDoc} + * + * @throws Exception\InvalidQueryException */ #[Override] - public function beginTransaction(): static + public function execute($sql): ResultInterface { - if ($this->inTransaction()) { - throw new Exception\RuntimeException('Nested transactions are not supported'); - } - if (! $this->isConnected()) { $this->connect(); } - pg_query($this->resource, 'BEGIN'); - $this->inTransaction = true; + $this->profiler?->profilerStart($sql); - return $this; + $resultResource = pg_query($this->resource, $sql); + + $this->profiler?->profilerFinish(); + + // if the returnValue is something other than a pg result resource, bypass wrapping it + if (false === $resultResource) { + throw new Exception\InvalidQueryException(pg_last_error($this->resource)); + } + + /** @phpstan-ignore argument.type */ + return $this->driver->createResult($resultResource); } /** * {@inheritDoc} */ #[Override] - public function commit(): static + public function getCurrentSchema(): string|false { if (! $this->isConnected()) { $this->connect(); } - if (! $this->inTransaction()) { - return $this; // We ignore attempts to commit non-existing transaction + $result = pg_query($this->resource, 'SELECT CURRENT_SCHEMA AS "currentschema"'); + if (false === $result) { + return false; } - pg_query($this->resource, 'COMMIT'); - $this->inTransaction = false; + return pg_fetch_result($result, 0, 'currentschema'); + } - return $this; + /** + * {@inheritDoc} + */ + #[Override] + public function getLastGeneratedValue(?string $name = null): string|int|false|null + { + if (null === $name) { + return null; + } + $result = pg_query( + $this->resource, + 'SELECT CURRVAL(\'' . str_replace('\'', '\\\'', $name) . '\') as "currval"', + ); + + return pg_fetch_result($result, 0, 'currval'); + } + + /** @phpstan-ignore method.childReturnType */ + #[Override] + public function getResource(): ?PgSqlConnection + { + return $this->resource; + } + + /** + * {@inheritDoc} + */ + #[Override] + public function isConnected(): bool + { + return $this->resource instanceof PgSqlConnection; } /** @@ -231,48 +245,34 @@ public function rollback(): static return $this; } - /** - * {@inheritDoc} - * - * @throws Exception\InvalidQueryException - */ #[Override] - public function execute($sql): ResultInterface - { - if (! $this->isConnected()) { - $this->connect(); - } - - $this->profiler?->profilerStart($sql); - - $resultResource = pg_query($this->resource, $sql); + public function setDriver( + DriverInterface|Driver $driver, + ): ConnectionInterface&DriverAwareInterface { + $this->driver = $driver; - $this->profiler?->profilerFinish(); + return $this; + } - // if the returnValue is something other than a pg result resource, bypass wrapping it - if ($resultResource === false) { - throw new Exception\InvalidQueryException(pg_last_error($this->resource)); - } + public function setResource( + PgSqlConnection $resource, + ): ConnectionInterface&DriverAwareInterface { + $this->resource = $resource; - /** @phpstan-ignore argument.type */ - return $this->driver->createResult($resultResource); + return $this; } - /** - * {@inheritDoc} - */ - #[Override] - public function getLastGeneratedValue(?string $name = null): string|int|false|null + public function setType(?int $type): ConnectionInterface&DriverAwareInterface { - if ($name === null) { - return null; + $invalidConectionType = PGSQL_CONNECT_FORCE_NEW !== $type; + if ($invalidConectionType) { + throw new Exception\InvalidArgumentException( + 'Connection type is not valid. (See: https://php.net/manual/en/function.pg-connect.php)', + ); } - $result = pg_query( - $this->resource, - 'SELECT CURRVAL(\'' . str_replace('\'', '\\\'', $name) . '\') as "currval"' - ); + $this->type = $type; - return pg_fetch_result($result, 0, 'currval'); + return $this; } /** @@ -291,10 +291,10 @@ private function getConnectionString(): string 'port' => 'port', 'socket' => 'socket', default => throw new Exception\InvalidArgumentException( - 'Connection parameter "' . $name . '" is not valid for Pgsql adapter' + 'Connection parameter "' . $name . '" is not valid for Pgsql adapter', ), }; - if ($name === 'port' && $value !== null) { + if ('port' === $name && null !== $value) { $value = (int) $value; } $conn[$name] = $value; @@ -304,8 +304,8 @@ private function getConnectionString(): string http_build_query( array_filter($conn), '', - ' ' - ) + ' ', + ), ); } } diff --git a/src/Container/ConnectionInterfaceFactory.php b/src/Container/ConnectionInterfaceFactory.php index 70e3805..4009dc9 100644 --- a/src/Container/ConnectionInterfaceFactory.php +++ b/src/Container/ConnectionInterfaceFactory.php @@ -26,12 +26,12 @@ final class ConnectionInterfaceFactory public function __invoke( ContainerInterface $container, string $requestedName, - ?array $options = null + ?array $options = null, ): ConnectionInterface&Connection { - if (! is_array($options['connection']) || $options['connection'] === []) { + if (! is_array($options['connection']) || [] === $options['connection']) { throw new InvalidConnectionParametersException( 'Connection configuration must be an array of parameters passed via $options["connection"]', - $options['connection'] + $options['connection'], ); } return new Connection($options['connection']); diff --git a/src/Container/DriverInterfaceFactory.php b/src/Container/DriverInterfaceFactory.php index 8156852..06b60d8 100644 --- a/src/Container/DriverInterfaceFactory.php +++ b/src/Container/DriverInterfaceFactory.php @@ -15,19 +15,19 @@ final class DriverInterfaceFactory public function __invoke( ContainerInterface&ServiceManager $container, string $requestedName, - ?array $options = null + ?array $options = null, ): DriverInterface { if (! $options['connection']) { throw ContainerException::forService( Pgsql\Driver::class, self::class, - '$options["connection"] must contain an array of connection configuration.' + '$options["connection"] must contain an array of connection configuration.', ); } $connection = $container->build(Pgsql\Connection::class, $options); return new Pgsql\Driver( - connection:$connection, + connection: $connection, statementPrototype: $container->build(Pgsql\Statement::class, ['options' => $options['options'] ?? []]), resultPrototype: new Pgsql\Result(), ); diff --git a/src/Container/MetadataInterfaceFactory.php b/src/Container/MetadataInterfaceFactory.php index 9b0230b..5ecc989 100644 --- a/src/Container/MetadataInterfaceFactory.php +++ b/src/Container/MetadataInterfaceFactory.php @@ -4,6 +4,4 @@ namespace PhpDb\Pgsql\Container; -final class MetadataInterfaceFactory -{ -} +final class MetadataInterfaceFactory {} diff --git a/src/Container/PdoConnectionInterfaceFactory.php b/src/Container/PdoConnectionInterfaceFactory.php index 230d872..37fd495 100644 --- a/src/Container/PdoConnectionInterfaceFactory.php +++ b/src/Container/PdoConnectionInterfaceFactory.php @@ -25,25 +25,25 @@ final class PdoConnectionInterfaceFactory public function __invoke( ContainerInterface $container, string $requestedName, - ?array $options = null + ?array $options = null, ): PdoConnectionInterface&Pdo\Connection { if (! $container->has('config')) { // todo: Once latest PR is merged for 0.5.0 update to use PhpDB\Exception\ContainerException throw ContainerException::forService( Pdo\Connection::class, self::class, - 'Container is missing a config service' + 'Container is missing a config service', ); } $config = $container->get('config'); $connectionInfo = $options['connection'] ?? $config[$requestedName]['connection'] ?? $config[AdapterInterface::class]['adapters'][$requestedName]['connection'] - ?? null; - if ($connectionInfo === null || ! is_array($connectionInfo) || $connectionInfo === []) { + ?? null; + if (null === $connectionInfo || ! is_array($connectionInfo) || [] === $connectionInfo) { throw new InvalidConnectionParametersException( 'Connection configuration must be an array of parameters', - $connectionInfo + $connectionInfo, ); } return new Pdo\Connection($connectionInfo); diff --git a/src/Container/PdoDriverInterfaceFactory.php b/src/Container/PdoDriverInterfaceFactory.php index a6e9c03..c0e9db5 100644 --- a/src/Container/PdoDriverInterfaceFactory.php +++ b/src/Container/PdoDriverInterfaceFactory.php @@ -21,22 +21,22 @@ final class PdoDriverInterfaceFactory public function __invoke( ContainerInterface&ServiceManager $container, string $requestedName, - ?array $options = null + ?array $options = null, ): PdoDriverInterface&Pdo\Driver { if (! $container->has('config')) { // todo: Once latest PR is merged for 0.5.0 update to use PhpDB\Exception\ContainerException throw ContainerException::forService( Pdo\Driver::class, self::class, - 'Container is missing a config service' + 'Container is missing a config service', ); } $config = $container->get('config'); $connectionParameters = $options['connection'] ?? $config[$requestedName]['connection'] ?? $config[AdapterInterface::class]['adapters'][$requestedName]['connection'] - ?? null; - $connection = $container->build(Pdo\Connection::class, ['connection' => $connectionParameters]); + ?? null; + $connection = $container->build(Pdo\Connection::class, ['connection' => $connectionParameters]); return new Pdo\Driver( connection: $connection, statementPrototype: $container->build(Statement::class, ['options' => $options['options'] ?? []]), diff --git a/src/Container/PdoStatementFactory.php b/src/Container/PdoStatementFactory.php index ecf848a..aab3954 100644 --- a/src/Container/PdoStatementFactory.php +++ b/src/Container/PdoStatementFactory.php @@ -14,12 +14,12 @@ final class PdoStatementFactory public function __invoke( ContainerInterface $container, string $requestedName, - ?array $options = null + ?array $options = null, ): StatementInterface&PdoStatement { $statementOptions = $options['options'] ?? []; return new PdoStatement( parameterContainer: new ParameterContainer(), - options: $statementOptions + options: $statementOptions, ); } } diff --git a/src/Container/PlatformInterfaceFactory.php b/src/Container/PlatformInterfaceFactory.php index b34074e..c1ab391 100644 --- a/src/Container/PlatformInterfaceFactory.php +++ b/src/Container/PlatformInterfaceFactory.php @@ -17,18 +17,18 @@ final class PlatformInterfaceFactory public function __invoke( ContainerInterface $container, string $requestedName, - ?array $options = null + ?array $options = null, ): PlatformInterface&Pgsql\AdapterPlatform { $driver = $options['driver'] ?? null; if ( ! $driver instanceof Pgsql\Driver - && ! $driver instanceof Pgsql\Pdo\Driver + && ! $driver instanceof Pgsql\Pdo\Driver ) { // todo: Once latest PR is merged for 0.5.0 update to use PhpDB\Exception\ContainerException throw ContainerException::forService( PlatformInterface::class, self::class, - 'Invalid or missing driver provided' + 'Invalid or missing driver provided', ); } return new Pgsql\AdapterPlatform($driver); diff --git a/src/Container/StatementInterfaceFactory.php b/src/Container/StatementInterfaceFactory.php index e07201c..a583b00 100644 --- a/src/Container/StatementInterfaceFactory.php +++ b/src/Container/StatementInterfaceFactory.php @@ -13,10 +13,10 @@ final class StatementInterfaceFactory public function __invoke( ContainerInterface $container, string $requestedName, - ?array $options = null + ?array $options = null, ): StatementInterface { return new Pgsql\Statement( - options: $options['options'] ?? false + options: $options['options'] ?? false, ); } } diff --git a/src/Driver.php b/src/Driver.php index eacb53e..fb2ebb9 100644 --- a/src/Driver.php +++ b/src/Driver.php @@ -36,57 +36,42 @@ public function __construct( protected readonly DriverAwareInterface&ConnectionInterface&Connection $connection, protected readonly DriverAwareInterface&StatementInterface&Statement $statementPrototype = new Statement(), protected readonly ResultInterface&Result $resultPrototype = new Result(), - array $options = [] + array $options = [], ) { $this->checkEnvironment(); //todo: verify this usage - $options = array_intersect_key(array_merge($this->options, $options), $this->options); + $options = array_intersect_key([...$this->options, ...$options], $this->options); $this->connection->setDriver($this); $this->statementPrototype->setDriver($this); } - #[Override] - public function setProfiler( - ProfilerInterface $profiler - ): DriverInterface&ProfilerAwareInterface { - $this->profiler = $profiler; - - // @phpstan-ignore instanceof.alwaysTrue - if ($this->connection instanceof ProfilerAwareInterface) { - $this->connection->setProfiler($profiler); - } - - // @phpstan-ignore instanceof.alwaysTrue - if ($this->statementPrototype instanceof ProfilerAwareInterface) { - $this->statementPrototype->setProfiler($profiler); - } - - return $this; - } - - public function getProfiler(): ?ProfilerInterface - { - return $this->profiler; - } - #[Override] public function checkEnvironment(): bool { if (! extension_loaded('pgsql')) { throw new Exception\RuntimeException( - 'The PostgreSQL (pgsql) extension is required for this Driver but the extension is not loaded' + 'The PostgreSQL (pgsql) extension is required for this Driver but the extension is not loaded', ); } return true; } + /** + * Create result + * + * @param PgSqlResult|resource $resource + */ #[Override] - public function getConnection(): ConnectionInterface&Connection + public function createResult($resource): ResultInterface&Result { - return $this->connection; + /** @var Result $result */ + $result = clone $this->resultPrototype; + $result->initialize($resource, $this->connection->getLastGeneratedValue()); + + return $result; } /** @@ -112,24 +97,25 @@ public function createStatement($sqlOrResource = null): StatementInterface&State return $statement; } - /** - * Create result - * - * @param PgSqlResult|resource $resource - */ #[Override] - public function createResult($resource): ResultInterface&Result + public function formatParameterName(string $name, ?string $type = null): string { - /** @var Result $result */ - $result = clone $this->resultPrototype; - $result->initialize($resource, $this->connection->getLastGeneratedValue()); + return '$#'; + } - return $result; + #[Override] + public function getConnection(): ConnectionInterface&Connection + { + return $this->connection; } - public function getResultPrototype(): ResultInterface&Result + /** + * Get last generated value + */ + #[Override] + public function getLastGeneratedValue(?string $name = null): int|string|false|null { - return $this->resultPrototype; + return $this->connection->getLastGeneratedValue($name); } #[Override] @@ -138,18 +124,32 @@ public function getPrepareType(): string return self::PARAMETERIZATION_POSITIONAL; } - #[Override] - public function formatParameterName(string $name, ?string $type = null): string + public function getProfiler(): ?ProfilerInterface { - return '$#'; + return $this->profiler; } - /** - * Get last generated value - */ - #[Override] - public function getLastGeneratedValue(?string $name = null): int|string|false|null + public function getResultPrototype(): ResultInterface&Result { - return $this->connection->getLastGeneratedValue($name); + return $this->resultPrototype; + } + + #[Override] + public function setProfiler( + ProfilerInterface $profiler, + ): DriverInterface&ProfilerAwareInterface { + $this->profiler = $profiler; + + // @phpstan-ignore instanceof.alwaysTrue + if ($this->connection instanceof ProfilerAwareInterface) { + $this->connection->setProfiler($profiler); + } + + // @phpstan-ignore instanceof.alwaysTrue + if ($this->statementPrototype instanceof ProfilerAwareInterface) { + $this->statementPrototype->setProfiler($profiler); + } + + return $this; } } diff --git a/src/Metadata/Source.php b/src/Metadata/Source.php index 55f2bf2..11122fe 100644 --- a/src/Metadata/Source.php +++ b/src/Metadata/Source.php @@ -21,91 +21,6 @@ class Source extends AbstractSource { - #[Override] - protected function loadSchemaData(): void - { - if (isset($this->data['schemas'])) { - return; - } - $this->prepareDataHierarchy('schemas'); - - $p = $this->adapter->getPlatform(); - - $sql = 'SELECT ' . $p->quoteIdentifier('schema_name') - . ' FROM ' . $p->quoteIdentifierChain(['information_schema', 'schemata']) - . ' WHERE ' . $p->quoteIdentifier('schema_name') - . ' != \'information_schema\'' - . ' AND ' . $p->quoteIdentifier('schema_name') . " NOT LIKE 'pg_%'"; - - /** @var ResultSet\ResultSetInterface&ResultSet\ResultSet $results */ - $results = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE); - - $schemas = []; - foreach ($results->toArray() as $row) { - $schemas[] = $row['schema_name']; - } - - $this->data['schemas'] = $schemas; - } - - #[Override] - protected function loadTableNameData(string $schema): void - { - if (isset($this->data['table_names'][$schema])) { - return; - } - $this->prepareDataHierarchy('table_names', $schema); - - $p = $this->adapter->getPlatform(); - - $isColumns = [ - ['t', 'table_name'], - ['t', 'table_type'], - ['v', 'view_definition'], - ['v', 'check_option'], - ['v', 'is_updatable'], - ]; - - array_walk($isColumns, function (&$c) use ($p) { - $c = $p->quoteIdentifierChain($c); - }); - - $sql = 'SELECT ' . implode(', ', $isColumns) - . ' FROM ' . $p->quoteIdentifierChain(['information_schema', 'tables']) . ' t' - - . ' LEFT JOIN ' . $p->quoteIdentifierChain(['information_schema', 'views']) . ' v' - . ' ON ' . $p->quoteIdentifierChain(['t', 'table_schema']) - . ' = ' . $p->quoteIdentifierChain(['v', 'table_schema']) - . ' AND ' . $p->quoteIdentifierChain(['t', 'table_name']) - . ' = ' . $p->quoteIdentifierChain(['v', 'table_name']) - - . ' WHERE ' . $p->quoteIdentifierChain(['t', 'table_type']) - . ' IN (\'BASE TABLE\', \'VIEW\')'; - - if ($schema !== self::DEFAULT_SCHEMA) { - $sql .= ' AND ' . $p->quoteIdentifierChain(['t', 'table_schema']) - . ' = ' . $p->quoteTrustedValue($schema); - } else { - $sql .= ' AND ' . $p->quoteIdentifierChain(['t', 'table_schema']) - . ' != \'information_schema\''; - } - - /** @var ResultSet\ResultSetInterface&ResultSet\ResultSet $results */ - $results = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE); - - $tables = []; - foreach ($results->toArray() as $row) { - $tables[$row['table_name']] = [ - 'table_type' => $row['table_type'], - 'view_definition' => $row['view_definition'], - 'check_option' => $row['check_option'], - 'is_updatable' => 'YES' === $row['is_updatable'], - ]; - } - - $this->data['table_names'][$schema] = $tables; - } - #[Override] protected function loadColumnData(string $table, string $schema): void { @@ -130,21 +45,27 @@ protected function loadColumnData(string $table, string $schema): void 'numeric_scale', ]; - array_walk($isColumns, function (&$c) use ($platform) { + array_walk($isColumns, static function (&$c) use ($platform) { $c = $platform->quoteIdentifier($c); }); - $sql = 'SELECT ' . implode(', ', $isColumns) - . ' FROM ' . $platform->quoteIdentifier('information_schema') - . $platform->getIdentifierSeparator() . $platform->quoteIdentifier('columns') - . ' WHERE ' . $platform->quoteIdentifier('table_schema') + $sql = + 'SELECT ' + . implode(', ', $isColumns) + . ' FROM ' + . $platform->quoteIdentifier('information_schema') + . $platform->getIdentifierSeparator() + . $platform->quoteIdentifier('columns') + . ' WHERE ' + . $platform->quoteIdentifier('table_schema') . ' != \'information\'' - . ' AND ' . $platform->quoteIdentifier('table_name') - . ' = ' . $platform->quoteTrustedValue($table); + . ' AND ' + . $platform->quoteIdentifier('table_name') + . ' = ' + . $platform->quoteTrustedValue($table); - if ($schema !== '__DEFAULT_SCHEMA__') { - $sql .= ' AND ' . $platform->quoteIdentifier('table_schema') - . ' = ' . $platform->quoteTrustedValue($schema); + if ('__DEFAULT_SCHEMA__' !== $schema) { + $sql .= " AND {$platform->quoteIdentifier('table_schema')} = {$platform->quoteTrustedValue($schema)}"; } /** @var ResultSet\ResultSetInterface&ResultSet\ResultSet $results */ @@ -194,72 +115,107 @@ protected function loadConstraintData(string $table, string $schema): void $p = $this->adapter->getPlatform(); - array_walk($isColumns, function (&$c) use ($p) { + array_walk($isColumns, static function (&$c) use ($p) { $alias = key($c); $c = $p->quoteIdentifierChain($c); if (is_string($alias)) { - $c .= ' ' . $p->quoteIdentifier($alias); + $c .= " {$p->quoteIdentifier($alias)}"; } }); - $sql = 'SELECT ' . implode(', ', $isColumns) - . ' FROM ' . $p->quoteIdentifierChain(['information_schema', 'tables']) . ' t' - - . ' INNER JOIN ' . $p->quoteIdentifierChain(['information_schema', 'table_constraints']) . ' tc' - . ' ON ' . $p->quoteIdentifierChain(['t', 'table_schema']) - . ' = ' . $p->quoteIdentifierChain(['tc', 'table_schema']) - . ' AND ' . $p->quoteIdentifierChain(['t', 'table_name']) - . ' = ' . $p->quoteIdentifierChain(['tc', 'table_name']) - - . ' LEFT JOIN ' . $p->quoteIdentifierChain(['information_schema', 'key_column_usage']) . ' kcu' - . ' ON ' . $p->quoteIdentifierChain(['tc', 'table_schema']) - . ' = ' . $p->quoteIdentifierChain(['kcu', 'table_schema']) - . ' AND ' . $p->quoteIdentifierChain(['tc', 'table_name']) - . ' = ' . $p->quoteIdentifierChain(['kcu', 'table_name']) - . ' AND ' . $p->quoteIdentifierChain(['tc', 'constraint_name']) - . ' = ' . $p->quoteIdentifierChain(['kcu', 'constraint_name']) - - . ' LEFT JOIN ' . $p->quoteIdentifierChain(['information_schema', 'check_constraints']) . ' cc' - . ' ON ' . $p->quoteIdentifierChain(['tc', 'constraint_schema']) - . ' = ' . $p->quoteIdentifierChain(['cc', 'constraint_schema']) - . ' AND ' . $p->quoteIdentifierChain(['tc', 'constraint_name']) - . ' = ' . $p->quoteIdentifierChain(['cc', 'constraint_name']) - - . ' LEFT JOIN ' . $p->quoteIdentifierChain(['information_schema', 'referential_constraints']) . ' rc' - . ' ON ' . $p->quoteIdentifierChain(['tc', 'constraint_schema']) - . ' = ' . $p->quoteIdentifierChain(['rc', 'constraint_schema']) - . ' AND ' . $p->quoteIdentifierChain(['tc', 'constraint_name']) - . ' = ' . $p->quoteIdentifierChain(['rc', 'constraint_name']) - - . ' LEFT JOIN ' . $p->quoteIdentifierChain(['information_schema', 'key_column_usage']) . ' kcu2' - . ' ON ' . $p->quoteIdentifierChain(['rc', 'unique_constraint_schema']) - . ' = ' . $p->quoteIdentifierChain(['kcu2', 'constraint_schema']) - . ' AND ' . $p->quoteIdentifierChain(['rc', 'unique_constraint_name']) - . ' = ' . $p->quoteIdentifierChain(['kcu2', 'constraint_name']) - . ' AND ' . $p->quoteIdentifierChain(['kcu', 'position_in_unique_constraint']) - . ' = ' . $p->quoteIdentifierChain(['kcu2', 'ordinal_position']) - - . ' WHERE ' . $p->quoteIdentifierChain(['t', 'table_name']) - . ' = ' . $p->quoteTrustedValue($table) - . ' AND ' . $p->quoteIdentifierChain(['t', 'table_type']) - . ' IN (\'BASE TABLE\', \'VIEW\')'; - - if ($schema !== self::DEFAULT_SCHEMA) { - $sql .= ' AND ' . $p->quoteIdentifierChain(['t', 'table_schema']) - . ' = ' . $p->quoteTrustedValue($schema); + $sql = + 'SELECT ' + . implode(', ', $isColumns) + . ' FROM ' + . $p->quoteIdentifierChain(['information_schema', 'tables']) + . ' t' + . ' INNER JOIN ' + . $p->quoteIdentifierChain(['information_schema', 'table_constraints']) + . ' tc' + . ' ON ' + . $p->quoteIdentifierChain(['t', 'table_schema']) + . ' = ' + . $p->quoteIdentifierChain(['tc', 'table_schema']) + . ' AND ' + . $p->quoteIdentifierChain(['t', 'table_name']) + . ' = ' + . $p->quoteIdentifierChain(['tc', 'table_name']) + . ' LEFT JOIN ' + . $p->quoteIdentifierChain(['information_schema', 'key_column_usage']) + . ' kcu' + . ' ON ' + . $p->quoteIdentifierChain(['tc', 'table_schema']) + . ' = ' + . $p->quoteIdentifierChain(['kcu', 'table_schema']) + . ' AND ' + . $p->quoteIdentifierChain(['tc', 'table_name']) + . ' = ' + . $p->quoteIdentifierChain(['kcu', 'table_name']) + . ' AND ' + . $p->quoteIdentifierChain(['tc', 'constraint_name']) + . ' = ' + . $p->quoteIdentifierChain(['kcu', 'constraint_name']) + . ' LEFT JOIN ' + . $p->quoteIdentifierChain(['information_schema', 'check_constraints']) + . ' cc' + . ' ON ' + . $p->quoteIdentifierChain(['tc', 'constraint_schema']) + . ' = ' + . $p->quoteIdentifierChain(['cc', 'constraint_schema']) + . ' AND ' + . $p->quoteIdentifierChain(['tc', 'constraint_name']) + . ' = ' + . $p->quoteIdentifierChain(['cc', 'constraint_name']) + . ' LEFT JOIN ' + . $p->quoteIdentifierChain(['information_schema', 'referential_constraints']) + . ' rc' + . ' ON ' + . $p->quoteIdentifierChain(['tc', 'constraint_schema']) + . ' = ' + . $p->quoteIdentifierChain(['rc', 'constraint_schema']) + . ' AND ' + . $p->quoteIdentifierChain(['tc', 'constraint_name']) + . ' = ' + . $p->quoteIdentifierChain(['rc', 'constraint_name']) + . ' LEFT JOIN ' + . $p->quoteIdentifierChain(['information_schema', 'key_column_usage']) + . ' kcu2' + . ' ON ' + . $p->quoteIdentifierChain(['rc', 'unique_constraint_schema']) + . ' = ' + . $p->quoteIdentifierChain(['kcu2', 'constraint_schema']) + . ' AND ' + . $p->quoteIdentifierChain(['rc', 'unique_constraint_name']) + . ' = ' + . $p->quoteIdentifierChain(['kcu2', 'constraint_name']) + . ' AND ' + . $p->quoteIdentifierChain(['kcu', 'position_in_unique_constraint']) + . ' = ' + . $p->quoteIdentifierChain(['kcu2', 'ordinal_position']) + . ' WHERE ' + . $p->quoteIdentifierChain(['t', 'table_name']) + . ' = ' + . $p->quoteTrustedValue($table) + . ' AND ' + . $p->quoteIdentifierChain(['t', 'table_type']) + . ' IN (\'BASE TABLE\', \'VIEW\')'; + + if (self::DEFAULT_SCHEMA !== $schema) { + $sql .= " AND {$p->quoteIdentifierChain(['t', 'table_schema'])} = {$p->quoteTrustedValue($schema)}"; } else { - $sql .= ' AND ' . $p->quoteIdentifierChain(['t', 'table_schema']) - . ' != \'information_schema\''; + $sql .= + ' AND ' + . $p->quoteIdentifierChain(['t', 'table_schema']) + . ' != \'information_schema\''; } - $sql .= ' ORDER BY CASE ' . $p->quoteIdentifierChain(['tc', 'constraint_type']) - . " WHEN 'PRIMARY KEY' THEN 1" - . " WHEN 'UNIQUE' THEN 2" - . " WHEN 'FOREIGN KEY' THEN 3" - . " WHEN 'CHECK' THEN 4" - . " ELSE 5 END" - . ', ' . $p->quoteIdentifierChain(['tc', 'constraint_name']) - . ', ' . $p->quoteIdentifierChain(['kcu', 'ordinal_position']); + $sql .= " ORDER BY CASE {$p->quoteIdentifierChain([ + 'tc', + 'constraint_type', + ])} WHEN 'PRIMARY KEY' THEN 1 WHEN 'UNIQUE' THEN 2 WHEN 'FOREIGN KEY' THEN 3 WHEN 'CHECK' THEN 4 ELSE 5 END, {$p->quoteIdentifierChain([ + 'tc', + 'constraint_name', + ])}, {$p->quoteIdentifierChain(['kcu', 'ordinal_position'])}"; /** @var ResultSet\ResultSetInterface&ResultSet\ResultSet $results */ $results = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE); @@ -297,9 +253,111 @@ protected function loadConstraintData(string $table, string $schema): void } $this->data['constraints'][$schema][$table] = $constraints; + // phpcs:enable WebimpressCodingStandard.NamingConventions.ValidVariableName.NotCamelCaps } + #[Override] + protected function loadSchemaData(): void + { + if (isset($this->data['schemas'])) { + return; + } + $this->prepareDataHierarchy('schemas'); + + $p = $this->adapter->getPlatform(); + + $sql = + 'SELECT ' + . $p->quoteIdentifier('schema_name') + . ' FROM ' + . $p->quoteIdentifierChain(['information_schema', 'schemata']) + . ' WHERE ' + . $p->quoteIdentifier('schema_name') + . ' != \'information_schema\'' + . ' AND ' + . $p->quoteIdentifier('schema_name') + . " NOT LIKE 'pg_%'"; + + /** @var ResultSet\ResultSetInterface&ResultSet\ResultSet $results */ + $results = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE); + + $schemas = []; + foreach ($results->toArray() as $row) { + $schemas[] = $row['schema_name']; + } + + $this->data['schemas'] = $schemas; + } + + #[Override] + protected function loadTableNameData(string $schema): void + { + if (isset($this->data['table_names'][$schema])) { + return; + } + $this->prepareDataHierarchy('table_names', $schema); + + $p = $this->adapter->getPlatform(); + + $isColumns = [ + ['t', 'table_name'], + ['t', 'table_type'], + ['v', 'view_definition'], + ['v', 'check_option'], + ['v', 'is_updatable'], + ]; + + array_walk($isColumns, static function (&$c) use ($p) { + $c = $p->quoteIdentifierChain($c); + }); + + $sql = + 'SELECT ' + . implode(', ', $isColumns) + . ' FROM ' + . $p->quoteIdentifierChain(['information_schema', 'tables']) + . ' t' + . ' LEFT JOIN ' + . $p->quoteIdentifierChain(['information_schema', 'views']) + . ' v' + . ' ON ' + . $p->quoteIdentifierChain(['t', 'table_schema']) + . ' = ' + . $p->quoteIdentifierChain(['v', 'table_schema']) + . ' AND ' + . $p->quoteIdentifierChain(['t', 'table_name']) + . ' = ' + . $p->quoteIdentifierChain(['v', 'table_name']) + . ' WHERE ' + . $p->quoteIdentifierChain(['t', 'table_type']) + . ' IN (\'BASE TABLE\', \'VIEW\')'; + + if (self::DEFAULT_SCHEMA !== $schema) { + $sql .= " AND {$p->quoteIdentifierChain(['t', 'table_schema'])} = {$p->quoteTrustedValue($schema)}"; + } else { + $sql .= + ' AND ' + . $p->quoteIdentifierChain(['t', 'table_schema']) + . ' != \'information_schema\''; + } + + /** @var ResultSet\ResultSetInterface&ResultSet\ResultSet $results */ + $results = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE); + + $tables = []; + foreach ($results->toArray() as $row) { + $tables[$row['table_name']] = [ + 'table_type' => $row['table_type'], + 'view_definition' => $row['view_definition'], + 'check_option' => $row['check_option'], + 'is_updatable' => 'YES' === $row['is_updatable'], + ]; + } + + $this->data['table_names'][$schema] = $tables; + } + #[Override] protected function loadTriggerData(string $schema): void { @@ -327,27 +385,30 @@ protected function loadTriggerData(string $schema): void 'created', ]; - array_walk($isColumns, function (&$c) use ($p) { + array_walk($isColumns, static function (&$c) use ($p) { if (is_array($c)) { $alias = key($c); $c = $p->quoteIdentifierChain($c); if (is_string($alias)) { - $c .= ' ' . $p->quoteIdentifier($alias); + $c .= " {$p->quoteIdentifier($alias)}"; } } else { $c = $p->quoteIdentifier($c); } }); - $sql = 'SELECT ' . implode(', ', $isColumns) - . ' FROM ' . $p->quoteIdentifierChain(['information_schema', 'triggers']) + $sql = + 'SELECT ' + . implode(', ', $isColumns) + . ' FROM ' + . $p->quoteIdentifierChain(['information_schema', 'triggers']) . ' WHERE '; - if ($schema !== self::DEFAULT_SCHEMA) { - $sql .= $p->quoteIdentifier('trigger_schema') - . ' = ' . $p->quoteTrustedValue($schema); + if (self::DEFAULT_SCHEMA !== $schema) { + $sql .= "{$p->quoteIdentifier('trigger_schema')} = {$p->quoteTrustedValue($schema)}"; } else { - $sql .= $p->quoteIdentifier('trigger_schema') + $sql .= + $p->quoteIdentifier('trigger_schema') . ' != \'information_schema\''; } diff --git a/src/Pdo/Connection.php b/src/Pdo/Connection.php index e3013fd..cbf4afe 100644 --- a/src/Pdo/Connection.php +++ b/src/Pdo/Connection.php @@ -28,7 +28,7 @@ class Connection extends AbstractPdoConnection * @throws Exception\InvalidArgumentException */ public function __construct( - PDO|array $connectionParameters + PDO|array $connectionParameters, ) { if (is_array($connectionParameters)) { $this->setConnectionParameters($connectionParameters); @@ -37,25 +37,6 @@ public function __construct( } } - /** - * {@inheritDoc} - */ - #[Override] - public function getCurrentSchema(): string|false - { - if (! $this->isConnected()) { - $this->connect(); - } - - /** @var PDOStatement $result */ - $result = $this->resource->query('SELECT CURRENT_SCHEMA'); - if ($result instanceof PDOStatement) { - return $result->fetchColumn(); - } - - return false; - } - /** * {@inheritDoc} * @@ -69,23 +50,23 @@ public function connect(): ConnectionInterface&PdoConnectionInterface return $this; } - $dsn = $username = $password = $hostname = $database = null; + $dsn = $username = $password = $hostname = $database = null; $options = []; foreach ($this->connectionParameters as $key => $value) { $result = match (strtolower($key)) { - 'dsn' => $dsn = (string) $value, - 'user', 'username' => $username = (string) $value, - 'password', 'passwd', 'pw' => $password = (string) $value, - 'host', 'hostname' => $hostname = (string) $value, - 'port' => $port = (int) $value, - 'dbname', 'database', 'db', 'schema' => $database = (string) $value, + 'dsn' => $dsn = (string) $value, + 'user', 'username' => $username = (string) $value, + 'password', 'passwd', 'pw' => $password = (string) $value, + 'host', 'hostname' => $hostname = (string) $value, + 'port' => $port = (int) $value, + 'dbname', 'database', 'db', 'schema' => $database = (string) $value, 'unix_socket' => $unixSocket = (string) $value, // todo: should we suppport sslmode for pdo pgsql? - 'driver_options' => (function (&$options, $value): void { + 'driver_options' => (static function (&$options, $value): void { $value = (array) $value; $options = array_diff_key($options, $value) + $value; })($options, $value), - default => $options[$key] = $value, + default => $options[$key] = $value, }; } unset($result); @@ -118,12 +99,12 @@ public function connect(): ConnectionInterface&PdoConnectionInterface if ( ! str_contains($dsn, 'host=') - && ! str_contains($dsn, 'dbname=') - && ! str_contains($dsn, 'user=') + && ! str_contains($dsn, 'dbname=') + && ! str_contains($dsn, 'user=') ) { throw new Exception\InvalidConnectionParametersException( 'A dsn was not provided or could not be constructed from your parameters', - $this->connectionParameters + $this->connectionParameters, ); } @@ -138,12 +119,31 @@ public function connect(): ConnectionInterface&PdoConnectionInterface if (! is_int($code)) { $code = 0; } - throw new Exception\RuntimeException('Connect Error: ' . $e->getMessage(), $code, $e); + throw new Exception\RuntimeException("Connect Error: {$e->getMessage()}", $code, $e); } return $this; } + /** + * {@inheritDoc} + */ + #[Override] + public function getCurrentSchema(): string|false + { + if (! $this->isConnected()) { + $this->connect(); + } + + /** @var PDOStatement $result */ + $result = $this->resource->query('SELECT CURRENT_SCHEMA'); + if ($result instanceof PDOStatement) { + return $result->fetchColumn(); + } + + return false; + } + /** * {@inheritDoc} * diff --git a/src/Result.php b/src/Result.php index fb18b10..b5a8f1e 100644 --- a/src/Result.php +++ b/src/Result.php @@ -25,49 +25,55 @@ class Result implements ResultInterface protected mixed $generatedValue; - public function initialize(PgSqlResult $resource, string|int|null $generatedValue): void + #[Override] + public function buffer(): void {} + + #[Override] + public function count(): int { - $this->resource = $resource; - $this->count = pg_num_rows($this->resource); - $this->generatedValue = $generatedValue; + return $this->count; } #[Override] public function current(): array|false { - if ($this->count === 0) { + if (0 === $this->count) { return false; } return pg_fetch_assoc($this->resource, $this->position); } #[Override] - public function next(): void + public function getAffectedRows(): int { - $this->position++; + return pg_affected_rows($this->resource); } #[Override] - public function key(): int + public function getFieldCount(): int { - return $this->position; + return pg_num_fields($this->resource); } #[Override] - public function valid(): bool + public function getGeneratedValue(): int|string|false|null { - return $this->position < $this->count; + return $this->generatedValue; } - #[Override] - public function rewind(): void + /** + * Get resource + */ + public function getResource(): PgSqlResult { - $this->position = 0; + return $this->resource; } - #[Override] - public function buffer(): void + public function initialize(PgSqlResult $resource, string|int|null $generatedValue): void { + $this->resource = $resource; + $this->count = pg_num_rows($this->resource); + $this->generatedValue = $generatedValue; } #[Override] @@ -83,34 +89,26 @@ public function isQueryResult(): bool } #[Override] - public function getAffectedRows(): int + public function key(): int { - return pg_affected_rows($this->resource); + return $this->position; } #[Override] - public function getGeneratedValue(): int|string|false|null - { - return $this->generatedValue; - } - - /** - * Get resource - */ - public function getResource(): PgSqlResult + public function next(): void { - return $this->resource; + $this->position++; } #[Override] - public function count(): int + public function rewind(): void { - return $this->count; + $this->position = 0; } #[Override] - public function getFieldCount(): int + public function valid(): bool { - return pg_num_fields($this->resource); + return $this->position < $this->count; } } diff --git a/src/Statement.php b/src/Statement.php index a649346..d08e41a 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -22,10 +22,7 @@ use function pg_prepare; use function preg_replace_callback; -class Statement implements - StatementInterface, - DriverAwareInterface, - ProfilerAwareInterface +class Statement implements StatementInterface, DriverAwareInterface, ProfilerAwareInterface { protected bool $bufferResults = false; @@ -45,7 +42,7 @@ class Statement implements public function __construct( protected ParameterContainer $parameterContainer = new ParameterContainer(), - array|bool $options = false + array|bool $options = false, ) { if (is_array($options)) { $this->bufferResults = $options['buffer_results'] ?? false; @@ -54,20 +51,50 @@ public function __construct( } } + /** + * Execute + * + * @throws Exception\InvalidQueryException + */ #[Override] - public function setDriver( - DriverInterface $driver - ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { - $this->driver = $driver; - return $this; + public function execute(ParameterContainer|array|null $parameters = null): ?ResultInterface + { + if (! $this->isPrepared()) { + $this->prepare(); + } + + /** START Standard ParameterContainer Merging Block */ + if ($parameters instanceof ParameterContainer) { + $this->parameterContainer = $parameters; + $parameters = null; + } + + if (is_array($parameters)) { + $this->parameterContainer->setFromArray($parameters); + } + + if ($this->parameterContainer->count() > 0) { + $parameters = $this->parameterContainer->getPositionalArray(); + } + /** END Standard ParameterContainer Merging Block */ + + $this->profiler?->profilerStart($this); + + $resultResource = pg_execute($this->pgsql, $this->statementName, (array) $parameters); + + $this->profiler?->profilerFinish(); + + if (false === $resultResource) { + throw new Exception\InvalidQueryException(pg_last_error()); + } + /** @phpstan-ignore argument.type */ + return $this->driver->createResult($resultResource); } #[Override] - public function setProfiler( - ProfilerInterface $profiler - ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { - $this->profiler = $profiler; - return $this; + public function getParameterContainer(): ParameterContainer + { + return $this->parameterContainer; } public function getProfiler(): ?ProfilerInterface @@ -75,109 +102,79 @@ public function getProfiler(): ?ProfilerInterface return $this->profiler; } - public function initialize(PgSqlConnection $pgsql): void - { - $this->pgsql = $pgsql; - } - #[Override] public function getResource(): PgSqlResult|false { return $this->resource; } - #[Override] - public function setSql( - ?string $sql - ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { - $this->sql = $sql; - return $this; - } - #[Override] public function getSql(): ?string { return $this->sql; } - #[Override] - public function setParameterContainer( - ParameterContainer $parameterContainer - ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { - $this->parameterContainer = $parameterContainer; - return $this; + public function initialize(PgSqlConnection $pgsql): void + { + $this->pgsql = $pgsql; } #[Override] - public function getParameterContainer(): ParameterContainer + public function isPrepared(): bool { - return $this->parameterContainer; + return isset($this->resource); } #[Override] public function prepare( - ?string $sql = null + ?string $sql = null, ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { - $sql = $sql ?? $this->sql; + $sql ??= $this->sql; $pCount = 1; $sql = preg_replace_callback( '#\$\##', - function () use (&$pCount) { + static function () use (&$pCount) { return '$' . $pCount++; }, - $sql + $sql, ); - $this->sql = $sql; + $this->sql = $sql; $this->statementName .= ++static::$statementIndex; - $this->resource = pg_prepare($this->pgsql, $this->statementName, $sql); + $this->resource = pg_prepare($this->pgsql, $this->statementName, $sql); return $this; } #[Override] - public function isPrepared(): bool - { - return isset($this->resource); + public function setDriver( + DriverInterface $driver, + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { + $this->driver = $driver; + return $this; } - /** - * Execute - * - * @throws Exception\InvalidQueryException - */ #[Override] - public function execute(ParameterContainer|array|null $parameters = null): ?ResultInterface - { - if (! $this->isPrepared()) { - $this->prepare(); - } - - /** START Standard ParameterContainer Merging Block */ - if ($parameters instanceof ParameterContainer) { - $this->parameterContainer = $parameters; - $parameters = null; - } - - if (is_array($parameters)) { - $this->parameterContainer->setFromArray($parameters); - } - - if ($this->parameterContainer->count() > 0) { - $parameters = $this->parameterContainer->getPositionalArray(); - } - /** END Standard ParameterContainer Merging Block */ - - $this->profiler?->profilerStart($this); - - $resultResource = pg_execute($this->pgsql, $this->statementName, (array) $parameters); + public function setParameterContainer( + ParameterContainer $parameterContainer, + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { + $this->parameterContainer = $parameterContainer; + return $this; + } - $this->profiler?->profilerFinish(); + #[Override] + public function setProfiler( + ProfilerInterface $profiler, + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { + $this->profiler = $profiler; + return $this; + } - if ($resultResource === false) { - throw new Exception\InvalidQueryException(pg_last_error()); - } - /** @phpstan-ignore argument.type */ - return $this->driver->createResult($resultResource); + #[Override] + public function setSql( + ?string $sql, + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { + $this->sql = $sql; + return $this; } } diff --git a/stubs/Laminas/ServiceManager/Factory/AbstractFactoryInterface.stub b/stubs/Laminas/ServiceManager/Factory/AbstractFactoryInterface.stub deleted file mode 100644 index a129cb1..0000000 --- a/stubs/Laminas/ServiceManager/Factory/AbstractFactoryInterface.stub +++ /dev/null @@ -1,19 +0,0 @@ -|null $options - */ - public function __invoke( - ContainerInterface $container, - string $name, - callable $callback, - ?array $options = null - ): mixed; -} diff --git a/stubs/Laminas/ServiceManager/Factory/FactoryInterface.stub b/stubs/Laminas/ServiceManager/Factory/FactoryInterface.stub deleted file mode 100644 index e1d6ac5..0000000 --- a/stubs/Laminas/ServiceManager/Factory/FactoryInterface.stub +++ /dev/null @@ -1,21 +0,0 @@ -|null $options - */ - public function __invoke(ContainerInterface $container, string $requestedName, ?array $options = null): mixed; -} diff --git a/stubs/Laminas/ServiceManager/Factory/InvokableFactory.stub b/stubs/Laminas/ServiceManager/Factory/InvokableFactory.stub deleted file mode 100644 index 47d7303..0000000 --- a/stubs/Laminas/ServiceManager/Factory/InvokableFactory.stub +++ /dev/null @@ -1,22 +0,0 @@ -|null $options - */ - public function __invoke(ContainerInterface $container, string $requestedName, ?array $options = null): mixed - { - return null === $options ? new $requestedName() : new $requestedName($options); - } -} diff --git a/stubs/Laminas/ServiceManager/Initializer/InitializerInterface.stub b/stubs/Laminas/ServiceManager/Initializer/InitializerInterface.stub deleted file mode 100644 index 345c9a3..0000000 --- a/stubs/Laminas/ServiceManager/Initializer/InitializerInterface.stub +++ /dev/null @@ -1,19 +0,0 @@ - (string) getenv('TESTS_PHPDB_PGSQL_HOSTNAME'), - 'port' => 5432, - 'username' => (string) getenv('TESTS_PHPDB_PGSQL_USERNAME'), - 'password' => (string) getenv('TESTS_PHPDB_PGSQL_PASSWORD'), - 'database' => (string) getenv('TESTS_PHPDB_PGSQL_DATABASE'), - ]; - $this->conn = $conn; - parent::setUp(); - } public function getAdapter(string $adapter = self::NATIVE_ADAPTER): AdapterInterface { @@ -46,35 +35,19 @@ public function getAdapter(string $adapter = self::NATIVE_ADAPTER): AdapterInter 'services' => [ 'config' => $this->getTestConfig(), ], - ] + ], ); $serviceManagerConfig = ArrayUtils::merge( $serviceManagerConfig, - (new PhpDbConfigProvider())()['dependencies'] + (new PhpDbConfigProvider())()['dependencies'], ); $this->serviceManager = new ServiceManager($serviceManagerConfig); return $this->serviceManager->get($adapter); } - public function getTestConfig(): array + public function getHostname(): string { - return [ - AdapterInterface::class => [ - 'driver' => Pgsql\Driver::class, - 'connection' => $this->conn, - // Named Adapter configurations - PhpDbConfigProvider::NAMED_ADAPTER_KEY => [ - self::NATIVE_ADAPTER => [ - 'driver' => Pgsql\Driver::class, - 'connection' => $this->conn, - ], - self::PDO_ADAPTER => [ - 'driver' => Pgsql\Pdo\Driver::class, - 'connection' => $this->conn, - ], - ], - ], - ]; + return $this->conn['host']; } public function getMockedAdapter(string $adapter = self::NATIVE_ADAPTER): AdapterInterface @@ -129,10 +102,10 @@ public function getMockedAdapter(string $adapter = self::NATIVE_ADAPTER): Adapte PlatformInterface::class => Pgsql\AdapterPlatform::class, ], 'factories' => [ - Pgsql\Driver::class => function (ContainerInterface $container) use ($driverMock) { + Pgsql\Driver::class => static function (ContainerInterface $container) use ($driverMock) { return $driverMock; }, - Pgsql\Pdo\Driver::class => function (ContainerInterface $container) use ($pdoDriverMock) { + Pgsql\Pdo\Driver::class => static function (ContainerInterface $container) use ($pdoDriverMock) { return $pdoDriverMock; }, ], @@ -147,15 +120,44 @@ public function getMockedAdapter(string $adapter = self::NATIVE_ADAPTER): Adapte 'services' => [ 'config' => $config, ], - ] + ], ); $this->serviceManager = new ServiceManager($serviceManagerConfig); return $this->serviceManager->get($adapter); } - public function getHostname(): string + public function getTestConfig(): array { - return $this->conn['host']; + return [ + AdapterInterface::class => [ + 'driver' => Pgsql\Driver::class, + 'connection' => $this->conn, + // Named Adapter configurations + PhpDbConfigProvider::NAMED_ADAPTER_KEY => [ + self::NATIVE_ADAPTER => [ + 'driver' => Pgsql\Driver::class, + 'connection' => $this->conn, + ], + self::PDO_ADAPTER => [ + 'driver' => Pgsql\Pdo\Driver::class, + 'connection' => $this->conn, + ], + ], + ], + ]; + } + + protected function setUp(): void + { + $conn = [ + 'host' => (string) getenv('TESTS_PHPDB_PGSQL_HOSTNAME'), + 'port' => 5432, + 'username' => (string) getenv('TESTS_PHPDB_PGSQL_USERNAME'), + 'password' => (string) getenv('TESTS_PHPDB_PGSQL_PASSWORD'), + 'database' => (string) getenv('TESTS_PHPDB_PGSQL_DATABASE'), + ]; + $this->conn = $conn; + parent::setUp(); } } diff --git a/test/integration/AdapterPlatformTest.php b/test/integration/AdapterPlatformTest.php index 2dca1ed..6352012 100644 --- a/test/integration/AdapterPlatformTest.php +++ b/test/integration/AdapterPlatformTest.php @@ -17,23 +17,24 @@ final class AdapterPlatformTest extends TestCase { use SetupTrait; - public function testQuoteValueWithPgsql(): void + public function testQuoteValueWithPdoPgsql(): void { - $adapter = $this->getAdapter(self::NATIVE_ADAPTER); + $adapter = $this->getAdapter(self::PDO_ADAPTER); $pgsql = $adapter->getPlatform(); - $this->expectException(VunerablePlatformQuoteException::class); + //$this->expectException(VunerablePlatformQuoteException::class); $value = $pgsql->quoteValue('value'); self::assertEquals('\'value\'', $value); - // Should this assertion be? - //todo: self::assertEquals('E\'value\'', $value); } - public function testQuoteValueWithPdoPgsql(): void + public function testQuoteValueWithPgsql(): void { - $adapter = $this->getAdapter(self::PDO_ADAPTER); + $adapter = $this->getAdapter(self::NATIVE_ADAPTER); $pgsql = $adapter->getPlatform(); - //$this->expectException(VunerablePlatformQuoteException::class); + $this->expectException(VunerablePlatformQuoteException::class); $value = $pgsql->quoteValue('value'); self::assertEquals('\'value\'', $value); + + // Should this assertion be? + //todo: self::assertEquals('E\'value\'', $value); } } diff --git a/test/integration/AdapterTest.php b/test/integration/AdapterTest.php index 8c80a67..3a25287 100644 --- a/test/integration/AdapterTest.php +++ b/test/integration/AdapterTest.php @@ -29,15 +29,6 @@ public function testConnection(): void $this->assertInstanceOf(ConnectionInterface::class, $connection); } - public function testGetCurrentSchema(): void - { - /** @var AdapterInterface&SchemaAwareInterface&Adapter $adapter */ - $adapter = $this->getAdapter(); - $schema = $adapter->getCurrentSchema(); - self::assertIsString($schema); - self::assertNotEmpty($schema); - } - public function testDriverDisconnectAfterQuoteWithPlatform(): void { $isTcpConnection = $this->isTcpConnection(); @@ -75,9 +66,18 @@ public function testDriverDisconnectAfterQuoteWithPlatform(): void } } + public function testGetCurrentSchema(): void + { + /** @var AdapterInterface&SchemaAwareInterface&Adapter $adapter */ + $adapter = $this->getAdapter(); + $schema = $adapter->getCurrentSchema(); + self::assertIsString($schema); + self::assertNotEmpty($schema); + } + protected function isTcpConnection(): bool { $hostName = $this->getHostname(); - return $hostName !== 'localhost' && $hostName !== '127.0.0.1'; + return 'localhost' !== $hostName && '127.0.0.1' !== $hostName; } } diff --git a/test/integration/Extension/IntegrationTestStoppedListener.php b/test/integration/Extension/IntegrationTestStoppedListener.php index ccd56d4..f3b1fbc 100644 --- a/test/integration/Extension/IntegrationTestStoppedListener.php +++ b/test/integration/Extension/IntegrationTestStoppedListener.php @@ -19,7 +19,7 @@ public function notify(Finished $event): void { if ( $event->testSuite()->name() !== 'integration test' - || empty($this->fixtureLoaders) + || empty($this->fixtureLoaders) ) { return; } diff --git a/test/integration/Extension/ListenerExtension.php b/test/integration/Extension/ListenerExtension.php index ba9cd13..daec995 100644 --- a/test/integration/Extension/ListenerExtension.php +++ b/test/integration/Extension/ListenerExtension.php @@ -14,7 +14,7 @@ final class ListenerExtension implements Extension public function bootstrap( Configuration $configuration, Facade $facade, - ParameterCollection $parameters + ParameterCollection $parameters, ): void { $facade->registerSubscribers( new IntegrationTestStartedListener(), diff --git a/test/integration/FixtureLoader/PgsqlFixtureLoader.php b/test/integration/FixtureLoader/PgsqlFixtureLoader.php index a9655f2..5fa5b0c 100644 --- a/test/integration/FixtureLoader/PgsqlFixtureLoader.php +++ b/test/integration/FixtureLoader/PgsqlFixtureLoader.php @@ -33,14 +33,14 @@ public function createDatabase(): void if ( false === $this->pdo->exec(sprintf( - "CREATE DATABASE %s", - getenv('TESTS_PHPDB_PGSQL_DATABASE') + 'CREATE DATABASE %s', + getenv('TESTS_PHPDB_PGSQL_DATABASE'), )) ) { throw new Exception(sprintf( - "I cannot create the PostgreSQL %s test database: %s", + 'I cannot create the PostgreSQL %s test database: %s', getenv('TESTS_PHPDB_PGSQL_DATABASE'), - print_r($this->pdo->errorInfo(), true) + print_r($this->pdo->errorInfo(), true), )); } @@ -51,10 +51,10 @@ public function createDatabase(): void if (false === $this->pdo->exec(file_get_contents($this->fixtureFile))) { throw new Exception(sprintf( - "I cannot create the table for %s database. Check the %s file. %s ", + 'I cannot create the table for %s database. Check the %s file. %s ', getenv('TESTS_PHPDB_PGSQL_DATABASE'), $this->fixtureFile, - print_r($this->pdo->errorInfo(), true) + print_r($this->pdo->errorInfo(), true), )); } @@ -74,8 +74,8 @@ public function dropDatabase(): void $this->connect(); $this->pdo->exec(sprintf( - "DROP DATABASE IF EXISTS %s", - getenv('TESTS_PHPDB_PGSQL_DATABASE') + 'DROP DATABASE IF EXISTS %s', + getenv('TESTS_PHPDB_PGSQL_DATABASE'), )); $this->disconnect(); @@ -95,7 +95,7 @@ protected function connect(bool $useDb = false): void $this->pdo = new PDO( $dsn, getenv('TESTS_PHPDB_PGSQL_USERNAME'), - getenv('TESTS_PHPDB_PGSQL_PASSWORD') + getenv('TESTS_PHPDB_PGSQL_PASSWORD'), ); } diff --git a/test/integration/Pdo/AdapterTest.php b/test/integration/Pdo/AdapterTest.php index 50b23a8..a0cf2ed 100644 --- a/test/integration/Pdo/AdapterTest.php +++ b/test/integration/Pdo/AdapterTest.php @@ -29,15 +29,6 @@ public function testConnection(): void $this->assertInstanceOf(ConnectionInterface::class, $connection); } - public function testGetCurrentSchema(): void - { - /** @var AdapterInterface&SchemaAwareInterface&Adapter $adapter */ - $adapter = $this->getAdapter(self::PDO_ADAPTER); - $schema = $adapter->getCurrentSchema(); - self::assertIsString($schema); - self::assertNotEmpty($schema); - } - public function testDriverDisconnectAfterQuoteWithPlatform(): void { $isTcpConnection = $this->isTcpConnection(); @@ -76,9 +67,18 @@ public function testDriverDisconnectAfterQuoteWithPlatform(): void } } + public function testGetCurrentSchema(): void + { + /** @var AdapterInterface&SchemaAwareInterface&Adapter $adapter */ + $adapter = $this->getAdapter(self::PDO_ADAPTER); + $schema = $adapter->getCurrentSchema(); + self::assertIsString($schema); + self::assertNotEmpty($schema); + } + protected function isTcpConnection(): bool { $hostName = $this->getHostname(); - return $hostName !== 'localhost' && $hostName !== '127.0.0.1'; + return 'localhost' !== $hostName && '127.0.0.1' !== $hostName; } } diff --git a/test/unit/Adapter/ConfigProviderTest.php b/test/unit/Adapter/ConfigProviderTest.php index b887706..e5544ec 100644 --- a/test/unit/Adapter/ConfigProviderTest.php +++ b/test/unit/Adapter/ConfigProviderTest.php @@ -57,6 +57,12 @@ final class ConfigProviderTest extends TestCase ], ]; + #[Depends('testProvidesExpectedConfiguration')] + public function testInvocationProvidesDependencyConfiguration(Pgsql\ConfigProvider $provider): void + { + self::assertEquals(['dependencies' => $provider->getDependencies()], $provider()); + } + public function testProvidesExpectedConfiguration(): Pgsql\ConfigProvider { $provider = new Pgsql\ConfigProvider(); @@ -64,10 +70,4 @@ public function testProvidesExpectedConfiguration(): Pgsql\ConfigProvider return $provider; } - - #[Depends('testProvidesExpectedConfiguration')] - public function testInvocationProvidesDependencyConfiguration(Pgsql\ConfigProvider $provider): void - { - self::assertEquals(['dependencies' => $provider->getDependencies()], $provider()); - } } From 02eb97ade47fcd0163f0980153eefc6588fd9a91 Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 24 Aug 2026 15:25:22 +1000 Subject: [PATCH 2/8] Baseline the existing mago lint and analyzer findings Mago is stricter than the PHPStan level 5 baseline it replaces, so the 123 linter and 231 analyzer findings already present are recorded in lint-baseline.toml and analyzer-baseline.toml, matching the rest of the org. format --check, lint, analyze and guard all pass, and new findings in new code still fail. --- .gitattributes | 2 + analyzer-baseline.toml | 1009 ++++++++++++++++++++++++++++++++++++++++ lint-baseline.toml | 439 +++++++++++++++++ mago.toml | 6 + 4 files changed, 1456 insertions(+) create mode 100644 analyzer-baseline.toml create mode 100644 lint-baseline.toml diff --git a/.gitattributes b/.gitattributes index 03e07ab..a43edfe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,5 +8,7 @@ /codecov.yml export-ignore /infection.json5.dist export-ignore /mago.toml export-ignore +/lint-baseline.toml export-ignore +/analyzer-baseline.toml export-ignore /compose.yml export-ignore /docker/ export-ignore diff --git a/analyzer-baseline.toml b/analyzer-baseline.toml new file mode 100644 index 0000000..d6705b5 --- /dev/null +++ b/analyzer-baseline.toml @@ -0,0 +1,1009 @@ +variant = "loose" + +[[issues]] +file = "src/AdapterPlatform.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\AdapterPlatform` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "docblock-type-mismatch" +message = "Docblock type mismatch for variable `$resource`." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "impossible-condition" +message = "This condition (type `false`) will always evaluate to false." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "impossible-type-comparison" +message = "Impossible condition: variable `$resource` (type `string`) can never be `open-resource`." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "impossible-type-comparison" +message = "Impossible type assertion: `$resource` of type `string` can never be `open-resource`." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "missing-constant-type" +message = "Class constant `PLATFORM_NAME` is missing a type hint." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "missing-parameter-type" +message = "Parameter `$value` is missing a type hint." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "mixed-return-statement" +message = 'Could not infer a precise return type for function `PhpDb\Pgsql\AdapterPlatform::quoteViaDriver`. Saw type `mixed`.' +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "possibly-invalid-argument" +message = 'Possible argument type mismatch for argument #1 of `PhpDb\Pgsql\AdapterPlatform::quoteViaDriver`: expected `string`, but possibly received `scalar`.' +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "possibly-null-operand" +message = "Possibly null right operand used in string concatenation (type `null|string`)." +count = 1 + +[[issues]] +file = "src/AdapterPlatform.php" +code = "redundant-logical-operation" +message = "Redundant `||` operation: left operand is evaluated and right operand is always falsy." +count = 1 + +[[issues]] +file = "src/ConfigProvider.php" +code = "imprecise-type" +message = "Type `array` in return type of `__invoke` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/ConfigProvider.php" +code = "imprecise-type" +message = "Type `array` in return type of `getConfig` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/ConfigProvider.php" +code = "imprecise-type" +message = "Type `array` in return type of `getDependencies` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\Connection` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "docblock-type-mismatch" +message = 'Docblock return type `null|resource` is incompatible with native return type `PgSql\Connection|null`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "impossible-condition" +message = "This condition (type `false`) will always evaluate to false." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "imprecise-type" +message = "Type `array` in parameter `$connectionInfo` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "incompatible-property-type" +message = 'Property `PhpDb\Pgsql\Connection::$resource` has an incompatible type declaration from docblock.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "invalid-argument" +message = 'Invalid argument type for argument #1 of `PhpDb\Adapter\Driver\DriverInterface::createResult`: expected `resource`, but found `PgSql\Result`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "invalid-property-assignment-value" +message = 'Invalid type for property `$resource`: expected `PgSql\Connection|null`, but got `PgSql\Connection|false`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "invalid-return-statement" +message = 'Invalid return type for function `PhpDb\Pgsql\Connection::getCurrentSchema`: expected `false|string`, but found `false|null|string`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "invalid-return-statement" +message = 'Invalid return type for function `PhpDb\Pgsql\Connection::getResource`: expected `null|resource`, but found `PgSql\Connection|null`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "less-specific-argument" +message = "Argument type mismatch for argument #1 of `strtolower`: expected `string`, but provided type `array-key` is less specific." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #1 of `Exception::__construct`: expected `string`, but found `mixed`." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #2 of `Exception::__construct`: expected `int`, but found `mixed`." +count = 2 + +[[issues]] +file = "src/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #2 of `pg_set_client_encoding`: expected `string`, but found `truthy-mixed`." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #3 of `sprintf`: expected `Stringable|null|scalar`, but found `truthy-mixed`." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "mixed-assignment" +message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "nullable-return-statement" +message = 'Function `PhpDb\Pgsql\Connection::getCurrentSchema` is declared to return `false|string` but possibly returns a nullable value (inferred as `false|null|string`).' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "possibly-false-argument" +message = 'Argument #1 of function `pg_fetch_result` is possibly `false`, but parameter type `PgSql\Result` does not accept it.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "possibly-null-argument" +message = 'Argument #1 of function `pg_query` is possibly `null`, but parameter type `PgSql\Connection|string` does not accept it.' +count = 6 + +[[issues]] +file = "src/Connection.php" +code = "possibly-null-argument" +message = 'Argument #1 of function `pg_set_client_encoding` is possibly `null`, but parameter type `PgSql\Connection|string` does not accept it.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "redundant-comparison" +message = "Redundant `===` comparison: left-hand side is never identical to right-hand side." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Connection::beginTransaction`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Connection::commit`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Connection::execute`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Connection::getCurrentSchema`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Connection::rollback`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `{closure:src/Connection.php:106:27}`.' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "uninitialized-property" +message = 'Property `$driver` is not initialized in the constructor of class `PhpDb\Pgsql\Connection`.' +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "mixed-argument" +message = 'Invalid argument type for argument #2 of `PhpDb\Adapter\Exception\InvalidConnectionParametersException::__construct`: expected `array`, but found `mixed`.' +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "non-existent-use-import" +message = 'Imported class, interface, trait, or enum `PhpDb\Adapter\Pgsql\Exception\ContainerException` does not exist.' +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "possibly-null-array-access" +message = "Cannot perform array access on possibly `null` value." +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('connection')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$container` is never used." +count = 1 + +[[issues]] +file = "src/Container/ConnectionInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$requestedName` is never used." +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "possibly-null-array-access" +message = "Cannot perform array access on possibly `null` value." +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('connection')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Laminas\ServiceManager\Exception\ServiceNotCreatedException` in `PhpDb\Pgsql\Container\DriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Exception\ContainerException` in `PhpDb\Pgsql\Container\DriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Psr\Container\ContainerExceptionInterface` in `PhpDb\Pgsql\Container\DriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/DriverInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$requestedName` is never used." +count = 1 + +[[issues]] +file = "src/Container/PdoConnectionInterfaceFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/PdoConnectionInterfaceFactory.php" +code = "mixed-argument" +message = 'Invalid argument type for argument #2 of `PhpDb\Adapter\Exception\InvalidConnectionParametersException::__construct`: expected `array`, but found `mixed`.' +count = 1 + +[[issues]] +file = "src/Container/PdoConnectionInterfaceFactory.php" +code = "mixed-assignment" +message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 2 + +[[issues]] +file = "src/Container/PdoConnectionInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Psr\Container\ContainerExceptionInterface` in `PhpDb\Pgsql\Container\PdoConnectionInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/PdoConnectionInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Psr\Container\NotFoundExceptionInterface` in `PhpDb\Pgsql\Container\PdoConnectionInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "mixed-assignment" +message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 2 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Laminas\ServiceManager\Exception\ServiceNotCreatedException` in `PhpDb\Pgsql\Container\PdoDriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Exception\ContainerException` in `PhpDb\Pgsql\Container\PdoDriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Psr\Container\ContainerExceptionInterface` in `PhpDb\Pgsql\Container\PdoDriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Psr\Container\NotFoundExceptionInterface` in `PhpDb\Pgsql\Container\PdoDriverInterfaceFactory::__invoke`.' +count = 1 + +[[issues]] +file = "src/Container/PdoStatementFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/PdoStatementFactory.php" +code = "mixed-argument" +message = 'Invalid argument type for argument #2 of `PhpDb\Adapter\Driver\Pdo\Statement::__construct`: expected `array`, but found `nonnull`.' +count = 1 + +[[issues]] +file = "src/Container/PdoStatementFactory.php" +code = "mixed-assignment" +message = "Assigning `nonnull` type to a variable may lead to unexpected behavior." +count = 1 + +[[issues]] +file = "src/Container/PdoStatementFactory.php" +code = "unused-parameter" +message = "Parameter `$container` is never used." +count = 1 + +[[issues]] +file = "src/Container/PdoStatementFactory.php" +code = "unused-parameter" +message = "Parameter `$requestedName` is never used." +count = 1 + +[[issues]] +file = "src/Container/PlatformInterfaceFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/PlatformInterfaceFactory.php" +code = "mixed-assignment" +message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 1 + +[[issues]] +file = "src/Container/PlatformInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$container` is never used." +count = 1 + +[[issues]] +file = "src/Container/PlatformInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$requestedName` is never used." +count = 1 + +[[issues]] +file = "src/Container/StatementInterfaceFactory.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Container/StatementInterfaceFactory.php" +code = "mixed-argument" +message = 'Invalid argument type for argument #1 of `PhpDb\Pgsql\Statement::__construct`: expected `array|bool`, but found `nonnull`.' +count = 1 + +[[issues]] +file = "src/Container/StatementInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$container` is never used." +count = 1 + +[[issues]] +file = "src/Container/StatementInterfaceFactory.php" +code = "unused-parameter" +message = "Parameter `$requestedName` is never used." +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "invalid-argument" +message = 'Invalid argument type for argument #1 of `PhpDb\Pgsql\Statement::initialize`: expected `PgSql\Connection`, but found `null|resource`.' +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "missing-property-type" +message = "Property `$options` is missing a type hint." +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "possibly-false-argument" +message = 'Argument #2 of method `PhpDb\Pgsql\Result::initialize` is possibly `false`, but parameter type `int|null|string` does not accept it.' +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "possibly-invalid-argument" +message = 'Possible argument type mismatch for argument #1 of `PhpDb\Pgsql\Result::initialize`: expected `PgSql\Result`, but possibly received `PgSql\Result|resource`.' +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "possibly-null-argument" +message = 'Argument #1 of method `PhpDb\Pgsql\Statement::initialize` is possibly `null`, but parameter type `PgSql\Connection` does not accept it.' +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "redundant-condition" +message = "This condition (type `true`) will always evaluate to true." +count = 2 + +[[issues]] +file = "src/Driver.php" +code = "redundant-docblock-type" +message = "Redundant docblock type for variable `$result`." +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Driver::createStatement`.' +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Exception\RuntimeException` in `PhpDb\Pgsql\Driver::__construct`.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\Metadata\Source` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "invalid-array-access" +message = 'Cannot access array index on object `PhpDb\ResultSet\RowPrototypeInterface` that does not implement `ArrayAccess`.' +count = 28 + +[[issues]] +file = "src/Metadata/Source.php" +code = "less-specific-argument" +message = 'Argument type mismatch for argument #1 of `array_change_key_case`: expected `array`, but provided type `ArrayObject|PhpDb\ResultSet\RowPrototypeInterface|array` is less specific.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "mixed-argument" +message = "Invalid argument type for argument #1 of `DateTime::__construct`: expected `string`, but found `nonnull`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "mixed-array-assignment" +message = "Unsafe array assignment on type `mixed`." +count = 6 + +[[issues]] +file = "src/Metadata/Source.php" +code = "mixed-assignment" +message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-invalid-argument" +message = "Possible argument type mismatch for argument #2 of `implode`: expected `array|null`, but possibly received `non-empty-list`." +count = 4 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-null-operand" +message = "Possibly null middle operand used in string concatenation (type `null|string`)." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-null-operand" +message = "Possibly null right operand used in string concatenation (type `null|string`)." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('character_maximum_length')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('character_octet_length')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('check_clause')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('check_option')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('column_default')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('column_name')` accessed on `array`." +count = 2 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('constraint_name')` accessed on `array`." +count = 2 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('constraint_type')` accessed on `array`." +count = 2 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('data_type')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('is_nullable')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('is_updatable')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('numeric_precision')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('numeric_scale')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('ordinal_position')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('referenced_column_name')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('schema_name')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('table_name')` accessed on `array`." +count = 2 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('table_type')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "possibly-undefined-string-array-index" +message = "Possibly undefined array key `string('view_definition')` accessed on `array`." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "reference-constraint-violation" +message = "Invalid assignment to by-reference parameter `$c`." +count = 7 + +[[issues]] +file = "src/Metadata/Source.php" +code = "too-many-arguments" +message = 'Too many arguments provided for method `PhpDb\Metadata\Source\AbstractSource::prepareDataHierarchy`.' +count = 4 + +[[issues]] +file = "src/Metadata/Source.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadColumnData`.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadConstraintData`.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadSchemaData`.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadTableNameData`.' +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadTriggerData`.' +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\Pdo\Connection` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "imprecise-type" +message = "Type `array` in parameter `$connectionParameters` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "invalid-type-cast" +message = "Casting `mixed` to `array`." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "less-specific-argument" +message = "Argument type mismatch for argument #1 of `strtolower`: expected `string`, but provided type `array-key` is less specific." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #1 of `array_diff_key`: expected `array<('K.array_diff_key() extends array-key), ('V.array_diff_key() extends mixed)>`, but found `mixed`." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #1 of `strtolower`: expected `string`, but found `mixed`." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-argument" +message = "Invalid argument type for argument #4 of `PDO::__construct`: expected `array|null`, but found `mixed`." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-array-assignment" +message = "Unsafe array assignment on type `mixed`." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-assignment" +message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 4 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-return-statement" +message = 'Could not infer a precise return type for function `PhpDb\Pgsql\Pdo\Connection::getCurrentSchema`. Saw type `mixed`.' +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "mixed-return-statement" +message = 'Could not infer a precise return type for function `PhpDb\Pgsql\Pdo\Connection::getLastGeneratedValue`. Saw type `mixed`.' +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "possible-method-access-on-null" +message = "Attempting to call a method on `null`." +count = 2 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "redundant-condition" +message = "This condition (type `true`) will always evaluate to true." +count = 2 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PDOException` in `PhpDb\Pgsql\Pdo\Connection::getCurrentSchema`.' +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\InvalidConnectionParametersException` in `PhpDb\Pgsql\Pdo\Connection::getCurrentSchema`.' +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `PhpDb\Adapter\Exception\RuntimeException` in `PhpDb\Pgsql\Pdo\Connection::getCurrentSchema`.' +count = 1 + +[[issues]] +file = "src/Pdo/Driver.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\Pdo\Driver` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Pdo/Driver.php" +code = "invalid-property-assignment-value" +message = 'Invalid type for property `$connection`: expected `(PhpDb\Adapter\Driver\PdoConnectionInterface&PhpDb\Adapter\Driver\AbstractConnection&PhpDb\Adapter\Driver\PdoDriverAwareInterface)|PDO`, but got `(PhpDb\Adapter\Driver\PdoConnectionInterface&PhpDb\Adapter\Driver\PdoDriverAwareInterface)|PDO`.' +count = 1 + +[[issues]] +file = "src/Pdo/Driver.php" +code = "mixed-argument" +message = 'Invalid argument type for argument #2 of `PhpDb\Adapter\Driver\Pdo\Result::initialize`: expected `false|int|null|string`, but found `mixed`.' +count = 1 + +[[issues]] +file = "src/Pdo/Driver.php" +code = "non-existent-method" +message = "Method `getlastgeneratedvalue` does not exist on type `PDO`." +count = 1 + +[[issues]] +file = "src/Pdo/Driver.php" +code = "possibly-invalid-argument" +message = 'Possible argument type mismatch for argument #1 of `PhpDb\Adapter\Driver\Pdo\Result::initialize`: expected `PDOStatement`, but possibly received `PDOStatement|resource`.' +count = 1 + +[[issues]] +file = "src/Result.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\Result` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Result.php" +code = "imprecise-type" +message = "Type `array` in return type of `current` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Result.php" +code = "missing-constructor" +message = 'Class `PhpDb\Pgsql\Result` has typed properties without default values but no constructor to initialize them.' +count = 1 + +[[issues]] +file = "src/Result.php" +code = "missing-override-attribute" +message = 'Missing `#[Override]` attribute on overriding method `PhpDb\Pgsql\Result::getResource`.' +count = 1 + +[[issues]] +file = "src/Result.php" +code = "mixed-return-statement" +message = 'Could not infer a precise return type for function `PhpDb\Pgsql\Result::getGeneratedValue`. Saw type `mixed`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Pgsql\Statement` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "docblock-type-mismatch" +message = 'Docblock return type `false|resource` is incompatible with native return type `PgSql\Result|false`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "imprecise-type" +message = "Type `array` in parameter `$options` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "imprecise-type" +message = "Type `array` in parameter `$parameters` is imprecise, equivalent to `array`." +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "invalid-argument" +message = 'Invalid argument type for argument #1 of `PhpDb\Adapter\Driver\DriverInterface::createResult`: expected `resource`, but found `PgSql\Result`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "invalid-property-assignment-value" +message = "Invalid type for property `$sql`: expected `string`, but got `null|string`." +count = 2 + +[[issues]] +file = "src/Statement.php" +code = "invalid-return-statement" +message = 'Invalid return type for function `PhpDb\Pgsql\Statement::getResource`: expected `false|resource`, but found `PgSql\Result|false`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "invalid-type-cast" +message = "Casting type `null` to `array` will produce an empty array." +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "mixed-property-type-coercion" +message = "A value with a less specific type `nonnull` is being assigned to property `$bufferResults` (bool)." +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "possibly-null-argument" +message = "Argument #3 of function `pg_prepare` is possibly `null`, but parameter type `string` does not accept it." +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "uninitialized-property" +message = 'Property `$driver` is not initialized in the constructor of class `PhpDb\Pgsql\Statement`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "uninitialized-property" +message = 'Property `$pgsql` is not initialized in the constructor of class `PhpDb\Pgsql\Statement`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "uninitialized-property" +message = 'Property `$resource` is not initialized in the constructor of class `PhpDb\Pgsql\Statement`.' +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "uninitialized-property" +message = 'Property `$sql` is not initialized in the constructor of class `PhpDb\Pgsql\Statement`.' +count = 1 + +[[issues]] +file = "vendor/php-db/phpdb/src/Adapter/Driver/AbstractConnection.php" +code = "uninitialized-property" +message = 'Property `$driverName` is not initialized in the constructor of class `PhpDb\Pgsql\Connection`.' +count = 1 + +[[issues]] +file = "vendor/php-db/phpdb/src/Adapter/Driver/AbstractConnection.php" +code = "uninitialized-property" +message = 'Property `$driverName` is not initialized in the constructor of class `PhpDb\Pgsql\Pdo\Connection`.' +count = 1 + +[[issues]] +file = "vendor/php-db/phpdb/src/Adapter/Driver/Pdo/AbstractPdo.php" +code = "uninitialized-property" +message = 'Property `$profiler` is not initialized in the constructor of class `PhpDb\Pgsql\Pdo\Driver`.' +count = 1 + +[[issues]] +file = "vendor/php-db/phpdb/src/Adapter/Driver/Pdo/AbstractPdoConnection.php" +code = "uninitialized-property" +message = 'Property `$dsn` is not initialized in the constructor of class `PhpDb\Pgsql\Pdo\Connection`.' +count = 1 diff --git a/lint-baseline.toml b/lint-baseline.toml new file mode 100644 index 0000000..8d62c33 --- /dev/null +++ b/lint-baseline.toml @@ -0,0 +1,439 @@ +variant = "loose" + +[[issues]] +file = "src/AdapterPlatform.php" +code = "literal-named-argument" +message = """Literal argument `'""'` should be passed as a named argument for clarity.""" +count = 1 + +[[issues]] +file = "src/ConfigProvider.php" +code = "no-literal-password" +message = "Literal passwords or sensitive data should not be stored in code." +count = 2 + +[[issues]] +file = "src/Connection.php" +code = "cyclomatic-complexity" +message = "Class has high complexity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "kan-defect" +message = "Class has a high kan defect score." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `' '` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `''` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `'BEGIN'` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `'COMMIT'` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `'ROLLBACK'` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = """Literal argument `'SELECT CURRENT_SCHEMA AS "currentschema"'` should be passed as a named argument for clarity.""" +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = '''Literal argument `'\\\''` should be passed as a named argument for clarity.''' +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `'currentschema'` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `'currval'` should be passed as a named argument for clarity." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "literal-named-argument" +message = "Literal argument `0` should be passed as a named argument for clarity." +count = 2 + +[[issues]] +file = "src/Connection.php" +code = "no-else-clause" +message = "Avoid `else` clauses." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "no-empty" +message = "Use of the `empty` construct." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "string-style" +message = "String concatenation can be replaced with interpolation." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "src/Connection.php" +code = "too-many-methods" +message = "Class has too many methods." +count = 1 + +[[issues]] +file = "src/Container/PdoConnectionInterfaceFactory.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "src/Container/PdoDriverInterfaceFactory.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "src/Container/PlatformInterfaceFactory.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "no-redundant-use" +message = "Unused import: `array_merge`." +count = 1 + +[[issues]] +file = "src/Driver.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "cyclomatic-complexity" +message = "Class has high complexity." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "halstead" +message = "Method has a high halstead volume and effort" +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "kan-defect" +message = "Class has a high kan defect score." +count = 1 + +[[issues]] +file = "src/Metadata/Source.php" +code = "no-else-clause" +message = "Avoid `else` clauses." +count = 4 + +[[issues]] +file = "src/Metadata/Source.php" +code = "no-isset" +message = "Use of the `isset` construct." +count = 5 + +[[issues]] +file = "src/Metadata/Source.php" +code = "string-style" +message = "String concatenation can be replaced with interpolation." +count = 4 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "cyclomatic-complexity" +message = "Class has high complexity." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "halstead" +message = "Method has a high halstead effort" +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "no-else-clause" +message = "Avoid `elseif` clauses." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "no-empty-catch-clause" +message = "Do not use empty `catch` blocks." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "no-fully-qualified-global-class-like" +message = "Fully-qualified class-like reference detected." +count = 1 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "no-isset" +message = "Use of the `isset` construct." +count = 7 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "no-multi-assignments" +message = "Avoid multiple assignments in a single statement." +count = 4 + +[[issues]] +file = "src/Pdo/Connection.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 2 + +[[issues]] +file = "src/Statement.php" +code = "halstead" +message = "Method has a high halstead difficulty" +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "no-else-clause" +message = "Avoid `else` clauses." +count = 1 + +[[issues]] +file = "src/Statement.php" +code = "no-isset" +message = "Use of the `isset` construct." +count = 1 + +[[issues]] +file = "test/asset/SetupTrait.php" +code = "no-dead-store" +message = "Variable `$serviceManagerConfig` is overwritten before its value is read." +count = 1 + +[[issues]] +file = "test/asset/SetupTrait.php" +code = "no-literal-namespace-string" +message = "Use `::class` notation instead of a hardcoded namespace string." +count = 2 + +[[issues]] +file = "test/asset/SetupTrait.php" +code = "prefer-arrow-function" +message = "This closure can be simplified to a more concise arrow function." +count = 2 + +[[issues]] +file = "test/integration/AdapterPlatformTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 2 + +[[issues]] +file = "test/integration/AdapterPlatformTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testQuoteValueWithPdoPgsql`." +count = 1 + +[[issues]] +file = "test/integration/AdapterPlatformTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testQuoteValueWithPgsql`." +count = 1 + +[[issues]] +file = "test/integration/AdapterPlatformTest.php" +code = "strict-assertions" +message = "Use strict assertions in PHPUnit tests." +count = 2 + +[[issues]] +file = "test/integration/AdapterPlatformTest.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "test/integration/AdapterTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 11 + +[[issues]] +file = "test/integration/AdapterTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testConnection`." +count = 1 + +[[issues]] +file = "test/integration/AdapterTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testDriverDisconnectAfterQuoteWithPlatform`." +count = 1 + +[[issues]] +file = "test/integration/AdapterTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetCurrentSchema`." +count = 1 + +[[issues]] +file = "test/integration/AdapterTest.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "test/integration/Extension/IntegrationTestStartedListener.php" +code = "no-empty" +message = "Use of the `empty` construct." +count = 1 + +[[issues]] +file = "test/integration/Extension/IntegrationTestStoppedListener.php" +code = "no-empty" +message = "Use of the `empty` construct." +count = 1 + +[[issues]] +file = "test/integration/FixtureLoader/PgsqlFixtureLoader.php" +code = "literal-named-argument" +message = "Literal argument `true` should be passed as a named argument for clarity." +count = 2 + +[[issues]] +file = "test/integration/FixtureLoader/PgsqlFixtureLoader.php" +code = "no-boolean-flag-parameter" +message = "Avoid boolean flag parameters." +count = 1 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 11 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "no-dead-store" +message = "Variable `$isConnected` is overwritten before its value is read." +count = 1 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "no-redundant-variable" +message = "Variable `$isConnected` is assigned but never used." +count = 1 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testConnection`." +count = 1 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testDriverDisconnectAfterQuoteWithPlatform`." +count = 1 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetCurrentSchema`." +count = 1 + +[[issues]] +file = "test/integration/Pdo/AdapterTest.php" +code = "tagged-todo" +message = "TODO should be tagged with (@username) or (#issue)." +count = 1 + +[[issues]] +file = "test/integration/Pdo/TableGatewayTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 2 + +[[issues]] +file = "test/integration/Pdo/TableGatewayTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testLastInsertValue`." +count = 1 + +[[issues]] +file = "test/unit/Adapter/ConfigProviderTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 2 + +[[issues]] +file = "test/unit/Adapter/ConfigProviderTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testInvocationProvidesDependencyConfiguration`." +count = 1 + +[[issues]] +file = "test/unit/Adapter/ConfigProviderTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testProvidesExpectedConfiguration`." +count = 1 + +[[issues]] +file = "test/unit/Adapter/SetupTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 2 + +[[issues]] +file = "test/unit/Adapter/SetupTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testAdapterAbstractFactoryBuildsNativeDriver`." +count = 1 + +[[issues]] +file = "test/unit/Adapter/SetupTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testAdapterInterfaceFactoryBuildsNativeDriver`." +count = 1 diff --git a/mago.toml b/mago.toml index 4e2bc2b..f7bb3dd 100644 --- a/mago.toml +++ b/mago.toml @@ -5,3 +5,9 @@ php-version = "8.3.0" [source] paths = ["src", "test"] includes = ["vendor"] + +[linter] +baseline = "lint-baseline.toml" + +[analyzer] +baseline = "analyzer-baseline.toml" From c2bc213bae51bd5cf74f358fbb8360bec5fcf186 Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 24 Aug 2026 15:31:55 +1000 Subject: [PATCH 3/8] Point the adapter construction coverage at Adapter, not AdapterInterface AdapterInterface declares no __construct, so CoversMethod named a target that cannot exist and PHPUnit raised "is not a valid target for code coverage" once per test. With failOnWarning="true" that failed the coverage leg of the matrix, the only leg where coverage metadata is validated, which is why this surfaced with the qa-tools workflow and not before. --- test/integration/AdapterTest.php | 2 +- test/integration/Pdo/AdapterTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/AdapterTest.php b/test/integration/AdapterTest.php index 3a25287..189c7eb 100644 --- a/test/integration/AdapterTest.php +++ b/test/integration/AdapterTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\TestCase; #[CoversMethod(Adapter::class, 'getCurrentSchema')] -#[CoversMethod(AdapterInterface::class, '__construct')] +#[CoversMethod(Adapter::class, '__construct')] #[CoversMethod(SchemaAwareInterface::class, 'getCurrentSchema')] #[CoversMethod(ConnectionInterface::class, 'connect')] #[CoversMethod(ConnectionInterface::class, 'disconnect')] diff --git a/test/integration/Pdo/AdapterTest.php b/test/integration/Pdo/AdapterTest.php index a0cf2ed..938381b 100644 --- a/test/integration/Pdo/AdapterTest.php +++ b/test/integration/Pdo/AdapterTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\TestCase; #[CoversMethod(Adapter::class, 'getCurrentSchema')] -#[CoversMethod(AdapterInterface::class, '__construct')] +#[CoversMethod(Adapter::class, '__construct')] #[CoversMethod(SchemaAwareInterface::class, 'getCurrentSchema')] #[CoversMethod(ConnectionInterface::class, 'connect')] #[CoversMethod(ConnectionInterface::class, 'disconnect')] From 42eabc55eda16cbad3fe0f2b971fc53e9596a2bd Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 31 Aug 2026 12:20:38 +1000 Subject: [PATCH 4/8] Bring the merged Result work in line with the 8.3 toolchain The merge kept this branch's lock, which pinned php-db/phpdb at an April dev commit predating getQueryResult() on ResultInterface, so the merged Result::getQueryResult() fataled on its #[Override]. Update phpdb to the tip 0.6.x-dev. Run mago format over the four files the merge brought in and regenerate both baselines, which also clears 67 stale analyzer entries. --- analyzer-baseline.toml | 172 +++++--------------------------- composer.lock | 40 ++++---- lint-baseline.toml | 60 +++++++++++ src/Result.php | 4 +- test/asset/ResultStub.php | 15 +-- test/integration/ResultTest.php | 22 ++-- test/unit/ResultTest.php | 16 +-- 7 files changed, 134 insertions(+), 195 deletions(-) diff --git a/analyzer-baseline.toml b/analyzer-baseline.toml index d6705b5..b67b334 100644 --- a/analyzer-baseline.toml +++ b/analyzer-baseline.toml @@ -542,32 +542,32 @@ count = 1 [[issues]] file = "src/Metadata/Source.php" -code = "invalid-array-access" -message = 'Cannot access array index on object `PhpDb\ResultSet\RowPrototypeInterface` that does not implement `ArrayAccess`.' -count = 28 - -[[issues]] -file = "src/Metadata/Source.php" -code = "less-specific-argument" -message = 'Argument type mismatch for argument #1 of `array_change_key_case`: expected `array`, but provided type `ArrayObject|PhpDb\ResultSet\RowPrototypeInterface|array` is less specific.' +code = "mixed-argument" +message = "Invalid argument type for argument #1 of `DateTime::__construct`: expected `string`, but found `nonnull`." count = 1 [[issues]] file = "src/Metadata/Source.php" code = "mixed-argument" -message = "Invalid argument type for argument #1 of `DateTime::__construct`: expected `string`, but found `nonnull`." +message = "Invalid argument type for argument #1 of `array_change_key_case`: expected `array`, but found `mixed`." count = 1 [[issues]] file = "src/Metadata/Source.php" -code = "mixed-array-assignment" -message = "Unsafe array assignment on type `mixed`." -count = 6 +code = "mixed-array-access" +message = "Unsafe array access on type `mixed`." +count = 23 [[issues]] file = "src/Metadata/Source.php" code = "mixed-assignment" message = "Assigning `mixed` type to a variable may lead to unexpected behavior." +count = 6 + +[[issues]] +file = "src/Metadata/Source.php" +code = "mixed-property-type-coercion" +message = "A value with a less specific type `array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas': array{}|non-empty-list, 'table_names'?: array>, 'triggers'?: array>}` is being assigned to property `$data` (array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>})." count = 1 [[issues]] @@ -590,116 +590,26 @@ count = 1 [[issues]] file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('character_maximum_length')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('character_octet_length')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('check_clause')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('check_option')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('column_default')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('column_name')` accessed on `array`." -count = 2 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('constraint_name')` accessed on `array`." -count = 2 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('constraint_type')` accessed on `array`." -count = 2 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('data_type')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('is_nullable')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('is_updatable')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('numeric_precision')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('numeric_scale')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('ordinal_position')` accessed on `array`." -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('referenced_column_name')` accessed on `array`." +code = "property-type-coercion" +message = "A value of a less specific type `array{'columns': non-empty-array, 'is_nullable': bool|null, 'numeric_precision': mixed, 'numeric_scale': mixed, 'numeric_unsigned': bool|null, 'ordinal_position': mixed}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>}` is being assigned to property `$data` (array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>})." count = 1 [[issues]] file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('schema_name')` accessed on `array`." +code = "property-type-coercion" +message = "A value of a less specific type `array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints': non-empty-array, 'constraint_name'?: mixed, 'constraint_type'?: mixed, 'delete_rule'?: mixed, 'match_option'?: mixed, 'referenced_columns'?: list, 'referenced_table_name'?: mixed, 'referenced_table_schema'?: mixed, 'table_name'?: mixed, 'update_rule'?: mixed}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>}` is being assigned to property `$data` (array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>})." count = 1 [[issues]] file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('table_name')` accessed on `array`." -count = 2 - -[[issues]] -file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('table_type')` accessed on `array`." +code = "property-type-coercion" +message = "A value of a less specific type `array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names': non-empty-array>, 'triggers'?: array>}` is being assigned to property `$data` (array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>})." count = 1 [[issues]] file = "src/Metadata/Source.php" -code = "possibly-undefined-string-array-index" -message = "Possibly undefined array key `string('view_definition')` accessed on `array`." +code = "property-type-coercion" +message = "A value of a less specific type `array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers': non-empty-array}>>}` is being assigned to property `$data` (array{'columns'?: array, 'is_nullable': bool|null, 'numeric_precision': int|null|string, 'numeric_scale': int|null|string, 'numeric_unsigned': bool|null, 'ordinal_position': int|null|string}>>>, 'constraint_keys'?: array>, 'constraint_references'?: array>, 'constraints'?: array, 'constraint_type'?: string, 'delete_rule'?: string, 'match_option'?: string, 'referenced_columns'?: list, 'referenced_table_name'?: string, 'referenced_table_schema'?: string, 'update_rule'?: string}>>>, 'schemas'?: list, 'table_names'?: array>, 'triggers'?: array>})." count = 1 [[issues]] @@ -708,42 +618,6 @@ code = "reference-constraint-violation" message = "Invalid assignment to by-reference parameter `$c`." count = 7 -[[issues]] -file = "src/Metadata/Source.php" -code = "too-many-arguments" -message = 'Too many arguments provided for method `PhpDb\Metadata\Source\AbstractSource::prepareDataHierarchy`.' -count = 4 - -[[issues]] -file = "src/Metadata/Source.php" -code = "unhandled-thrown-type" -message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadColumnData`.' -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "unhandled-thrown-type" -message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadConstraintData`.' -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "unhandled-thrown-type" -message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadSchemaData`.' -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "unhandled-thrown-type" -message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadTableNameData`.' -count = 1 - -[[issues]] -file = "src/Metadata/Source.php" -code = "unhandled-thrown-type" -message = 'Potentially unhandled exception `PhpDb\ResultSet\Exception\RuntimeException` in `PhpDb\Pgsql\Metadata\Source::loadTriggerData`.' -count = 1 - [[issues]] file = "src/Pdo/Connection.php" code = "class-must-be-final" @@ -900,6 +774,12 @@ code = "mixed-return-statement" message = 'Could not infer a precise return type for function `PhpDb\Pgsql\Result::getGeneratedValue`. Saw type `mixed`.' count = 1 +[[issues]] +file = "src/Result.php" +code = "unhandled-thrown-type" +message = 'Potentially unhandled exception `Exception` in `PhpDb\Pgsql\Result::getQueryResult`.' +count = 1 + [[issues]] file = "src/Statement.php" code = "class-must-be-final" diff --git a/composer.lock b/composer.lock index 07a0166..8a2ff2f 100644 --- a/composer.lock +++ b/composer.lock @@ -57,16 +57,16 @@ }, { "name": "laminas/laminas-servicemanager", - "version": "4.5.0", + "version": "4.5.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "a6996829c8ce55025cca1b57b1e8a8b165e3926c" + "reference": "11192d588876ad04ba2988984c77b4ecb5c771c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/a6996829c8ce55025cca1b57b1e8a8b165e3926c", - "reference": "a6996829c8ce55025cca1b57b1e8a8b165e3926c", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/11192d588876ad04ba2988984c77b4ecb5c771c2", + "reference": "11192d588876ad04ba2988984c77b4ecb5c771c2", "shasum": "" }, "require": { @@ -130,7 +130,7 @@ "chat": "https://laminas.dev/chat", "forum": "https://discourse.laminas.dev", "issues": "https://github.com/laminas/laminas-servicemanager/issues", - "source": "https://github.com/laminas/laminas-servicemanager/tree/4.5.0" + "source": "https://github.com/laminas/laminas-servicemanager/tree/4.5.1" }, "funding": [ { @@ -138,7 +138,7 @@ "type": "community_bridge" } ], - "time": "2025-10-14T09:41:04+00:00" + "time": "2026-05-12T09:53:32+00:00" }, { "name": "laminas/laminas-stdlib", @@ -201,20 +201,19 @@ }, { "name": "nikic/php-parser", - "version": "v5.7.0", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", "shasum": "" }, "require": { - "ext-ctype": "*", "ext-json": "*", "ext-tokenizer": "*", "php": ">=7.4" @@ -253,9 +252,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0" }, - "time": "2025-12-06T11:56:16+00:00" + "time": "2026-07-04T14:30:18+00:00" }, { "name": "php-db/phpdb", @@ -263,30 +262,29 @@ "source": { "type": "git", "url": "https://github.com/php-db/phpdb.git", - "reference": "81844a5699bf397bf044bbe36ea90be361b4a021" + "reference": "b57f549b411d0b4fe46de8a469983816395be850" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-db/phpdb/zipball/81844a5699bf397bf044bbe36ea90be361b4a021", - "reference": "81844a5699bf397bf044bbe36ea90be361b4a021", + "url": "https://api.github.com/repos/php-db/phpdb/zipball/b57f549b411d0b4fe46de8a469983816395be850", + "reference": "b57f549b411d0b4fe46de8a469983816395be850", "shasum": "" }, "require": { "laminas/laminas-servicemanager": "^3.0.0 || ^4.0.0", "laminas/laminas-stdlib": "^3.20.0", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + "php": "~8.3.0 || ~8.4.0 || ~8.5.0" }, "conflict": { "laminas/laminas-db": "*", "zendframework/zend-db": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^3.0.1", + "infection/infection": "^0.34.1", "laminas/laminas-eventmanager": "^3.14.0", "laminas/laminas-hydrator": "^4.6.0", + "php-db/phpdb-qa-tools": "0.1.x-dev", "phpbench/phpbench": "^1.4", - "phpstan/phpstan": "^2.1", - "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^11.5.42", "rector/rector": "^2.0" }, @@ -324,7 +322,7 @@ "issues": "https://github.com/php-db/phpdb/issues", "source": "https://github.com/php-db/phpdb" }, - "time": "2026-04-13T01:24:01+00:00" + "time": "2026-08-24T01:49:39+00:00" }, { "name": "psr/container", diff --git a/lint-baseline.toml b/lint-baseline.toml index 8d62c33..87d11ff 100644 --- a/lint-baseline.toml +++ b/lint-baseline.toml @@ -228,6 +228,12 @@ code = "tagged-todo" message = "TODO should be tagged with (@username) or (#issue)." count = 2 +[[issues]] +file = "src/Result.php" +code = "too-many-methods" +message = "Class has too many methods." +count = 1 + [[issues]] file = "src/Statement.php" code = "halstead" @@ -402,6 +408,36 @@ code = "prefer-test-attribute" message = "Use `#[Test]` attribute instead of `test` prefix on method `testLastInsertValue`." count = 1 +[[issues]] +file = "test/integration/ResultTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 3 + +[[issues]] +file = "test/integration/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testAStatementReturningNoFieldsIsNotAQueryResult`." +count = 1 + +[[issues]] +file = "test/integration/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultIteratesTheSelectedRows`." +count = 1 + +[[issues]] +file = "test/integration/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultRejectsAStatementThatReturnsNoFields`." +count = 1 + +[[issues]] +file = "test/integration/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultSeedsTheResultSetFromASelect`." +count = 1 + [[issues]] file = "test/unit/Adapter/ConfigProviderTest.php" code = "assertion-style" @@ -437,3 +473,27 @@ file = "test/unit/Adapter/SetupTest.php" code = "prefer-test-attribute" message = "Use `#[Test]` attribute instead of `test` prefix on method `testAdapterInterfaceFactoryBuildsNativeDriver`." count = 1 + +[[issues]] +file = "test/unit/ResultTest.php" +code = "assertion-style" +message = "Inconsistent assertions style." +count = 2 + +[[issues]] +file = "test/unit/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultClonesTheGivenPrototype`." +count = 1 + +[[issues]] +file = "test/unit/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultRejectsAResultThatIsNotAQueryResult`." +count = 1 + +[[issues]] +file = "test/unit/ResultTest.php" +code = "prefer-test-attribute" +message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultSeedsTheResultSetFromTheResult`." +count = 1 diff --git a/src/Result.php b/src/Result.php index eb1db69..dcb7a35 100644 --- a/src/Result.php +++ b/src/Result.php @@ -73,12 +73,12 @@ public function getQueryResult(?ResultSetInterface $resultPrototype = null): Res if (! $this->isQueryResult()) { throw new Exception\RuntimeException( 'Cannot produce a query result set from a result that is not a query result;' - . ' check isQueryResult() first' + . ' check isQueryResult() first', ); } $resultPrototype ??= new ResultSet(); - $resultSet = clone $resultPrototype; + $resultSet = clone $resultPrototype; $resultSet->initialize($this); return $resultSet; diff --git a/test/asset/ResultStub.php b/test/asset/ResultStub.php index 814e290..34a0a6b 100644 --- a/test/asset/ResultStub.php +++ b/test/asset/ResultStub.php @@ -14,19 +14,20 @@ */ final class ResultStub extends Result { - public function __construct(private bool $isQueryResult, private int $fieldCount = 0) - { - } + public function __construct( + private bool $isQueryResult, + private int $fieldCount = 0, + ) {} #[Override] - public function isQueryResult(): bool + public function getFieldCount(): int { - return $this->isQueryResult; + return $this->fieldCount; } #[Override] - public function getFieldCount(): int + public function isQueryResult(): bool { - return $this->fieldCount; + return $this->isQueryResult; } } diff --git a/test/integration/ResultTest.php b/test/integration/ResultTest.php index e25f435..d05c2de 100644 --- a/test/integration/ResultTest.php +++ b/test/integration/ResultTest.php @@ -16,11 +16,11 @@ class ResultTest extends TestCase { use SetupTrait; - public function testGetQueryResultSeedsTheResultSetFromASelect(): void + public function testAStatementReturningNoFieldsIsNotAQueryResult(): void { - $result = $this->getAdapter()->executeQuery('SELECT id, name, value FROM test'); + $result = $this->getAdapter()->executeQuery('SET search_path TO public'); - self::assertSame($result->getFieldCount(), $result->getQueryResult()->getFieldCount()); + self::assertFalse($result->isQueryResult()); } public function testGetQueryResultIteratesTheSelectedRows(): void @@ -35,13 +35,6 @@ public function testGetQueryResultIteratesTheSelectedRows(): void self::assertSame(['foo', 'bar'], $names); } - public function testAStatementReturningNoFieldsIsNotAQueryResult(): void - { - $result = $this->getAdapter()->executeQuery('SET search_path TO public'); - - self::assertFalse($result->isQueryResult()); - } - public function testGetQueryResultRejectsAStatementThatReturnsNoFields(): void { $result = $this->getAdapter()->executeQuery('SET search_path TO public'); @@ -49,9 +42,16 @@ public function testGetQueryResultRejectsAStatementThatReturnsNoFields(): void $this->expectException(Exception\RuntimeException::class); $this->expectExceptionMessage( 'Cannot produce a query result set from a result that is not a query result;' - . ' check isQueryResult() first' + . ' check isQueryResult() first', ); $result->getQueryResult(); } + + public function testGetQueryResultSeedsTheResultSetFromASelect(): void + { + $result = $this->getAdapter()->executeQuery('SELECT id, name, value FROM test'); + + self::assertSame($result->getFieldCount(), $result->getQueryResult()->getFieldCount()); + } } diff --git a/test/unit/ResultTest.php b/test/unit/ResultTest.php index 0300f96..e6164b2 100644 --- a/test/unit/ResultTest.php +++ b/test/unit/ResultTest.php @@ -14,13 +14,6 @@ #[CoversMethod(Result::class, 'getQueryResult')] class ResultTest extends TestCase { - public function testGetQueryResultSeedsTheResultSetFromTheResult(): void - { - $resultSet = (new ResultStub(true, 3))->getQueryResult(); - - self::assertSame(3, $resultSet->getFieldCount()); - } - public function testGetQueryResultClonesTheGivenPrototype(): void { $prototype = new ResultSet(); @@ -35,9 +28,16 @@ public function testGetQueryResultRejectsAResultThatIsNotAQueryResult(): void $this->expectException(Exception\RuntimeException::class); $this->expectExceptionMessage( 'Cannot produce a query result set from a result that is not a query result;' - . ' check isQueryResult() first' + . ' check isQueryResult() first', ); (new ResultStub(false))->getQueryResult(); } + + public function testGetQueryResultSeedsTheResultSetFromTheResult(): void + { + $resultSet = (new ResultStub(true, 3))->getQueryResult(); + + self::assertSame(3, $resultSet->getFieldCount()); + } } From 6a17639c08f37064a786cb9535e5bc19f6a432c3 Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 31 Aug 2026 12:28:04 +1000 Subject: [PATCH 5/8] Reformat three files under mago 1.47 Mago 1.47 de-indents the continuation operators in a multi-line if condition by one level. CI installs mago unpinned via setup-php's `tools: mago`, so it was checking against 1.47 while this branch had been formatted with 1.45. --- src/Container/PlatformInterfaceFactory.php | 2 +- src/Pdo/Connection.php | 4 ++-- test/integration/Extension/IntegrationTestStoppedListener.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Container/PlatformInterfaceFactory.php b/src/Container/PlatformInterfaceFactory.php index c1ab391..a4df5e2 100644 --- a/src/Container/PlatformInterfaceFactory.php +++ b/src/Container/PlatformInterfaceFactory.php @@ -22,7 +22,7 @@ public function __invoke( $driver = $options['driver'] ?? null; if ( ! $driver instanceof Pgsql\Driver - && ! $driver instanceof Pgsql\Pdo\Driver + && ! $driver instanceof Pgsql\Pdo\Driver ) { // todo: Once latest PR is merged for 0.5.0 update to use PhpDB\Exception\ContainerException throw ContainerException::forService( diff --git a/src/Pdo/Connection.php b/src/Pdo/Connection.php index cbf4afe..aa16640 100644 --- a/src/Pdo/Connection.php +++ b/src/Pdo/Connection.php @@ -99,8 +99,8 @@ public function connect(): ConnectionInterface&PdoConnectionInterface if ( ! str_contains($dsn, 'host=') - && ! str_contains($dsn, 'dbname=') - && ! str_contains($dsn, 'user=') + && ! str_contains($dsn, 'dbname=') + && ! str_contains($dsn, 'user=') ) { throw new Exception\InvalidConnectionParametersException( 'A dsn was not provided or could not be constructed from your parameters', diff --git a/test/integration/Extension/IntegrationTestStoppedListener.php b/test/integration/Extension/IntegrationTestStoppedListener.php index f3b1fbc..ccd56d4 100644 --- a/test/integration/Extension/IntegrationTestStoppedListener.php +++ b/test/integration/Extension/IntegrationTestStoppedListener.php @@ -19,7 +19,7 @@ public function notify(Finished $event): void { if ( $event->testSuite()->name() !== 'integration test' - || empty($this->fixtureLoaders) + || empty($this->fixtureLoaders) ) { return; } From 7f5f6c872632af8f6a2eb35daf0b2f7f11f2e09a Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 31 Aug 2026 12:30:23 +1000 Subject: [PATCH 6/8] Avoid immediately-invoked new in the Result unit test Under MAGO_PHP_VERSION 8.4/8.5 the formatter rewrites (new ResultStub(...))->getQueryResult() to the parenthesis-less 8.4 form, which is a parse error on 8.3. The CI matrix runs a format check per PHP version, so no single formatting of that construct satisfies every leg. Bind the stub to a variable first; there are then no parentheses to strip. The underlying issue is in phpdb-qa-tools: the format check should run at the minimum supported version, not once per matrix leg. Lint and analyze are legitimately version-dependent, formatting is not. --- test/unit/ResultTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/unit/ResultTest.php b/test/unit/ResultTest.php index e6164b2..70b0ad9 100644 --- a/test/unit/ResultTest.php +++ b/test/unit/ResultTest.php @@ -18,7 +18,8 @@ public function testGetQueryResultClonesTheGivenPrototype(): void { $prototype = new ResultSet(); - $resultSet = (new ResultStub(true, 1))->getQueryResult($prototype); + $result = new ResultStub(true, 1); + $resultSet = $result->getQueryResult($prototype); self::assertNotSame($prototype, $resultSet); } @@ -31,12 +32,14 @@ public function testGetQueryResultRejectsAResultThatIsNotAQueryResult(): void . ' check isQueryResult() first', ); - (new ResultStub(false))->getQueryResult(); + $result = new ResultStub(false); + $result->getQueryResult(); } public function testGetQueryResultSeedsTheResultSetFromTheResult(): void { - $resultSet = (new ResultStub(true, 3))->getQueryResult(); + $result = new ResultStub(true, 3); + $resultSet = $result->getQueryResult(); self::assertSame(3, $resultSet->getFieldCount()); } From c2a1ad376ed8252cfc8d7587179210fc0fd3bd5a Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 31 Aug 2026 12:38:21 +1000 Subject: [PATCH 7/8] Fix the baselined lint findings instead of suppressing them Ran the mago fixer with --potentially-unsafe over the whole suite, which clears assertion-style, prefer-test-attribute, strict-assertions, prefer-arrow-function and no-redundant-use outright: 136 lint issues down to 76, and the baseline from 83 entries to 52. The fixer renamed testProvidesExpectedConfiguration without updating the #[Depends] attribute that named it, so repair that by hand. Declare the exception ResultSet::initialize() propagates out of getQueryResult(); the docblock only named RuntimeException. That was the one genuinely new analyzer finding the merge introduced. Regenerating the analyzer baseline wanted to suppress the missing-property-type warning on Result::$resource, which was previously visible. Drop that entry back out rather than hide it. --- analyzer-baseline.toml | 6 - lint-baseline.toml | 186 ---------------------- src/Driver.php | 1 - src/Result.php | 1 + test/asset/SetupTrait.php | 8 +- test/integration/AdapterPlatformTest.php | 11 +- test/integration/AdapterTest.php | 32 ++-- test/integration/Pdo/AdapterTest.php | 32 ++-- test/integration/Pdo/TableGatewayTest.php | 8 +- test/integration/ResultTest.php | 19 ++- test/unit/Adapter/ConfigProviderTest.php | 13 +- test/unit/Adapter/SetupTest.php | 11 +- test/unit/ResultTest.php | 14 +- 13 files changed, 87 insertions(+), 255 deletions(-) diff --git a/analyzer-baseline.toml b/analyzer-baseline.toml index b67b334..f535850 100644 --- a/analyzer-baseline.toml +++ b/analyzer-baseline.toml @@ -774,12 +774,6 @@ code = "mixed-return-statement" message = 'Could not infer a precise return type for function `PhpDb\Pgsql\Result::getGeneratedValue`. Saw type `mixed`.' count = 1 -[[issues]] -file = "src/Result.php" -code = "unhandled-thrown-type" -message = 'Potentially unhandled exception `Exception` in `PhpDb\Pgsql\Result::getQueryResult`.' -count = 1 - [[issues]] file = "src/Statement.php" code = "class-must-be-final" diff --git a/lint-baseline.toml b/lint-baseline.toml index 87d11ff..8b2320a 100644 --- a/lint-baseline.toml +++ b/lint-baseline.toml @@ -132,12 +132,6 @@ code = "tagged-todo" message = "TODO should be tagged with (@username) or (#issue)." count = 1 -[[issues]] -file = "src/Driver.php" -code = "no-redundant-use" -message = "Unused import: `array_merge`." -count = 1 - [[issues]] file = "src/Driver.php" code = "tagged-todo" @@ -264,66 +258,12 @@ code = "no-literal-namespace-string" message = "Use `::class` notation instead of a hardcoded namespace string." count = 2 -[[issues]] -file = "test/asset/SetupTrait.php" -code = "prefer-arrow-function" -message = "This closure can be simplified to a more concise arrow function." -count = 2 - -[[issues]] -file = "test/integration/AdapterPlatformTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 2 - -[[issues]] -file = "test/integration/AdapterPlatformTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testQuoteValueWithPdoPgsql`." -count = 1 - -[[issues]] -file = "test/integration/AdapterPlatformTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testQuoteValueWithPgsql`." -count = 1 - -[[issues]] -file = "test/integration/AdapterPlatformTest.php" -code = "strict-assertions" -message = "Use strict assertions in PHPUnit tests." -count = 2 - [[issues]] file = "test/integration/AdapterPlatformTest.php" code = "tagged-todo" message = "TODO should be tagged with (@username) or (#issue)." count = 1 -[[issues]] -file = "test/integration/AdapterTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 11 - -[[issues]] -file = "test/integration/AdapterTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testConnection`." -count = 1 - -[[issues]] -file = "test/integration/AdapterTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testDriverDisconnectAfterQuoteWithPlatform`." -count = 1 - -[[issues]] -file = "test/integration/AdapterTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetCurrentSchema`." -count = 1 - [[issues]] file = "test/integration/AdapterTest.php" code = "tagged-todo" @@ -354,12 +294,6 @@ code = "no-boolean-flag-parameter" message = "Avoid boolean flag parameters." count = 1 -[[issues]] -file = "test/integration/Pdo/AdapterTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 11 - [[issues]] file = "test/integration/Pdo/AdapterTest.php" code = "no-dead-store" @@ -372,128 +306,8 @@ code = "no-redundant-variable" message = "Variable `$isConnected` is assigned but never used." count = 1 -[[issues]] -file = "test/integration/Pdo/AdapterTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testConnection`." -count = 1 - -[[issues]] -file = "test/integration/Pdo/AdapterTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testDriverDisconnectAfterQuoteWithPlatform`." -count = 1 - -[[issues]] -file = "test/integration/Pdo/AdapterTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetCurrentSchema`." -count = 1 - [[issues]] file = "test/integration/Pdo/AdapterTest.php" code = "tagged-todo" message = "TODO should be tagged with (@username) or (#issue)." count = 1 - -[[issues]] -file = "test/integration/Pdo/TableGatewayTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 2 - -[[issues]] -file = "test/integration/Pdo/TableGatewayTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testLastInsertValue`." -count = 1 - -[[issues]] -file = "test/integration/ResultTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 3 - -[[issues]] -file = "test/integration/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testAStatementReturningNoFieldsIsNotAQueryResult`." -count = 1 - -[[issues]] -file = "test/integration/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultIteratesTheSelectedRows`." -count = 1 - -[[issues]] -file = "test/integration/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultRejectsAStatementThatReturnsNoFields`." -count = 1 - -[[issues]] -file = "test/integration/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultSeedsTheResultSetFromASelect`." -count = 1 - -[[issues]] -file = "test/unit/Adapter/ConfigProviderTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 2 - -[[issues]] -file = "test/unit/Adapter/ConfigProviderTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testInvocationProvidesDependencyConfiguration`." -count = 1 - -[[issues]] -file = "test/unit/Adapter/ConfigProviderTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testProvidesExpectedConfiguration`." -count = 1 - -[[issues]] -file = "test/unit/Adapter/SetupTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 2 - -[[issues]] -file = "test/unit/Adapter/SetupTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testAdapterAbstractFactoryBuildsNativeDriver`." -count = 1 - -[[issues]] -file = "test/unit/Adapter/SetupTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testAdapterInterfaceFactoryBuildsNativeDriver`." -count = 1 - -[[issues]] -file = "test/unit/ResultTest.php" -code = "assertion-style" -message = "Inconsistent assertions style." -count = 2 - -[[issues]] -file = "test/unit/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultClonesTheGivenPrototype`." -count = 1 - -[[issues]] -file = "test/unit/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultRejectsAResultThatIsNotAQueryResult`." -count = 1 - -[[issues]] -file = "test/unit/ResultTest.php" -code = "prefer-test-attribute" -message = "Use `#[Test]` attribute instead of `test` prefix on method `testGetQueryResultSeedsTheResultSetFromTheResult`." -count = 1 diff --git a/src/Driver.php b/src/Driver.php index fb2ebb9..ae3d676 100644 --- a/src/Driver.php +++ b/src/Driver.php @@ -16,7 +16,6 @@ use PhpDb\Adapter\Profiler\ProfilerInterface; use function array_intersect_key; -use function array_merge; use function extension_loaded; use function is_string; diff --git a/src/Result.php b/src/Result.php index dcb7a35..7475c39 100644 --- a/src/Result.php +++ b/src/Result.php @@ -66,6 +66,7 @@ public function getGeneratedValue(): int|string|false|null /** * @throws Exception\RuntimeException When this result is not a query result. + * @throws \Exception When the result set rejects this result as its data source. */ #[Override] public function getQueryResult(?ResultSetInterface $resultPrototype = null): ResultSetInterface diff --git a/test/asset/SetupTrait.php b/test/asset/SetupTrait.php index 170d769..3505306 100644 --- a/test/asset/SetupTrait.php +++ b/test/asset/SetupTrait.php @@ -102,12 +102,8 @@ public function getMockedAdapter(string $adapter = self::NATIVE_ADAPTER): Adapte PlatformInterface::class => Pgsql\AdapterPlatform::class, ], 'factories' => [ - Pgsql\Driver::class => static function (ContainerInterface $container) use ($driverMock) { - return $driverMock; - }, - Pgsql\Pdo\Driver::class => static function (ContainerInterface $container) use ($pdoDriverMock) { - return $pdoDriverMock; - }, + Pgsql\Driver::class => static fn(ContainerInterface $container) => $driverMock, + Pgsql\Pdo\Driver::class => static fn(ContainerInterface $container) => $pdoDriverMock, ], ], ]; diff --git a/test/integration/AdapterPlatformTest.php b/test/integration/AdapterPlatformTest.php index 6352012..c54e6e2 100644 --- a/test/integration/AdapterPlatformTest.php +++ b/test/integration/AdapterPlatformTest.php @@ -9,6 +9,7 @@ use PhpDbTestAsset\Pgsql\SetupTrait; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversClass(AdapterPlatform::class)] @@ -17,22 +18,24 @@ final class AdapterPlatformTest extends TestCase { use SetupTrait; - public function testQuoteValueWithPdoPgsql(): void + #[Test] + public function quoteValueWithPdoPgsql(): void { $adapter = $this->getAdapter(self::PDO_ADAPTER); $pgsql = $adapter->getPlatform(); //$this->expectException(VunerablePlatformQuoteException::class); $value = $pgsql->quoteValue('value'); - self::assertEquals('\'value\'', $value); + static::assertSame('\'value\'', $value); } - public function testQuoteValueWithPgsql(): void + #[Test] + public function quoteValueWithPgsql(): void { $adapter = $this->getAdapter(self::NATIVE_ADAPTER); $pgsql = $adapter->getPlatform(); $this->expectException(VunerablePlatformQuoteException::class); $value = $pgsql->quoteValue('value'); - self::assertEquals('\'value\'', $value); + static::assertSame('\'value\'', $value); // Should this assertion be? //todo: self::assertEquals('E\'value\'', $value); diff --git a/test/integration/AdapterTest.php b/test/integration/AdapterTest.php index 189c7eb..aceb342 100644 --- a/test/integration/AdapterTest.php +++ b/test/integration/AdapterTest.php @@ -10,6 +10,7 @@ use PhpDb\Adapter\SchemaAwareInterface; use PhpDbTestAsset\Pgsql\SetupTrait; use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversMethod(Adapter::class, 'getCurrentSchema')] @@ -22,14 +23,16 @@ class AdapterTest extends TestCase { use SetupTrait; - public function testConnection(): void + #[Test] + public function connection(): void { /** @var ConnectionInterface $connection */ $connection = $this->getAdapter()->getDriver()->getConnection(); - $this->assertInstanceOf(ConnectionInterface::class, $connection); + static::assertInstanceOf(ConnectionInterface::class, $connection); } - public function testDriverDisconnectAfterQuoteWithPlatform(): void + #[Test] + public function driverDisconnectAfterQuoteWithPlatform(): void { $isTcpConnection = $this->isTcpConnection(); @@ -38,41 +41,42 @@ public function testDriverDisconnectAfterQuoteWithPlatform(): void /** @var ConnectionInterface $connection */ $connection = $adapter->getDriver()->getConnection(); $connection->connect(); - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); if ($isTcpConnection) { - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); } // todo: why is this not disconnecting $connection->disconnect(); - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); if ($isTcpConnection) { - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); } $connection->connect(); - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); if ($isTcpConnection) { - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); } $adapter->getPlatform()->quoteValue('test'); $connection->disconnect(); - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); if ($isTcpConnection) { - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); } } - public function testGetCurrentSchema(): void + #[Test] + public function getCurrentSchema(): void { /** @var AdapterInterface&SchemaAwareInterface&Adapter $adapter */ $adapter = $this->getAdapter(); $schema = $adapter->getCurrentSchema(); - self::assertIsString($schema); - self::assertNotEmpty($schema); + static::assertIsString($schema); + static::assertNotEmpty($schema); } protected function isTcpConnection(): bool diff --git a/test/integration/Pdo/AdapterTest.php b/test/integration/Pdo/AdapterTest.php index 938381b..522f9c7 100644 --- a/test/integration/Pdo/AdapterTest.php +++ b/test/integration/Pdo/AdapterTest.php @@ -10,6 +10,7 @@ use PhpDb\Adapter\SchemaAwareInterface; use PhpDbTestAsset\Pgsql\SetupTrait; use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversMethod(Adapter::class, 'getCurrentSchema')] @@ -22,14 +23,16 @@ class AdapterTest extends TestCase { use SetupTrait; - public function testConnection(): void + #[Test] + public function connection(): void { /** @var ConnectionInterface $connection */ $connection = $this->getAdapter(self::PDO_ADAPTER)->getDriver()->getConnection(); - $this->assertInstanceOf(ConnectionInterface::class, $connection); + static::assertInstanceOf(ConnectionInterface::class, $connection); } - public function testDriverDisconnectAfterQuoteWithPlatform(): void + #[Test] + public function driverDisconnectAfterQuoteWithPlatform(): void { $isTcpConnection = $this->isTcpConnection(); @@ -38,42 +41,43 @@ public function testDriverDisconnectAfterQuoteWithPlatform(): void $connection = $adapter->getDriver()->getConnection(); $connection->connect(); $isConnected = $connection->isConnected(); - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); if ($isTcpConnection) { - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); } // todo: why is this not disconnecting $connection->disconnect(); $isConnected = $connection->isConnected(); - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); if ($isTcpConnection) { - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); } $connection->connect(); - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); if ($isTcpConnection) { - self::assertTrue($connection->isConnected()); + static::assertTrue($connection->isConnected()); } $adapter->getPlatform()->quoteValue('test'); $connection->disconnect(); - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); if ($isTcpConnection) { - self::assertFalse($connection->isConnected()); + static::assertFalse($connection->isConnected()); } } - public function testGetCurrentSchema(): void + #[Test] + public function getCurrentSchema(): void { /** @var AdapterInterface&SchemaAwareInterface&Adapter $adapter */ $adapter = $this->getAdapter(self::PDO_ADAPTER); $schema = $adapter->getCurrentSchema(); - self::assertIsString($schema); - self::assertNotEmpty($schema); + static::assertIsString($schema); + static::assertNotEmpty($schema); } protected function isTcpConnection(): bool diff --git a/test/integration/Pdo/TableGatewayTest.php b/test/integration/Pdo/TableGatewayTest.php index 56d8849..4d066dc 100644 --- a/test/integration/Pdo/TableGatewayTest.php +++ b/test/integration/Pdo/TableGatewayTest.php @@ -10,6 +10,7 @@ use PhpDb\TableGateway\TableGateway; use PhpDbTestAsset\Pgsql\SetupTrait; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversClass(TableGateway::class)] @@ -17,7 +18,8 @@ final class TableGatewayTest extends TestCase { use SetupTrait; - public function testLastInsertValue(): void + #[Test] + public function lastInsertValue(): void { $table = new TableIdentifier('test_seq'); $featureSet = new FeatureSet(); @@ -26,9 +28,9 @@ public function testLastInsertValue(): void $tableGateway = new TableGateway($table, $this->getAdapter(self::PDO_ADAPTER), $featureSet); $tableGateway->insert(['foo' => 'bar']); - self::assertSame(1, $tableGateway->getLastInsertValue()); + static::assertSame(1, $tableGateway->getLastInsertValue()); $tableGateway->insert(['foo' => 'baz']); - self::assertSame(2, $tableGateway->getLastInsertValue()); + static::assertSame(2, $tableGateway->getLastInsertValue()); } } diff --git a/test/integration/ResultTest.php b/test/integration/ResultTest.php index d05c2de..e8b5dfc 100644 --- a/test/integration/ResultTest.php +++ b/test/integration/ResultTest.php @@ -8,6 +8,7 @@ use PhpDb\Pgsql\Result; use PhpDbTestAsset\Pgsql\SetupTrait; use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversMethod(Result::class, 'getQueryResult')] @@ -16,14 +17,16 @@ class ResultTest extends TestCase { use SetupTrait; - public function testAStatementReturningNoFieldsIsNotAQueryResult(): void + #[Test] + public function aStatementReturningNoFieldsIsNotAQueryResult(): void { $result = $this->getAdapter()->executeQuery('SET search_path TO public'); - self::assertFalse($result->isQueryResult()); + static::assertFalse($result->isQueryResult()); } - public function testGetQueryResultIteratesTheSelectedRows(): void + #[Test] + public function getQueryResultIteratesTheSelectedRows(): void { $result = $this->getAdapter()->executeQuery('SELECT name FROM test ORDER BY id'); @@ -32,10 +35,11 @@ public function testGetQueryResultIteratesTheSelectedRows(): void $names[] = $row['name']; } - self::assertSame(['foo', 'bar'], $names); + static::assertSame(['foo', 'bar'], $names); } - public function testGetQueryResultRejectsAStatementThatReturnsNoFields(): void + #[Test] + public function getQueryResultRejectsAStatementThatReturnsNoFields(): void { $result = $this->getAdapter()->executeQuery('SET search_path TO public'); @@ -48,10 +52,11 @@ public function testGetQueryResultRejectsAStatementThatReturnsNoFields(): void $result->getQueryResult(); } - public function testGetQueryResultSeedsTheResultSetFromASelect(): void + #[Test] + public function getQueryResultSeedsTheResultSetFromASelect(): void { $result = $this->getAdapter()->executeQuery('SELECT id, name, value FROM test'); - self::assertSame($result->getFieldCount(), $result->getQueryResult()->getFieldCount()); + static::assertSame($result->getFieldCount(), $result->getQueryResult()->getFieldCount()); } } diff --git a/test/unit/Adapter/ConfigProviderTest.php b/test/unit/Adapter/ConfigProviderTest.php index e5544ec..d7af202 100644 --- a/test/unit/Adapter/ConfigProviderTest.php +++ b/test/unit/Adapter/ConfigProviderTest.php @@ -16,6 +16,7 @@ use PhpDb\Pgsql\Pdo\Driver as PdoDriver; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversMethod(Pgsql\ConfigProvider::class, '__invoke')] @@ -57,16 +58,18 @@ final class ConfigProviderTest extends TestCase ], ]; - #[Depends('testProvidesExpectedConfiguration')] - public function testInvocationProvidesDependencyConfiguration(Pgsql\ConfigProvider $provider): void + #[Test] + #[Depends('providesExpectedConfiguration')] + public function invocationProvidesDependencyConfiguration(Pgsql\ConfigProvider $provider): void { - self::assertEquals(['dependencies' => $provider->getDependencies()], $provider()); + static::assertEquals(['dependencies' => $provider->getDependencies()], $provider()); } - public function testProvidesExpectedConfiguration(): Pgsql\ConfigProvider + #[Test] + public function providesExpectedConfiguration(): Pgsql\ConfigProvider { $provider = new Pgsql\ConfigProvider(); - self::assertEquals($this->config, $provider->getDependencies()); + static::assertEquals($this->config, $provider->getDependencies()); return $provider; } diff --git a/test/unit/Adapter/SetupTest.php b/test/unit/Adapter/SetupTest.php index a1a3b1e..df4e9a8 100644 --- a/test/unit/Adapter/SetupTest.php +++ b/test/unit/Adapter/SetupTest.php @@ -7,6 +7,7 @@ use PhpDb\Adapter\AdapterInterface; use PhpDbTestAsset\Pgsql\SetupTrait; use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversTrait(SetupTrait::class)] @@ -14,15 +15,17 @@ final class SetupTest extends TestCase { use SetupTrait; - public function testAdapterAbstractFactoryBuildsNativeDriver(): void + #[Test] + public function adapterAbstractFactoryBuildsNativeDriver(): void { $adapter = $this->getAdapter(); - self::assertInstanceOf(AdapterInterface::class, $adapter); + static::assertInstanceOf(AdapterInterface::class, $adapter); } - public function testAdapterInterfaceFactoryBuildsNativeDriver(): void + #[Test] + public function adapterInterfaceFactoryBuildsNativeDriver(): void { $adapter = $this->getAdapter(self::NATIVE_ADAPTER); - self::assertInstanceOf(AdapterInterface::class, $adapter); + static::assertInstanceOf(AdapterInterface::class, $adapter); } } diff --git a/test/unit/ResultTest.php b/test/unit/ResultTest.php index 70b0ad9..7558818 100644 --- a/test/unit/ResultTest.php +++ b/test/unit/ResultTest.php @@ -9,22 +9,25 @@ use PhpDb\ResultSet\ResultSet; use PhpDbTestAsset\Pgsql\ResultStub; use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; #[CoversMethod(Result::class, 'getQueryResult')] class ResultTest extends TestCase { - public function testGetQueryResultClonesTheGivenPrototype(): void + #[Test] + public function getQueryResultClonesTheGivenPrototype(): void { $prototype = new ResultSet(); $result = new ResultStub(true, 1); $resultSet = $result->getQueryResult($prototype); - self::assertNotSame($prototype, $resultSet); + static::assertNotSame($prototype, $resultSet); } - public function testGetQueryResultRejectsAResultThatIsNotAQueryResult(): void + #[Test] + public function getQueryResultRejectsAResultThatIsNotAQueryResult(): void { $this->expectException(Exception\RuntimeException::class); $this->expectExceptionMessage( @@ -36,11 +39,12 @@ public function testGetQueryResultRejectsAResultThatIsNotAQueryResult(): void $result->getQueryResult(); } - public function testGetQueryResultSeedsTheResultSetFromTheResult(): void + #[Test] + public function getQueryResultSeedsTheResultSetFromTheResult(): void { $result = new ResultStub(true, 3); $resultSet = $result->getQueryResult(); - self::assertSame(3, $resultSet->getFieldCount()); + static::assertSame(3, $resultSet->getFieldCount()); } } From a9e19cb784cd4dc9d1bf2a0320b3ad9d2e9cfdd9 Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 31 Aug 2026 13:36:01 +1000 Subject: [PATCH 8/8] Made resource strongly-typed --- src/Result.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Result.php b/src/Result.php index 7475c39..f720007 100644 --- a/src/Result.php +++ b/src/Result.php @@ -19,8 +19,7 @@ // phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse class Result implements ResultInterface { - /** @var PgSqlResult */ - protected $resource; + protected PgSqlResult $resource; protected int $position = 0;