diff --git a/composer.json b/composer.json index e5f63c3..a753655 100644 --- a/composer.json +++ b/composer.json @@ -30,17 +30,18 @@ } }, "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "php-db/phpdb": "^0.2.1" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "php-db/phpdb": "^0.4.1" }, "require-dev": { + "ext-pdo_pgsql": "*", + "ext-pgsql": "*", "laminas/laminas-coding-standard": "^3.0.1", "phpstan/phpstan": "^2.1", "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^11.5.15" + "phpunit/phpunit": "^11.5.42" }, "suggest": { - "ext-pdo": "*", "ext-pdo_pgsql": "*", "ext-pgsql": "*", "laminas/laminas-servicemanager": "Laminas\\ServiceManager component" @@ -53,13 +54,14 @@ "autoload-dev": { "psr-4": { "PhpDbTest\\Adapter\\Pgsql\\": "test/unit/", + "PhpDbTestAsset\\Pgsql\\": "test/asset/", "PhpDbIntegrationTest\\Adapter\\Pgsql\\": "test/integration/" } }, "scripts": { "check": [ "@cs-check", - "@static-analysis", + "@sa", "@test", "@test-integration" ], @@ -68,8 +70,9 @@ "test": "phpunit --colors=always --testsuite \"unit test\"", "test-coverage": "phpunit --colors=always --coverage-clover clover.xml", "test-integration": "phpunit --colors=always --testsuite \"integration test\"", - "static-analysis": "vendor/bin/phpstan analyse --memory-limit=256M", + "sa": "vendor/bin/phpstan analyse --memory-limit=256M", "sa-generate-baseline": "vendor/bin/phpstan analyse --memory-limit=256M --generate-baseline", + "sa-verbose": "vendor/bin/phpstan analyse --memory-limit=256M -vv", "upload-coverage": "coveralls -v" } } diff --git a/composer.lock b/composer.lock index 0413512..4461851 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,30 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "93b90a40dd4fe8c39502da74c4585c56", + "content-hash": "5063e7391ca1bbb366715a6569a7af12", "packages": [ { "name": "brick/varexporter", - "version": "0.5.0", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/brick/varexporter.git", - "reference": "84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b" + "reference": "af98bfc2b702a312abbcaff37656dbe419cec5bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/varexporter/zipball/84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b", - "reference": "84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b", + "url": "https://api.github.com/repos/brick/varexporter/zipball/af98bfc2b702a312abbcaff37656dbe419cec5bc", + "reference": "af98bfc2b702a312abbcaff37656dbe419cec5bc", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", - "php": "^7.4 || ^8.0" + "php": "^8.1" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^9.3", - "psalm/phar": "5.21.1" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "6.8.4" }, "type": "library", "autoload": { @@ -45,7 +45,7 @@ ], "support": { "issues": "https://github.com/brick/varexporter/issues", - "source": "https://github.com/brick/varexporter/tree/0.5.0" + "source": "https://github.com/brick/varexporter/tree/0.6.0" }, "funding": [ { @@ -53,26 +53,26 @@ "type": "github" } ], - "time": "2024-05-10T17:15:19+00:00" + "time": "2025-02-20T17:42:39+00:00" }, { "name": "laminas/laminas-servicemanager", - "version": "4.4.0", + "version": "4.5.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "74da44d07e493b834347123242d0047976fb9932" + "reference": "a6996829c8ce55025cca1b57b1e8a8b165e3926c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/74da44d07e493b834347123242d0047976fb9932", - "reference": "74da44d07e493b834347123242d0047976fb9932", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/a6996829c8ce55025cca1b57b1e8a8b165e3926c", + "reference": "a6996829c8ce55025cca1b57b1e8a8b165e3926c", "shasum": "" }, "require": { - "brick/varexporter": "^0.3.8 || ^0.4.0 || ^0.5.0", + "brick/varexporter": "^0.3.8 || ^0.4.0 || ^0.5.0 || ^0.6.0", "laminas/laminas-stdlib": "^3.19", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "psr/container": "^1.1 || ^2.0" }, "conflict": { @@ -86,14 +86,14 @@ "composer/package-versions-deprecated": "^1.11.99.5", "friendsofphp/proxy-manager-lts": "^1.0.18", "laminas/laminas-cli": "^1.11", - "laminas/laminas-coding-standard": "~3.0.1", - "laminas/laminas-container-config-test": "^1.0", + "laminas/laminas-coding-standard": "~3.1.0", + "laminas/laminas-container-config-test": "^1.1", "mikey179/vfsstream": "^1.6.12", - "phpbench/phpbench": "^1.4.0", - "phpunit/phpunit": "^10.5.44", - "psalm/plugin-phpunit": "^0.19.2", - "symfony/console": "^6.4.17 || ^7.0", - "vimeo/psalm": "^6.2.0" + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^10.5.58", + "psalm/plugin-phpunit": "^0.19.5", + "symfony/console": "^6.4.17 || ^7.3.4", + "vimeo/psalm": "^6.13.1" }, "suggest": { "friendsofphp/proxy-manager-lts": "To handle lazy initialization of services", @@ -130,7 +130,7 @@ "chat": "https://laminas.dev/chat", "forum": "https://discourse.laminas.dev", "issues": "https://github.com/laminas/laminas-servicemanager/issues", - "source": "https://github.com/laminas/laminas-servicemanager/tree/4.4.0" + "source": "https://github.com/laminas/laminas-servicemanager/tree/4.5.0" }, "funding": [ { @@ -138,34 +138,34 @@ "type": "community_bridge" } ], - "time": "2025-02-04T06:13:50+00:00" + "time": "2025-10-14T09:41:04+00:00" }, { "name": "laminas/laminas-stdlib", - "version": "3.20.0", + "version": "3.21.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" + "reference": "b1c81514cfe158aadf724c42b34d3d0a8164c096" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", - "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/b1c81514cfe158aadf724c42b34d3d0a8164c096", + "reference": "b1c81514cfe158aadf724c42b34d3d0a8164c096", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^3.0", - "phpbench/phpbench": "^1.3.1", - "phpunit/phpunit": "^10.5.38", - "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.26.1" + "laminas/laminas-coding-standard": "^3.1.0", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^11.5.42", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.13.1" }, "type": "library", "autoload": { @@ -197,20 +197,20 @@ "type": "community_bridge" } ], - "time": "2024-10-29T13:46:07+00:00" + "time": "2025-10-11T18:13:12+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -253,28 +253,28 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "php-db/phpdb", - "version": "0.2.1", + "version": "0.4.x-dev", "source": { "type": "git", "url": "https://github.com/php-db/phpdb.git", - "reference": "d221b024cb3aea77992f41a962913918301dc92e" + "reference": "3cb7531b36bf37c42843bbe9dd05583d8d8f130e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-db/phpdb/zipball/d221b024cb3aea77992f41a962913918301dc92e", - "reference": "d221b024cb3aea77992f41a962913918301dc92e", + "url": "https://api.github.com/repos/php-db/phpdb/zipball/3cb7531b36bf37c42843bbe9dd05583d8d8f130e", + "reference": "3cb7531b36bf37c42843bbe9dd05583d8d8f130e", "shasum": "" }, "require": { - "laminas/laminas-servicemanager": "^4.0.0", + "laminas/laminas-servicemanager": "^3.0.0 || ^4.0.0", "laminas/laminas-stdlib": "^3.20.0", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, "conflict": { "laminas/laminas-db": "*", @@ -283,6 +283,8 @@ "require-dev": { "laminas/laminas-coding-standard": "^3.0.1", "laminas/laminas-eventmanager": "^3.14.0", + "laminas/laminas-hydrator": "^4.6.0", + "phpbench/phpbench": "^1.4", "phpstan/phpstan": "^2.1", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^11.5.15", @@ -321,7 +323,7 @@ "issues": "https://github.com/php-db/phpdb/issues", "source": "https://github.com/php-db/phpdb" }, - "time": "2025-10-07T08:36:48+00:00" + "time": "2025-12-05T01:52:04+00:00" }, { "name": "psr/container", @@ -380,29 +382,29 @@ "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.1.2", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", "shasum": "" }, "require": { "composer-plugin-api": "^2.2", "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.1.0 || ^4.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", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", @@ -472,7 +474,7 @@ "type": "thanks_dev" } ], - "time": "2025-07-17T20:45:56+00:00" + "time": "2025-11-11T04:32:07+00:00" }, { "name": "laminas/laminas-coding-standard", @@ -754,11 +756,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.30", + "version": "2.1.33", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a4a7f159927983dd4f7c8020ed227d80b7f39d7d", - "reference": "a4a7f159927983dd4f7c8020ed227d80b7f39d7d", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", + "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", "shasum": "" }, "require": { @@ -803,25 +805,25 @@ "type": "github" } ], - "time": "2025-10-02T16:07:52+00:00" + "time": "2025-12-05T10:24:31+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "2.0.7", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "9a9b161baee88a5f5c58d816943cff354ff233dc" + "reference": "8d61a5854e7497d95bc85188e13537e99bd7aae7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/9a9b161baee88a5f5c58d816943cff354ff233dc", - "reference": "9a9b161baee88a5f5c58d816943cff354ff233dc", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/8d61a5854e7497d95bc85188e13537e99bd7aae7", + "reference": "8d61a5854e7497d95bc85188e13537e99bd7aae7", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.1.18" + "phpstan/phpstan": "^2.1.32" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -854,9 +856,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.7" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.10" }, - "time": "2025-07-13T11:31:46+00:00" + "time": "2025-12-06T11:15:39+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1195,16 +1197,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.42", + "version": "11.5.46", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c" + "reference": "75dfe79a2aa30085b7132bb84377c24062193f33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c", - "reference": "1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/75dfe79a2aa30085b7132bb84377c24062193f33", + "reference": "75dfe79a2aa30085b7132bb84377c24062193f33", "shasum": "" }, "require": { @@ -1276,7 +1278,7 @@ "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.42" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.46" }, "funding": [ { @@ -1300,7 +1302,7 @@ "type": "tidelift" } ], - "time": "2025-09-28T12:09:13+00:00" + "time": "2025-12-06T08:01:15+00:00" }, { "name": "sebastian/cli-parser", @@ -2355,16 +2357,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.4", + "version": "3.13.5", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119" + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ad545ea9c1b7d270ce0fc9cbfb884161cd706119", - "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", "shasum": "" }, "require": { @@ -2381,11 +2383,6 @@ "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -2435,7 +2432,7 @@ "type": "thanks_dev" } ], - "time": "2025-09-05T05:47:09+00:00" + "time": "2025-11-04T16:30:35+00:00" }, { "name": "staabm/side-effects-detector", @@ -2491,16 +2488,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -2529,7 +2526,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -2537,7 +2534,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-17T20:03:58+00:00" }, { "name": "webimpress/coding-standard", @@ -2601,11 +2598,14 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "platform-dev": { + "ext-pdo_pgsql": "*", + "ext-pgsql": "*" }, - "platform-dev": {}, "platform-overrides": { "php": "8.2.99" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 97ae618..295633b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -29,10 +29,10 @@ - - - - - + + + + + \ No newline at end of file diff --git a/src/Platform/Postgresql.php b/src/AdapterPlatform.php similarity index 84% rename from src/Platform/Postgresql.php rename to src/AdapterPlatform.php index 55fac46..9ba5f64 100644 --- a/src/Platform/Postgresql.php +++ b/src/AdapterPlatform.php @@ -2,46 +2,38 @@ declare(strict_types=1); -namespace PhpDb\Adapter\Pgsql\Platform; +namespace PhpDb\Adapter\Pgsql; use Override; use PDO; use PgSql\Connection as PgSqlConnection; -use PhpDb\Adapter\AdapterInterface; use PhpDb\Adapter\Driver\DriverInterface; use PhpDb\Adapter\Driver\PdoDriverInterface; -use PhpDb\Adapter\Driver\Pgsql\Pgsql; -use PhpDb\Adapter\Exception; -use PhpDb\Adapter\Pgsql\Driver\Pdo\Pdo as PdoDriver; use PhpDb\Adapter\Platform\AbstractPlatform; use PhpDb\Sql\Platform\Platform as SqlPlatformDecorator; use PhpDb\Sql\Platform\PlatformDecoratorInterface; -use function get_resource_type; use function implode; -use function in_array; use function is_resource; use function pg_escape_string; use function str_replace; -class Postgresql extends AbstractPlatform +class AdapterPlatform extends AbstractPlatform { public final const PLATFORM_NAME = 'PostgreSQL'; + /** * Overrides value from AbstractPlatform to use proper escaping for Postgres - * - * @var string */ - protected $quoteIdentifierTo = '""'; + protected string $quoteIdentifierTo = '""'; /** @var string[] */ - private $knownPgsqlResources = [ + private array $knownPgsqlResources = [ 'pgsql link', 'pgsql link persistent', ]; public function __construct( - //private readonly PDO|Pgsql|PdoDriver $driver private readonly DriverInterface|PdoDriverInterface|PDO $driver, ) { } @@ -79,7 +71,6 @@ public function quoteValue($value): string * {@inheritDoc} * * @param scalar $value - * @return string */ #[Override] public function quoteTrustedValue($value): string diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 19aa7af..be98388 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -6,28 +6,88 @@ use Laminas\ServiceManager\Factory\InvokableFactory; use PhpDb\Adapter\AdapterInterface; +use PhpDb\Adapter\Driver\ConnectionInterface; use PhpDb\Adapter\Driver\DriverInterface; +use PhpDb\Adapter\Driver\PdoConnectionInterface; +use PhpDb\Adapter\Driver\PdoDriverInterface; use PhpDb\Adapter\Platform\PlatformInterface; +use PhpDb\Adapter\Pgsql\Pdo\Connection as PdoConnection; +use PhpDb\Adapter\Pgsql\Pdo\Driver as PdoDriver; +use PhpDb\Adapter\Profiler\Profiler; +use PhpDb\Adapter\Profiler\ProfilerInterface; +use PhpDb\Container\AdapterAbstractServiceFactory; +use PhpDb\Metadata\MetadataInterface; +use PhpDb\ResultSet\ResultSetInterface; -readonly class ConfigProvider +final readonly class ConfigProvider { public function __invoke(): array { return [ - 'dependencies' => $this->getDependencies(), + 'dependencies' => $this->getDependencies(), + AdapterInterface::class => $this->getAdapters(), + ]; + } + + public function getAdapters(): array + { + return [ + 'adapters' => [ + AdapterInterface::class => [ + 'driver' => Driver::class, + 'connection' => [ + 'host' => 'localhost', + 'port' => 5432, + 'username' => 'your_username', + 'password' => 'your_password', + 'database' => 'your_database', + ], + ], + ], ]; } public function getDependencies(): array { return [ + 'abstract_factories' => [ + Container\AdapterAbstractServiceFactory::class, + ], 'aliases' => [ - PlatformInterface::class => Platform\Postgresql::class, + DriverInterface::class => Driver::class, + 'pgsql' => Driver::class, + 'PgSQL' => Driver::class, + 'Postgresql' => Driver::class, + 'PostgreSQL' => Driver::class, + PdoDriverInterface::class => PdoDriver::class, + 'pdo_pgsql' => PdoDriver::class, + 'PDO_pgsql' => PdoDriver::class, + 'PDO_PgSQL' => PdoDriver::class, + 'Pdo_PgSQL' => PdoDriver::class, + 'PDO_postgresql' => PdoDriver::class, + 'pdo_postgresql' => PdoDriver::class, + 'PDO_Postgresql' => PdoDriver::class, + 'Pdo_Postgresql' => PdoDriver::class, + 'PDO_PostgreSQL' => PdoDriver::class, + 'pdo_PostgreSQL' => PdoDriver::class, + ConnectionInterface::class => Connection::class, + MetadataInterface::class => Metadata\Source::class, + PdoConnectionInterface::class => PdoConnection::class, + PlatformInterface::class => AdapterPlatform::class, ], 'factories' => [ - AdapterInterface::class => Container\AdapterServiceFactory::class, - DriverInterface::class => Container\PdoDriverInterfaceFactory::class, - Platform\Postgresql::class => InvokableFactory::class, + //AdapterInterface::class => Container\AdapterInterfaceFactory::class, + AdapterPlatform::class => Container\PlatformInterfaceFactory::class, + Connection::class => Container\ConnectionInterfaceFactory::class, + Metadata\Source::class => Container\MetadataInterfaceFactory::class, + Statement::class => Container\StatementInterfaceFactory::class, + Driver::class => Container\DriverInterfaceFactory::class, + PdoConnection::class => Container\PdoConnectionInterfaceFactory::class, + PdoDriver::class => Container\PdoDriverInterfaceFactory::class, + // Provide the following if you wish to override the Profiler implementation + //ProfilerInterface::class => YourCustomProfilerFactory::class, + // Provide the following if you wish to override the ResultSet implementation + //ResultSetInterface::class => YourCustomResultSetFactory::class, ], ]; } diff --git a/src/Driver/Pgsql/Connection.php b/src/Connection.php similarity index 77% rename from src/Driver/Pgsql/Connection.php rename to src/Connection.php index 03aba23..b058bc4 100644 --- a/src/Driver/Pgsql/Connection.php +++ b/src/Connection.php @@ -2,8 +2,9 @@ declare(strict_types=1); -namespace PhpDb\Adapter\Pgsql\Driver\Pgsql; +namespace PhpDb\Adapter\Pgsql; +use Override; use PgSql\Connection as PgSqlConnection; use PhpDb\Adapter\Driver\AbstractConnection; use PhpDb\Adapter\Driver\ConnectionInterface; @@ -16,7 +17,7 @@ use function array_filter; use function http_build_query; use function is_array; -use function is_resource; +use function pg_close; use function pg_connect; use function pg_fetch_result; use function pg_last_error; @@ -26,48 +27,53 @@ use function set_error_handler; use function sprintf; use function str_replace; +use function strtolower; use function urldecode; use const PGSQL_CONNECT_FORCE_NEW; class Connection extends AbstractConnection implements DriverAwareInterface { - /** @var Pgsql */ - protected $driver; + protected Driver $driver; + + /** @var PgSqlConnection|null */ + protected $resource; /** @var null|int PostgreSQL connection type */ protected ?int $type = null; - public function __construct(PgSqlConnection|array|null $connectionInfo = null) + public function __construct(PgSqlConnection|array $connectionInfo) { if (is_array($connectionInfo)) { $this->setConnectionParameters($connectionInfo); - } elseif ($connectionInfo instanceof PgSqlConnection || is_resource($connectionInfo)) { + } else { $this->setResource($connectionInfo); } } - public function setResource(PgSqlConnection $resource): ConnectionInterface - { + public function setResource( + PgSqlConnection $resource + ): ConnectionInterface&DriverAwareInterface { $this->resource = $resource; return $this; } - /** - * old param type hint Pgsql $driver - */ - public function setDriver(DriverInterface $driver): DriverAwareInterface + #[Override] + public function getResource(): ?PgSqlConnection { + return $this->resource; + } + + public function setDriver( + DriverInterface $driver + ): ConnectionInterface&DriverAwareInterface { $this->driver = $driver; return $this; } - /** - * @return $this Provides a fluent interface - */ - public function setType(?int $type): static + public function setType(?int $type): ConnectionInterface&DriverAwareInterface { $invalidConectionType = $type !== PGSQL_CONNECT_FORCE_NEW; if ($invalidConectionType) { @@ -80,12 +86,7 @@ public function setType(?int $type): static return $this; } - /** - * {@inheritDoc} - * - * @return null|string - */ - public function getCurrentSchema(): bool|string + public function getCurrentSchema(): string|false { if (! $this->isConnected()) { $this->connect(); @@ -157,7 +158,6 @@ public function isConnected(): bool */ public function disconnect(): static { - // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFallbackGlobalName pg_close($this->resource); return $this; @@ -269,8 +269,32 @@ public function getLastGeneratedValue($name = null): bool|int|string|null */ private function getConnectionString(): string { - $connectionParameters = array_filter((new PgsqlConfig())($this->connectionParameters)); + $parameters = $this->connectionParameters; + $conn = []; + foreach ($parameters as $name => $value) { + $name = match (strtolower($name)) { + 'host', 'hostname' => 'host', + 'user', 'username' => 'user', + 'password', 'passwd', 'pw' => 'password', + 'database', 'dbname', 'db', 'schema' => 'dbname', + 'port' => 'port', + 'socket' => 'socket', + default => throw new Exception\InvalidArgumentException( + 'Connection parameter "' . $name . '" is not valid for Pgsql adapter' + ), + }; + if ($name === 'port' && $value !== null) { + $value = (int) $value; + } + $conn[$name] = $value; + } - return urldecode(http_build_query($connectionParameters, '', ' ')); + return urldecode( + http_build_query( + array_filter($conn), + '', + ' ' + ) + ); } } diff --git a/src/Container/AdapterAbstractServiceFactory.php b/src/Container/AdapterAbstractServiceFactory.php new file mode 100644 index 0000000..f8f68b2 --- /dev/null +++ b/src/Container/AdapterAbstractServiceFactory.php @@ -0,0 +1,141 @@ +getConfig($container); + if ($config === []) { + return false; + } + + return isset($config[$requestedName]) + && is_array($config[$requestedName]) + && ! empty($config[$requestedName]); + } + + /** + * Create a DB adapter + * + * @param string $requestedName + */ + public function __invoke( + ContainerInterface|ServiceManager $container, + $requestedName, + ?array $options = null + ): AdapterInterface&Adapter { + /** @var string|null $driverClass */ + $driverClass = $this->config[$requestedName]['driver'] ?? null; + if ($driverClass === null) { + throw new ServiceNotCreatedException( + sprintf('Cannot create adapter "%s"; no driver configured', $requestedName) + ); + } + + /** @var DriverInterface|PdoDriverInterface $driver */ + $driver = $container->build($driverClass, $this->config[$requestedName]); + /** @var PlatformInterface&Pgsql\AdapterPlatform $platform */ + $platform = $container->build(PlatformInterface::class, ['driver' => $driver]); + /** @var ResultSetInterface|null $resultSet */ + $resultSet = $container->has(ResultSetInterface::class) + ? $container->build(ResultSetInterface::class) + : null; + /** @var ProfilerInterface|null $profiler */ + $profiler = $container->has(ProfilerInterface::class) + ? $container->build(ProfilerInterface::class) + : null; + + return match(true) { + $resultSet !== null && $profiler !== null => new Adapter( + driver:$driver, + platform: $platform, + queryResultSetPrototype: $resultSet, + profiler: $profiler, + ), + $resultSet !== null => new Adapter( + driver:$driver, + platform: $platform, + queryResultSetPrototype: $resultSet, + ), + $profiler !== null => new Adapter( + driver:$driver, + platform: $platform, + profiler: $profiler, + ), + default => new Adapter( + driver:$driver, + platform: $platform, + ), + }; + } + + /** + * Get db configuration, if any + * todo: refactor to use PhpDb\ConfigProvider::ADAPTERS_CONFIG_KEY instead of hardcoding 'adapters' + */ + protected function getConfig(ContainerInterface $container): array + { + if ($this->config !== null) { + return $this->config; + } + + if (! $container->has('config')) { + $this->config = []; + return $this->config; + } + + $config = $container->get('config'); + if ( + ! isset($config[AdapterInterface::class]) + || ! is_array($config[AdapterInterface::class]) + ) { + $this->config = []; + return $this->config; + } + + $config = $config[AdapterInterface::class]; + if ( + ! isset($config['adapters']) + || ! is_array($config['adapters']) + ) { + $this->config = []; + return $this->config; + } + + $this->config = $config['adapters']; + return $this->config; + } +} diff --git a/src/Container/AdapterInterfaceFactory.php b/src/Container/AdapterInterfaceFactory.php index 602df73..1b3df2e 100644 --- a/src/Container/AdapterInterfaceFactory.php +++ b/src/Container/AdapterInterfaceFactory.php @@ -12,7 +12,6 @@ use PhpDb\Adapter\Exception\RuntimeException; use PhpDb\Adapter\Platform\PlatformInterface; use PhpDb\Adapter\Profiler\ProfilerInterface; -use PhpDb\Container\AdapterManager; use PhpDb\ResultSet\ResultSetInterface; use Psr\Container\ContainerInterface; @@ -20,25 +19,76 @@ class AdapterInterfaceFactory { - /** - * Create db adapter service - * - * @param array|null $options - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface - */ - public function __invoke(ContainerInterface $container): AdapterInterface { - $resultSetPrototype = $container->has(ResultSetInterface::class) - ? $container->get(ResultSetInterface::class) + public function __invoke( + ContainerInterface $container, + string $requestedName, + ): AdapterInterface { + if (! $container->has('config')) { + throw new ServiceNotFoundException( + sprintf( + 'Could not find service "config" in container %s', + $container::class + ) + ); + } + + /** @var array $config */ + $config = $container->get('config'); + + /** @var array $dbConfig */ + $dbConfig = $config[AdapterInterface::class][$requestedName] ?? $config[AdapterInterface::class] ?? []; + + if (! isset($dbConfig['driver'])) { + throw new RuntimeException( + 'Database configuration must contain a "driver" key' + ); + } + + /** @var string $driver */ + $driver = $dbConfig['driver']; + if (! $container->has($driver)) { + throw new ServiceNotFoundException( + sprintf( + 'Could not find database driver service "%s" in container %s', + $driver, + $container::class + ) + ); + } + /** @var DriverInterface|PdoDriverInterface $driverInstance */ + $driverInstance = $container->get($driver); + + if (! $container->has(PlatformInterface::class)) { + throw new ServiceNotFoundException( + sprintf( + 'Could not find service "%s" in container %s', + PlatformInterface::class, + $container::class + ) + ); + } + + /** @var PlatformInterface $adapterPlatform */ + $adapterPlatform = $container->get(PlatformInterface::class); + + /** @var ProfilerInterface|null $profilerInstanceOrNull */ + $profilerInstanceOrNull = $container->has(ProfilerInterface::class) + ? $container->get(ProfilerInterface::class) : null; - $profiler = $container->get(ProfilerInterface::class); + if (! $container->has(ResultSetInterface::class)) { + return new $requestedName( + driver: $driverInstance, + platform: $adapterPlatform, + profiler: $profilerInstanceOrNull + ); + } - return new Adapter( - $container->get(DriverInterface::class), - $container->get(Platform\Postgresql::class), - $resultSetPrototype, - $profiler + return new $requestedName( + driver: $driverInstance, + platform: $adapterPlatform, + queryResultSetPrototype: $container->get(ResultSetInterface::class), + profiler: $profilerInstanceOrNull ); } } diff --git a/src/Container/ConnectionInterfaceFactory.php b/src/Container/ConnectionInterfaceFactory.php new file mode 100644 index 0000000..6b6e478 --- /dev/null +++ b/src/Container/ConnectionInterfaceFactory.php @@ -0,0 +1,31 @@ +get('config')[AdapterInterface::class]['adapters'][$requestedName]['connection'] + ?? null; + if ($connectionInfo === null || ! is_array($connectionInfo) || $connectionInfo === []) { + throw new InvalidConnectionParametersException( + 'Connection configuration must be an array of parameters', + $connectionInfo + ); + } + return new Connection($connectionInfo); + } +} diff --git a/src/Container/ConnectionInterfaceFactoryFactory.php b/src/Container/ConnectionInterfaceFactoryFactory.php deleted file mode 100644 index 16b120f..0000000 --- a/src/Container/ConnectionInterfaceFactoryFactory.php +++ /dev/null @@ -1,10 +0,0 @@ -get('config')[AdapterInterface::class]['adapters'][$requestedName]['connection'] + ?? []; + $connection = $container->build(Pgsql\Connection::class, ['connection' => $connectionParameters]); + return new Pgsql\Driver( + connection:$connection, + statementPrototype: $container->build(Pgsql\Statement::class, ['options' => $options['options'] ?? []]), + resultPrototype: new Pgsql\Result(), + ); + } +} diff --git a/src/Container/DriverInterfaceFactoryFactory.php b/src/Container/DriverInterfaceFactoryFactory.php deleted file mode 100644 index 72da1fa..0000000 --- a/src/Container/DriverInterfaceFactoryFactory.php +++ /dev/null @@ -1,10 +0,0 @@ -profiler = $profiler; if ($this->connection instanceof ProfilerAwareInterface) { $this->connection->setProfiler($profiler); @@ -77,7 +76,7 @@ public function checkEnvironment(): bool { if (! extension_loaded('pgsql')) { throw new Exception\RuntimeException( - 'The PostgreSQL (pgsql) extension is required for this adapter but the extension is not loaded' + 'The PostgreSQL (pgsql) extension is required for this Driver but the extension is not loaded' ); } return true; @@ -115,7 +114,7 @@ public function createStatement($sqlOrResource = null): StatementInterface&State /** * Create result * - * @param resource|PgSqlResult|PgSqlConnection $resource + * @param PgSqlResult $resource */ #[Override] public function createResult($resource): ResultInterface&Result diff --git a/src/Driver/DatabasePlatformNameTrait.php b/src/Driver/DatabasePlatformNameTrait.php deleted file mode 100644 index a940404..0000000 --- a/src/Driver/DatabasePlatformNameTrait.php +++ /dev/null @@ -1,20 +0,0 @@ - $value) { - $name = match (strtolower($name)) { - 'host', 'hostname' => 'host', - 'user', 'username' => 'user', - 'password', 'passwd', 'pw' => 'password', - 'database', 'dbname', 'db', 'schema' => 'dbname', - 'port' => 'port', - 'socket' => 'socket', - default => throw new InvalidArgumentException( - 'Unknown connection parameter "' . $name . '"' - ), - }; - $connectionParameters[$name] = $value; - } - - $connectionFilters = [ - 'host' => [ - 'filter' => FILTER_SANITIZE_URL, - 'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_EMPTY_STRING_NULL, - ], - 'user' => [ - 'filter' => FILTER_SANITIZE_ENCODED, - 'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_EMPTY_STRING_NULL, - ], - 'password' => [ - 'filter' => FILTER_SANITIZE_ENCODED, - 'flags' => FILTER_FLAG_EMPTY_STRING_NULL, - ], - 'database' => [ - 'filter' => FILTER_SANITIZE_ENCODED, - 'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_EMPTY_STRING_NULL, - ], - 'socket' => [ - 'filter' => FILTER_SANITIZE_ENCODED, - 'flags' => FILTER_FLAG_EMPTY_STRING_NULL, - ], - 'port' => [ - 'filter' => FILTER_VALIDATE_INT, - 'flags' => FILTER_NULL_ON_FAILURE, - ], - ]; - - return filter_var_array($connectionParameters, $connectionFilters); - } -} diff --git a/src/Driver/Pgsql/Result.php b/src/Driver/Pgsql/Result.php deleted file mode 100644 index 92831c6..0000000 --- a/src/Driver/Pgsql/Result.php +++ /dev/null @@ -1,174 +0,0 @@ -resource = $resource; - $this->count = pg_num_rows($this->resource); - $this->generatedValue = $generatedValue; - } - - /** - * Current - * - * @return array|bool|mixed - */ - #[ReturnTypeWillChange] - public function current() - { - if ($this->count === 0) { - return false; - } - return pg_fetch_assoc($this->resource, $this->position); - } - - /** - * Next - * - * @return void - */ - #[ReturnTypeWillChange] - public function next() - { - $this->position++; - } - - /** - * Key - * - * @return int|mixed - */ - #[ReturnTypeWillChange] - public function key() - { - return $this->position; - } - - /** - * Valid - * - * @return bool - */ - #[ReturnTypeWillChange] - public function valid() - { - return $this->position < $this->count; - } - - /** - * Rewind - * - * @return void - */ - #[ReturnTypeWillChange] - public function rewind() - { - $this->position = 0; - } - - /** todo: track this */ - public function buffer(): void - { - } - - /** - * Is buffered - */ - public function isBuffered(): ?bool - { - return false; - } - - public function isQueryResult(): bool - { - return pg_num_fields($this->resource) > 0; - } - - /** - * Get affected rows - */ - public function getAffectedRows(): int - { - return pg_affected_rows($this->resource); - } - - /** - * Get generated value - * - * @return mixed|null - */ - public function getGeneratedValue() - { - return $this->generatedValue; - } - - /** - * Get resource - */ - public function getResource() - { - // TODO: Implement getResource() method. - } - - /** - * Count - * - * @return int The custom count as an integer. - */ - #[ReturnTypeWillChange] - public function count() - { - return $this->count; - } - - /** - * Get field count - */ - public function getFieldCount(): int - { - return pg_num_fields($this->resource); - } -} diff --git a/src/Exception/ContainerException.php b/src/Exception/ContainerException.php new file mode 100644 index 0000000..639e953 --- /dev/null +++ b/src/Exception/ContainerException.php @@ -0,0 +1,25 @@ +data['schemas'])) { return; diff --git a/src/Driver/Pdo/Connection.php b/src/Pdo/Connection.php similarity index 97% rename from src/Driver/Pdo/Connection.php rename to src/Pdo/Connection.php index 3f5de24..e8597e0 100644 --- a/src/Driver/Pdo/Connection.php +++ b/src/Pdo/Connection.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpDb\Adapter\Pgsql\Driver\Pdo; +namespace PhpDb\Adapter\Pgsql\Pdo; use Override; use PDO; @@ -26,7 +26,7 @@ class Connection extends AbstractPdoConnection * {@inheritDoc} */ #[Override] - public function getCurrentSchema(): string|bool + public function getCurrentSchema(): string|false { if (! $this->isConnected()) { $this->connect(); diff --git a/src/Driver/Pdo/Pdo.php b/src/Pdo/Driver.php similarity index 81% rename from src/Driver/Pdo/Pdo.php rename to src/Pdo/Driver.php index 1aee71d..48f21a2 100644 --- a/src/Driver/Pdo/Pdo.php +++ b/src/Pdo/Driver.php @@ -2,16 +2,16 @@ declare(strict_types=1); -namespace PhpDb\Adapter\Pgsql\Driver\Pdo; +namespace PhpDb\Adapter\Pgsql\Pdo; use Override; use PDOStatement; use PhpDb\Adapter\Driver\Pdo\AbstractPdo; use PhpDb\Adapter\Driver\Pdo\Result; use PhpDb\Adapter\Driver\ResultInterface; -use PhpDb\Adapter\Pgsql\Driver\DatabasePlatformNameTrait; +use PhpDb\Adapter\Pgsql\DatabasePlatformNameTrait; -class Pdo extends AbstractPdo +class Driver extends AbstractPdo { use DatabasePlatformNameTrait; diff --git a/src/Result.php b/src/Result.php new file mode 100644 index 0000000..9f71e89 --- /dev/null +++ b/src/Result.php @@ -0,0 +1,116 @@ +resource = $resource; + $this->count = pg_num_rows($this->resource); + $this->generatedValue = $generatedValue; + } + + #[Override] + public function current(): array|false + { + if ($this->count === 0) { + return false; + } + return pg_fetch_assoc($this->resource, $this->position); + } + + #[Override] + public function next(): void + { + $this->position++; + } + + #[Override] + public function key(): int + { + return $this->position; + } + + #[Override] + public function valid(): bool + { + return $this->position < $this->count; + } + + #[Override] + public function rewind(): void + { + $this->position = 0; + } + + #[Override] + public function buffer(): void + { + } + + #[Override] + public function isBuffered(): false + { + return false; + } + + #[Override] + public function isQueryResult(): bool + { + return pg_num_fields($this->resource) > 0; + } + + #[Override] + public function getAffectedRows(): int + { + return pg_affected_rows($this->resource); + } + + #[Override] + public function getGeneratedValue(): mixed + { + return $this->generatedValue; + } + + /** + * Get resource + */ + public function getResource(): PgSqlResult + { + return $this->resource; + } + + #[Override] + public function count(): int + { + return $this->count; + } + + #[Override] + public function getFieldCount(): int + { + return pg_num_fields($this->resource); + } +} diff --git a/src/Driver/Pgsql/Statement.php b/src/Statement.php similarity index 51% rename from src/Driver/Pgsql/Statement.php rename to src/Statement.php index fcb26f1..8ea3752 100644 --- a/src/Driver/Pgsql/Statement.php +++ b/src/Statement.php @@ -2,151 +2,123 @@ declare(strict_types=1); -namespace PhpDb\Adapter\Pgsql\Driver\Pgsql; +namespace PhpDb\Adapter\Pgsql; +use Override; +use PgSql\Connection as PgSqlConnection; +use PgSql\Result as PgSqlResult; +use PhpDb\Adapter\Driver\DriverAwareInterface; +use PhpDb\Adapter\Driver\DriverInterface; use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\Adapter\Driver\StatementInterface; use PhpDb\Adapter\Exception; use PhpDb\Adapter\ParameterContainer; -use PhpDb\Adapter\Pgsql\Connection as PgSqlConnection; -use PhpDb\Adapter\Profiler; +use PhpDb\Adapter\Profiler\ProfilerAwareInterface; +use PhpDb\Adapter\Profiler\ProfilerInterface; -use function get_resource_type; use function is_array; -use function is_resource; use function pg_execute; use function pg_last_error; use function pg_prepare; use function preg_replace_callback; -use function sprintf; -class Statement implements StatementInterface, Profiler\ProfilerAwareInterface +class Statement implements + StatementInterface, + DriverAwareInterface, + ProfilerAwareInterface { + protected bool $bufferResults = false; + protected static int $statementIndex = 0; - protected string $statementName = ''; + protected string $statementName = 'statement'; - protected Pgsql $driver; + protected Driver $driver; - protected Profiler\ProfilerInterface $profiler; + protected ProfilerInterface $profiler; - /** @var resource */ - protected $pgsql; + protected PgSqlConnection $pgsql; - /** @var resource */ - protected $resource; + protected PgSqlResult|false $resource; protected string $sql; - protected ParameterContainer $parameterContainer; + public function __construct( + protected ParameterContainer $parameterContainer = new ParameterContainer(), + array|bool $options = false + ) { + if (is_array($options)) { + $this->bufferResults = $options['buffer_results'] ?? false; + } else { + $this->bufferResults = $options; + } + } - /** - * @return $this Provides a fluent interface - */ - public function setDriver(Pgsql $driver): static - { + #[Override] + public function setDriver( + DriverInterface $driver + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { $this->driver = $driver; return $this; } - /** - * @return $this Provides a fluent interface - */ - public function setProfiler(Profiler\ProfilerInterface $profiler): static - { + #[Override] + public function setProfiler( + ProfilerInterface $profiler + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { $this->profiler = $profiler; return $this; } - public function getProfiler(): ?Profiler\ProfilerInterface + public function getProfiler(): (StatementInterface&ProfilerInterface)|null { return $this->profiler; } - /** - * Initialize - * - * @param resource $pgsql - * @throws Exception\RuntimeException For invalid or missing postgresql connection. - */ - public function initialize($pgsql): void + public function initialize(PgSqlConnection $pgsql): void { - if ( - ! $pgsql instanceof PgSqlConnection - && ( - ! is_resource($pgsql) - || 'pgsql link' !== get_resource_type($pgsql) - ) - ) { - throw new Exception\RuntimeException(sprintf( - '%s: Invalid or missing postgresql connection; received "%s"', - __METHOD__, - get_resource_type($pgsql) - )); - } - $this->pgsql = $pgsql; } - /** - * Get resource - * - * @todo Implement this method - * phpcs:ignore Squiz.Commenting.FunctionComment.InvalidNoReturn - * @return resource - */ - public function getResource() + #[Override] + public function getResource(): PgSqlResult|false { return $this->resource; } - /** - * Set sql - * - * @param string $sql - * @return $this Provides a fluent interface - */ - public function setSql($sql): static - { + #[Override] + public function setSql( + ?string $sql + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { $this->sql = $sql; return $this; } - /** - * Get sql - */ + #[Override] public function getSql(): ?string { return $this->sql; } - /** - * Set parameter container - * - * @return $this Provides a fluent interface - */ - public function setParameterContainer(ParameterContainer $parameterContainer): static - { + #[Override] + public function setParameterContainer( + ParameterContainer $parameterContainer + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { $this->parameterContainer = $parameterContainer; return $this; } - /** - * Get parameter container - */ + #[Override] public function getParameterContainer(): ParameterContainer { return $this->parameterContainer; } - /** - * Prepare - * - * @param string $sql - */ - public function prepare($sql = null): StatementInterface - { - $sql = $sql ?: $this->sql; + #[Override] + public function prepare( + ?string $sql = null + ): StatementInterface&DriverAwareInterface&ProfilerAwareInterface { + $sql = $sql ?? $this->sql; $pCount = 1; $sql = preg_replace_callback( @@ -157,14 +129,13 @@ function () use (&$pCount) { $sql ); - $this->sql = $sql; - $this->statementName = 'statement' . ++static::$statementIndex; - $this->resource = pg_prepare($this->pgsql, $this->statementName, $sql); + $this->sql = $sql; + $this->statementName .= ++static::$statementIndex; + $this->resource = pg_prepare($this->pgsql, $this->statementName, $sql); + return $this; } - /** - * Is prepared - */ + #[Override] public function isPrepared(): bool { return isset($this->resource); @@ -174,8 +145,8 @@ public function isPrepared(): bool * Execute * * @throws Exception\InvalidQueryException - * @return Result */ + #[Override] public function execute(ParameterContainer|array|null $parameters = null): ?ResultInterface { if (! $this->isPrepared()) { diff --git a/test/asset/SetupTrait.php b/test/asset/SetupTrait.php new file mode 100644 index 0000000..e6ba423 --- /dev/null +++ b/test/asset/SetupTrait.php @@ -0,0 +1,152 @@ +getAdapter(); + parent::setUp(); + } + + public function getAdapter(string $adapter = self::NATIVE_ADAPTER): AdapterInterface + { + $serviceManagerConfig = ArrayUtils::merge( + (new Pgsql\ConfigProvider())()['dependencies'], + [ + 'services' => [ + 'config' => $this->getTestConfig(), + ], + ] + ); + $this->serviceManager = new ServiceManager($serviceManagerConfig); + return $this->serviceManager->get($adapter); + } + + public function getTestConfig(): array + { + return [ + AdapterInterface::class => [ + 'adapters' => [ + self::NATIVE_ADAPTER => [ + 'driver' => Pgsql\Driver::class, + 'connection' => [ + 'host' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'), + 'port' => 5432, + 'username' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_USERNAME'), + 'password' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_PASSWORD'), + 'database' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), + ], + ], + self::PDO_ADAPTER => [ + 'driver' => Pgsql\Pdo\Driver::class, + 'connection' => [ + 'host' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'), + 'port' => 5432, + 'username' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_USERNAME'), + 'password' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_PASSWORD'), + 'database' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), + ], + ], + ], + ], + ]; + } + + public function getMockedAdapter(string $adapter = self::NATIVE_ADAPTER): AdapterInterface + { + $driverMock = $this->getMockBuilder(DriverInterface::class)->getMock(); + $pdoDriverMock = $this->getMockBuilder(PdoDriverInterface::class)->getMock(); + $testConfig = [ + AdapterInterface::class => [ + 'adapters' => [ + self::NATIVE_ADAPTER => [ + 'driver' => Pgsql\Driver::class, + 'connection' => [ + 'host' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'), + 'port' => 5432, + 'username' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_USERNAME'), + 'password' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_PASSWORD'), + 'database' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), + ], + ], + self::PDO_ADAPTER => [ + 'driver' => Pgsql\Pdo\Driver::class, + 'connection' => [ + 'host' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'), + 'port' => 5432, + 'username' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_USERNAME'), + 'password' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_PASSWORD'), + 'database' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), + ], + ], + ], + ], + 'dependencies' => [ + 'abstract_factories' => [ + Pgsql\Container\AdapterAbstractServiceFactory::class, + ], + 'aliases' => [ + DriverInterface::class => Pgsql\Driver::class, + 'pgsql' => Pgsql\Driver::class, + 'PgSQL' => Pgsql\Driver::class, + 'Postgresql' => Pgsql\Driver::class, + 'PostgreSQL' => Pgsql\Driver::class, + PdoDriverInterface::class => Pgsql\Pdo\Driver::class, + 'pdo_pgsql' => Pgsql\Pdo\Driver::class, + 'PDO_pgsql' => Pgsql\Pdo\Driver::class, + 'PDO_PgSQL' => Pgsql\Pdo\Driver::class, + 'Pdo_PgSQL' => Pgsql\Pdo\Driver::class, + 'PDO_postgresql' => Pgsql\Pdo\Driver::class, + 'pdo_postgresql' => Pgsql\Pdo\Driver::class, + 'PDO_Postgresql' => Pgsql\Pdo\Driver::class, + 'Pdo_Postgresql' => Pgsql\Pdo\Driver::class, + 'PDO_PostgreSQL' => Pgsql\Pdo\Driver::class, + 'pdo_PostgreSQL' => Pgsql\Pdo\Driver::class, + ConnectionInterface::class => Pgsql\Connection::class, + PdoConnectionInterface::class => Pgsql\Pdo\Connection::class, + PlatformInterface::class => Pgsql\AdapterPlatform::class, + ], + 'factories' => [ + Pgsql\Driver::class => function (ContainerInterface $container) use ($driverMock) { + return $driverMock; + }, + Pgsql\Pdo\Driver::class => function (ContainerInterface $container) use ($pdoDriverMock) { + return $pdoDriverMock; + }, + ], + ], + ]; + + $libConfig = (new Pgsql\ConfigProvider())(); + $config = ArrayUtils::merge($libConfig, $testConfig); + $serviceManagerConfig = ArrayUtils::merge( + $config['dependencies'], + [ + 'services' => [ + 'config' => $config, + ], + ] + ); + + $this->serviceManager = new ServiceManager($serviceManagerConfig); + return $this->serviceManager->get($adapter); + } +} diff --git a/test/integration/Adapter/Driver/Pdo/Postgresql/AdapterTest.php b/test/integration/Adapter/Driver/Pdo/Postgresql/AdapterTest.php deleted file mode 100644 index 7604764..0000000 --- a/test/integration/Adapter/Driver/Pdo/Postgresql/AdapterTest.php +++ /dev/null @@ -1,14 +0,0 @@ -markTestSkipped('pdo_pgsql integration tests are not enabled!'); - } - - $this->adapter = new Adapter([ - 'driver' => 'pdo_pgsql', - 'database' => (string) getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_DATABASE'), - 'hostname' => (string) getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_HOSTNAME'), - 'username' => (string) getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_USERNAME'), - 'password' => (string) getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_PASSWORD'), - ]); - - $this->hostname = (string) getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_HOSTNAME'); - } -} diff --git a/test/integration/Adapter/Platform/PostgresqlTest.php b/test/integration/AdapterPlatformTest.php similarity index 74% rename from test/integration/Adapter/Platform/PostgresqlTest.php rename to test/integration/AdapterPlatformTest.php index 7bec9ab..759d5f6 100644 --- a/test/integration/Adapter/Platform/PostgresqlTest.php +++ b/test/integration/AdapterPlatformTest.php @@ -1,12 +1,12 @@ */ public array|\PDO $adapters = []; @@ -25,23 +25,23 @@ final class PostgresqlTest extends TestCase #[Override] protected function setUp(): void { - if (! getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL')) { + if (! getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL')) { $this->markTestSkipped(self::class . ' integration tests are not enabled!'); } if (extension_loaded('pgsql')) { $this->adapters['pgsql'] = pg_connect( - 'host=' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_HOSTNAME') - . ' dbname=' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_DATABASE') - . ' user=' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_USERNAME') - . ' password=' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_PASSWORD') + 'host=' . getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_HOSTNAME') + . ' dbname=' . getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_DATABASE') + . ' user=' . getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_USERNAME') + . ' password=' . getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_PASSWORD') ); } if (extension_loaded('pdo')) { $this->adapters['pdo_pgsql'] = new \PDO( - 'pgsql:host=' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_HOSTNAME') . ';dbname=' - . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_DATABASE'), - getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_USERNAME'), - getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_PGSQL_PASSWORD') + 'pgsql:host=' . getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_HOSTNAME') . ';dbname=' + . getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_DATABASE'), + getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_USERNAME'), + getenv('TESTS_LAMINAS_DB_ADAPTER_PGSQL_PASSWORD') ); } } @@ -60,11 +60,11 @@ public function testQuoteValueWithPgsql() ) { $this->markTestSkipped('Postgres (pgsql) not configured in unit test configuration file'); } - $pgsql = new Postgresql($this->adapters['pgsql']); + $pgsql = new AdapterPlatform($this->adapters['pgsql']); $value = $pgsql->quoteValue('value'); self::assertEquals('\'value\'', $value); - $pgsql = new Postgresql(new Pgsql\Pgsql(new Pgsql\Connection($this->adapters['pgsql']))); + $pgsql = new AdapterPlatform(new Driver(new PgSqlConnection($this->adapters['pgsql']))); $value = $pgsql->quoteValue('value'); self::assertEquals('\'value\'', $value); } diff --git a/test/integration/Extension/IntegrationTestStartedListener.php b/test/integration/Extension/IntegrationTestStartedListener.php new file mode 100644 index 0000000..b3dc4c3 --- /dev/null +++ b/test/integration/Extension/IntegrationTestStartedListener.php @@ -0,0 +1,44 @@ +testSuite()->name() !== 'integration test') { + return; + } + + if (getenv('TESTS_PHPDB_ADAPTER_MYSQL')) { + $this->fixtureLoaders[] = new PgsqlFixtureLoader(); + } + + if (empty($this->fixtureLoaders)) { + return; + } + + printf("\nIntegration test started.\n"); + + foreach ($this->fixtureLoaders as $fixtureLoader) { + $fixtureLoader->createDatabase(); + } + } +} diff --git a/test/integration/Extension/IntegrationTestStoppedListener.php b/test/integration/Extension/IntegrationTestStoppedListener.php new file mode 100644 index 0000000..dcf1b9f --- /dev/null +++ b/test/integration/Extension/IntegrationTestStoppedListener.php @@ -0,0 +1,33 @@ +testSuite()->name() !== 'integration test' + || empty($this->fixtureLoaders) + ) { + return; + } + + printf("\nIntegration test ended.\n"); + + foreach ($this->fixtureLoaders as $fixtureLoader) { + $fixtureLoader->dropDatabase(); + } + } +} diff --git a/test/integration/Extension/ListenerExtension.php b/test/integration/Extension/ListenerExtension.php new file mode 100644 index 0000000..9f0f171 --- /dev/null +++ b/test/integration/Extension/ListenerExtension.php @@ -0,0 +1,24 @@ +registerSubscribers( + new IntegrationTestStartedListener(), + new IntegrationTestStoppedListener(), + ); + } +} diff --git a/test/integration/FixtureLoader/PgsqlFixtureLoader.php b/test/integration/FixtureLoader/PgsqlFixtureLoader.php index f2cd5d6..c54a7c5 100644 --- a/test/integration/FixtureLoader/PgsqlFixtureLoader.php +++ b/test/integration/FixtureLoader/PgsqlFixtureLoader.php @@ -34,12 +34,12 @@ public function createDatabase(): void if ( false === $this->pdo->exec(sprintf( "CREATE DATABASE %s", - getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_DATABASE') + getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE') )) ) { throw new Exception(sprintf( "I cannot create the PostgreSQL %s test database: %s", - getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_DATABASE'), + getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), print_r($this->pdo->errorInfo(), true) )); } @@ -52,7 +52,7 @@ 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 ", - getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_DATABASE'), + getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), $this->fixtureFile, print_r($this->pdo->errorInfo(), true) )); @@ -75,7 +75,7 @@ public function dropDatabase(): void $this->pdo->exec(sprintf( "DROP DATABASE IF EXISTS %s", - getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_DATABASE') + getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE') )); $this->disconnect(); @@ -86,16 +86,16 @@ public function dropDatabase(): void */ protected function connect(bool $useDb = false): void { - $dsn = 'pgsql:host=' . getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_HOSTNAME'); + $dsn = 'pgsql:host=' . getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'); if ($useDb) { - $dsn .= ';dbname=' . getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_DATABASE'); + $dsn .= ';dbname=' . getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'); } $this->pdo = new PDO( $dsn, - getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_USERNAME'), - getenv('TESTS_PHPDB_ADAPTER_DRIVER_PGSQL_PASSWORD') + getenv('TESTS_PHPDB_ADAPTER_PGSQL_USERNAME'), + getenv('TESTS_PHPDB_ADAPTER_PGSQL_PASSWORD') ); } diff --git a/test/integration/Pdo/AdapterTest.php b/test/integration/Pdo/AdapterTest.php new file mode 100644 index 0000000..2710453 --- /dev/null +++ b/test/integration/Pdo/AdapterTest.php @@ -0,0 +1,84 @@ +getAdapter()->getDriver()->getConnection(); + $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(); + + /** @var AdapterInterface&Adapter $adapter */ + $adapter = $this->getAdapter([ + 'db' => [ + 'driver' => Driver::class, + ], + ]); + $adapter->getDriver()->getConnection()->connect(); + self::assertTrue($adapter->getDriver()->getConnection()->isConnected()); + if ($isTcpConnection) { + self::assertTrue($adapter->getDriver()->getConnection()->isConnected()); + } + + $adapter->getDriver()->getConnection()->disconnect(); + self::assertFalse($adapter->getDriver()->getConnection()->isConnected()); + if ($isTcpConnection) { + self::assertFalse($adapter->getDriver()->getConnection()->isConnected()); + } + + $adapter->getDriver()->getConnection()->connect(); + self::assertTrue($adapter->getDriver()->getConnection()->isConnected()); + if ($isTcpConnection) { + self::assertTrue($adapter->getDriver()->getConnection()->isConnected()); + } + + $adapter->getPlatform()->quoteValue('test'); + + $adapter->getDriver()->getConnection()->disconnect(); + + self::assertFalse($adapter->getDriver()->getConnection()->isConnected()); + if ($isTcpConnection) { + self::assertFalse($adapter->getDriver()->getConnection()->isConnected()); + } + } + + protected function isTcpConnection(): bool + { + $hostName = $this->getHostname(); + return $hostName !== 'localhost' && $hostName !== '127.0.0.1'; + } +} diff --git a/test/integration/Pdo/SetupTrait.php b/test/integration/Pdo/SetupTrait.php new file mode 100644 index 0000000..2918279 --- /dev/null +++ b/test/integration/Pdo/SetupTrait.php @@ -0,0 +1,66 @@ +markTestSkipped('pdo_pgsql integration tests are not enabled!'); + } + + $connectionParams = [ + 'driver' => 'pdo_pgsql', + 'database' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_DATABASE'), + 'hostname' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'), + 'username' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_USERNAME'), + 'password' => (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_PASSWORD'), + ]; + + $pdoDriver = new Driver( + new Connection($connectionParams), + new Statement(), + new Result() + ); + + $this->adapter = new Adapter( + $pdoDriver, + new AdapterPlatform($pdoDriver) + ); + + $this->hostname = (string) getenv('TESTS_PHPDB_ADAPTER_PGSQL_HOSTNAME'); + } + + public function getAdapter(): AdapterInterface + { + return $this->adapter; + } + + public function getHostname(): string + { + return $this->hostname; + } +} diff --git a/test/integration/Adapter/Driver/Pdo/Postgresql/TableGatewayTest.php b/test/integration/Pdo/TableGatewayTest.php similarity index 81% rename from test/integration/Adapter/Driver/Pdo/Postgresql/TableGatewayTest.php rename to test/integration/Pdo/TableGatewayTest.php index 6d278a6..160ca49 100644 --- a/test/integration/Adapter/Driver/Pdo/Postgresql/TableGatewayTest.php +++ b/test/integration/Pdo/TableGatewayTest.php @@ -1,8 +1,9 @@ getDependencies(); - $config['services']['config'] = $dbConfig; - - return new ServiceManager($config); - } - - #[Override] - protected function setUp(): void - { - if (! extension_loaded('pdo_sqlite')) { - $this->markTestSkipped('Adapter factory tests require pdo_sqlite'); - } - - $this->factory = new AdapterInterfaceFactory(); - } - - /** - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface - */ - public function testV3FactoryReturnsDefaultAdapter(): void - { - $this->expectNotToPerformAssertions(); - - $services = $this->createServiceManager([ - 'db' => [ - 'driver' => 'Pdo_Pgsql', - 'database' => ':memory:', - ], - ]); - - $this->factory->__invoke($services, Adapter::class); - } - - /** - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface - */ - public function testV3FactoryReturnsDefaultAdapterWithDefaultProfiler(): void - { - $services = $this->createServiceManager([ - 'db' => [ - 'driver' => 'Pdo_Pgsql', - 'database' => ':memory:', - 'profiler' => true, - ], - ]); - - $adapter = $this->factory->__invoke($services, Adapter::class); - self::assertInstanceOf(ProfilerInterface::class, $adapter->getProfiler()); - } - - /** - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface - */ - public function testV3FactoryReturnsDefaultAdapterWithProfilerClassname(): void - { - $services = $this->createServiceManager([ - 'db' => [ - 'driver' => 'Pdo_Pgsql', - 'database' => ':memory:', - 'profiler' => Profiler::class, - ], - ]); - - $adapter = $this->factory->__invoke($services, Adapter::class); - self::assertInstanceOf(ProfilerInterface::class, $adapter->getProfiler()); - } - - /** - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface - */ - public function testV3FactoryReturnsDefaultAdapterWithProfilerInstance(): void - { - $services = $this->createServiceManager([ - 'db' => [ - 'driver' => 'Pdo_Pgsql', - 'database' => ':memory:', - 'profiler' => $this->getMockBuilder(ProfilerInterface::class)->getMock(), - ], - ]); - - $adapter = $this->factory->__invoke($services, Adapter::class); - self::assertInstanceOf(ProfilerInterface::class, $adapter->getProfiler()); - } -} diff --git a/test/unit/Adapter/AdapterTest.php b/test/unit/Adapter/AdapterTest.php index 0ee756b..cdfb8f0 100644 --- a/test/unit/Adapter/AdapterTest.php +++ b/test/unit/Adapter/AdapterTest.php @@ -12,12 +12,11 @@ use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\Adapter\Driver\StatementInterface; use PhpDb\Adapter\ParameterContainer; -use PhpDb\Adapter\Pgsql\Driver\Pdo\Pdo; -use PhpDb\Adapter\Pgsql\Platform\Postgresql as PgsqlPlatform; +use PhpDb\Adapter\Pgsql\AdapterPlatform; +use PhpDb\Adapter\Pgsql\Pdo\Driver; use PhpDb\Adapter\Profiler; use PhpDb\ResultSet\ResultSet; use PhpDb\ResultSet\ResultSetInterface; -use PhpDbTest\TestAsset\TemporaryResultSet; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\TestDox; @@ -40,7 +39,7 @@ final class AdapterTest extends TestCase { protected DriverInterface&MockObject $mockDriver; - protected PgsqlPlatform $mockPlatform; + protected AdapterPlatform $mockPlatform; protected ConnectionInterface&MockObject $mockConnection; @@ -194,9 +193,6 @@ public function testQueryWhenExecutedProducesAResultSetObjectWhenResultIsQuery() $r = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); self::assertInstanceOf(ResultSet::class, $r); - - $r = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE, new TemporaryResultSet()); - self::assertInstanceOf(TemporaryResultSet::class, $r); } #[TestDox('unit test: Test createStatement() produces a statement object')] @@ -220,33 +216,33 @@ public function testMagicGet(): void $this->adapter->foo; } - /** - * @throws Exception - */ - #[Override] - protected function setUp(): void - { - $this->mockConnection = $this->createMock(ConnectionInterface::class); - $this->mockPlatform = new PgsqlPlatform(); - $this->mockStatement = $this->getMockBuilder(Statement::class)->getMock(); - $this->mockDriver = $this->getMockBuilder(Pdo::class) - ->setConstructorArgs([ - $this->mockConnection, - $this->mockStatement, - ]) - ->getMock(); - - $this->mockResultSet = $this->getMockBuilder(ResultSetInterface::class)->getMock(); - - $this->mockDriver->method('getDatabasePlatformName')->willReturn('Pgsql'); - $this->mockDriver->method('checkEnvironment')->willReturn(true); - $this->mockDriver->method('getConnection')->willReturn($this->mockConnection); - //$this->mockDriver->method('createStatement')->willReturn($this->mockStatement); - - $this->adapter = new Adapter( - $this->mockDriver, - $this->mockPlatform, - $this->mockResultSet - ); - } + // #[Override] + // protected function setUp(): void + // { + // $this->mockConnection = $this->createMock(ConnectionInterface::class); + + // $this->mockStatement = $this->getMockBuilder(Statement::class)->getMock(); + + // $this->mockDriver = $this->getMockBuilder(Driver::class) + // ->setConstructorArgs([ + // $this->mockConnection, + // $this->mockStatement, + // ]) + // ->getMock(); + + // $this->mockDriver->method('getDatabasePlatformName')->willReturn('Pgsql'); + // $this->mockDriver->method('checkEnvironment')->willReturn(true); + // $this->mockDriver->method('getConnection')->willReturn($this->mockConnection); + // $this->mockDriver->method('createStatement')->willReturn($this->mockStatement); + + // $this->mockPlatform = new AdapterPlatform($this->mockDriver); + + // $this->mockResultSet = $this->getMockBuilder(ResultSetInterface::class)->getMock(); + + // $this->adapter = new Adapter( + // $this->mockDriver, + // $this->mockPlatform, + // $this->mockResultSet + // ); + // } } diff --git a/test/unit/Adapter/ConfigProviderTest.php b/test/unit/Adapter/ConfigProviderTest.php index 4132144..8d1c86b 100644 --- a/test/unit/Adapter/ConfigProviderTest.php +++ b/test/unit/Adapter/ConfigProviderTest.php @@ -6,46 +6,70 @@ use Laminas\ServiceManager\Factory\InvokableFactory; use PhpDb\Adapter\AdapterInterface; +use PhpDb\Adapter\Driver\ConnectionInterface; use PhpDb\Adapter\Driver\DriverInterface; -use PhpDb\Adapter\Pgsql\ConfigProvider; -use PhpDb\Adapter\Pgsql\Container\AdapterServiceFactory; -use PhpDb\Adapter\Pgsql\Driver; -use PhpDb\Adapter\Pgsql\Platform; +use PhpDb\Adapter\Driver\PdoConnectionInterface; +use PhpDb\Adapter\Driver\PdoDriverInterface; +use PhpDb\Adapter\Pgsql; use PhpDb\Adapter\Platform\PlatformInterface; use PhpDb\Adapter\Profiler\Profiler; use PhpDb\Adapter\Profiler\ProfilerInterface; +use PhpDb\Container\AdapterAbstractServiceFactory; +use PhpDb\Metadata\MetadataInterface; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\Depends; use PHPUnit\Framework\TestCase; -#[CoversMethod(ConfigProvider::class, '__invoke')] -#[CoversMethod(ConfigProvider::class, 'getDependencies')] +#[CoversMethod(Pgsql\ConfigProvider::class, '__invoke')] +#[CoversMethod(Pgsql\ConfigProvider::class, 'getDependencies')] final class ConfigProviderTest extends TestCase { /** @var array> */ private array $config = [ 'aliases' => [ - PlatformInterface::class => Platform\Postgresql::class, - ProfilerInterface::class => Profiler::class, + DriverInterface::class => Pgsql\Driver::class, + 'pgsql' => Pgsql\Driver::class, + 'PgSQL' => Pgsql\Driver::class, + 'Postgresql' => Pgsql\Driver::class, + 'PostgreSQL' => Pgsql\Driver::class, + PdoDriverInterface::class => Pgsql\Pdo\Driver::class, + 'pdo_pgsql' => Pgsql\Pdo\Driver::class, + 'PDO_pgsql' => Pgsql\Pdo\Driver::class, + 'PDO_PgSQL' => Pgsql\Pdo\Driver::class, + 'Pdo_PgSQL' => Pgsql\Pdo\Driver::class, + 'PDO_postgresql' => Pgsql\Pdo\Driver::class, + 'pdo_postgresql' => Pgsql\Pdo\Driver::class, + 'PDO_Postgresql' => Pgsql\Pdo\Driver::class, + 'Pdo_Postgresql' => Pgsql\Pdo\Driver::class, + 'PDO_PostgreSQL' => Pgsql\Pdo\Driver::class, + 'pdo_PostgreSQL' => Pgsql\Pdo\Driver::class, + ConnectionInterface::class => Pgsql\Connection::class, + MetadataInterface::class => Pgsql\Metadata\Source::class, + PdoConnectionInterface::class => Pgsql\Pdo\Connection::class, + PlatformInterface::class => Pgsql\AdapterPlatform::class, + ProfilerInterface::class => Profiler::class, ], 'factories' => [ - AdapterInterface::class => AdapterServiceFactory::class, - DriverInterface::class => Driver\Pdo\DriverFactory::class, - Platform\Postgresql::class => InvokableFactory::class, - Profiler::class => InvokableFactory::class, + AdapterInterface::class => Pgsql\Container\AdapterInterfaceFactory::class, + Pgsql\Driver::class => Pgsql\Container\DriverInterfaceFactory::class, + Pgsql\Pdo\Driver::class => Pgsql\Container\PdoDriverInterfaceFactory::class, + Pgsql\Connection::class => Pgsql\Container\ConnectionInterfaceFactory::class, + Pgsql\Pdo\Connection::class => Pgsql\Container\PdoConnectionInterfaceFactory::class, + Pgsql\AdapterPlatform::class => Pgsql\Container\PlatformInterfaceFactory::class, + Profiler::class => InvokableFactory::class, ], ]; - public function testProvidesExpectedConfiguration(): ConfigProvider + public function testProvidesExpectedConfiguration(): Pgsql\ConfigProvider { - $provider = new ConfigProvider(); + $provider = new Pgsql\ConfigProvider(); self::assertEquals($this->config, $provider->getDependencies()); return $provider; } #[Depends('testProvidesExpectedConfiguration')] - public function testInvocationProvidesDependencyConfiguration(ConfigProvider $provider): void + public function testInvocationProvidesDependencyConfiguration(Pgsql\ConfigProvider $provider): void { self::assertEquals(['dependencies' => $provider->getDependencies()], $provider()); } diff --git a/test/unit/Adapter/SetupTest.php b/test/unit/Adapter/SetupTest.php new file mode 100644 index 0000000..8ed8abf --- /dev/null +++ b/test/unit/Adapter/SetupTest.php @@ -0,0 +1,20 @@ +getAdapter(); + self::assertInstanceOf(AdapterInterface::class, $adapter); + } +}