diff --git a/.gitattributes b/.gitattributes index 4368bd2..a43edfe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,11 +1,14 @@ /.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 +/lint-baseline.toml export-ignore +/analyzer-baseline.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/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/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/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 new file mode 100644 index 0000000..f7bb3dd --- /dev/null +++ b/mago.toml @@ -0,0 +1,13 @@ +#: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"] + +[linter] +baseline = "lint-baseline.toml" + +[analyzer] +baseline = "analyzer-baseline.toml" 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..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')] @@ -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..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')] @@ -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()); - } }