diff --git a/composer.json b/composer.json index 55effa2..1f58b5a 100644 --- a/composer.json +++ b/composer.json @@ -32,8 +32,8 @@ } }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", - "php-db/phpdb": "^0.1.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "php-db/phpdb": "^0.1.1" }, "require-dev": { "ext-mysqli": "*", diff --git a/composer.lock b/composer.lock index 930fce5..8e9f62b 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": "0a28997311306ff77626a0d7c49dc330", + "content-hash": "e5e1ef9a4473d1845705bbe6dfa7c935", "packages": [ { "name": "brick/varexporter", @@ -259,16 +259,16 @@ }, { "name": "php-db/phpdb", - "version": "0.1.0", + "version": "0.1.1", "source": { "type": "git", "url": "https://github.com/php-db/phpdb.git", - "reference": "db3f84bd1952885ded3ed2b6731e82b7e9943bf9" + "reference": "f671eabd951cd5da927ea814c8d0f83bb16247e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-db/phpdb/zipball/db3f84bd1952885ded3ed2b6731e82b7e9943bf9", - "reference": "db3f84bd1952885ded3ed2b6731e82b7e9943bf9", + "url": "https://api.github.com/repos/php-db/phpdb/zipball/f671eabd951cd5da927ea814c8d0f83bb16247e0", + "reference": "f671eabd951cd5da927ea814c8d0f83bb16247e0", "shasum": "" }, "require": { @@ -321,7 +321,7 @@ "issues": "https://github.com/php-db/phpdb/issues", "source": "https://github.com/php-db/phpdb" }, - "time": "2025-08-06T05:15:11+00:00" + "time": "2025-09-15T22:14:40+00:00" }, { "name": "psr/container", @@ -2875,16 +2875,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.36", + "version": "11.5.39", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "264a87c7ef68b1ab9af7172357740dc266df5957" + "reference": "ad5597f79d8489d2870073ac0bc0dd0ad1fa9931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/264a87c7ef68b1ab9af7172357740dc266df5957", - "reference": "264a87c7ef68b1ab9af7172357740dc266df5957", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ad5597f79d8489d2870073ac0bc0dd0ad1fa9931", + "reference": "ad5597f79d8489d2870073ac0bc0dd0ad1fa9931", "shasum": "" }, "require": { @@ -2956,7 +2956,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.36" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.39" }, "funding": [ { @@ -2980,7 +2980,7 @@ "type": "tidelift" } ], - "time": "2025-09-03T06:24:17+00:00" + "time": "2025-09-14T06:20:41+00:00" }, { "name": "psalm/plugin-phpunit", @@ -4246,16 +4246,16 @@ }, { "name": "slevomat/coding-standard", - "version": "8.22.0", + "version": "8.22.1", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "a4cef983bad2e70125612d22b2f6e2bd1333d5c2" + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/a4cef983bad2e70125612d22b2f6e2bd1333d5c2", - "reference": "a4cef983bad2e70125612d22b2f6e2bd1333d5c2", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/1dd80bf3b93692bedb21a6623c496887fad05fec", + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec", "shasum": "" }, "require": { @@ -4267,11 +4267,11 @@ "require-dev": { "phing/phing": "3.0.1|3.1.0", "php-parallel-lint/php-parallel-lint": "1.4.0", - "phpstan/phpstan": "2.1.22", + "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.8" + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.36|12.3.10" }, "type": "phpcodesniffer-standard", "extra": { @@ -4295,7 +4295,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.22.0" + "source": "https://github.com/slevomat/coding-standard/tree/8.22.1" }, "funding": [ { @@ -4307,7 +4307,7 @@ "type": "tidelift" } ], - "time": "2025-09-06T09:14:48+00:00" + "time": "2025-09-13T08:53:30+00:00" }, { "name": "spatie/array-to-xml", diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 59f46a9..5380170 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -7,25 +7,133 @@ - - - - + + + + + + + + + + + get('config')[AdapterManager::class]]]> + + + + + + + + + + + + + + + + + + + + + + + + + + get('config')[AdapterManager::class]]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - @@ -116,9 +224,6 @@ - - - @@ -151,9 +256,6 @@ - - - resource->affected_rows]]> resource->num_rows]]> @@ -225,9 +327,6 @@ - - - @@ -288,9 +387,6 @@ - - - @@ -303,9 +399,6 @@ - - - @@ -480,14 +573,8 @@ - - - - - - @@ -546,9 +633,6 @@ - - - @@ -585,15 +669,7 @@ - - - - - - - - processInfo['paramPrefix']]]> processInfo['paramPrefix']]]> diff --git a/psalm.xml.dist b/psalm.xml.dist index a063019..d0a7d11 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -35,6 +35,12 @@ + + + + + + diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 9eb4524..d0a9c1d 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -14,8 +14,12 @@ use PhpDb\Adapter\Mysql\Metadata\Source\MysqlMetadata; use PhpDb\Adapter\Platform\PlatformInterface; use PhpDb\Adapter\Profiler; +use PhpDb\Container\AdapterAbstractServiceFactory; use PhpDb\Container\AdapterManager; +use PhpDb\Container\ConnectionInterfaceFactoryFactoryInterface; +use PhpDb\Container\DriverInterfaceFactoryFactoryInterface; use PhpDb\Container\MetadataFactory; +use PhpDb\Container\PlatformInterfaceFactoryFactoryInterface; use PhpDb\Metadata\MetadataInterface; use PhpDb\ResultSet; @@ -32,13 +36,16 @@ public function __invoke(): array public function getDependencies(): array { return [ - 'aliases' => [ + 'abstract_factories' => [ + AdapterAbstractServiceFactory::class, + ], + 'aliases' => [ MetadataInterface::class => MysqlMetadata::class, ], - 'factories' => [ + 'factories' => [ MysqlMetadata::class => MetadataFactory::class, ], - 'delegators' => [ + 'delegators' => [ AdapterManager::class => [ Container\AdapterManagerDelegator::class, ], @@ -49,24 +56,27 @@ public function getDependencies(): array public function getAdapterManagerConfig(): array { return [ - 'aliases' => [ - 'MySqli' => Driver\Mysqli\Mysqli::class, - 'MySQLi' => Driver\Mysqli\Mysqli::class, - 'Mysqli' => Driver\Mysqli\Mysqli::class, - 'mysqli' => Driver\Mysqli\Mysqli::class, - 'PDO_MySQL' => Driver\Pdo\Pdo::class, - 'Pdo_MySQL' => Driver\Pdo\Pdo::class, - 'Pdo_Mysql' => Driver\Pdo\Pdo::class, - 'pdo_mysql' => Driver\Pdo\Pdo::class, - 'pdomysql' => Driver\Pdo\Pdo::class, - 'pdodriver' => Driver\Pdo\Pdo::class, - 'pdo' => Driver\Pdo\Pdo::class, - DriverInterface::class => Driver\Mysqli\Mysqli::class, - PdoDriverInterface::class => Driver\Pdo\Pdo::class, - Profiler\ProfilerInterface::class => Profiler\Profiler::class, - ResultSet\ResultSetInterface::class => ResultSet\ResultSet::class, + 'aliases' => [ + 'MySqli' => Driver\Mysqli\Mysqli::class, + 'MySQLi' => Driver\Mysqli\Mysqli::class, + 'Mysqli' => Driver\Mysqli\Mysqli::class, + 'mysqli' => Driver\Mysqli\Mysqli::class, + 'PDO_MySQL' => Driver\Pdo\Pdo::class, + 'Pdo_MySQL' => Driver\Pdo\Pdo::class, + 'Pdo_Mysql' => Driver\Pdo\Pdo::class, + 'pdo_mysql' => Driver\Pdo\Pdo::class, + 'pdomysql' => Driver\Pdo\Pdo::class, + 'pdodriver' => Driver\Pdo\Pdo::class, + 'pdo' => Driver\Pdo\Pdo::class, + DriverInterface::class => Driver\Mysqli\Mysqli::class, + PdoDriverInterface::class => Driver\Pdo\Pdo::class, + Profiler\ProfilerInterface::class => Profiler\Profiler::class, + ResultSet\ResultSetInterface::class => ResultSet\ResultSet::class, + ConnectionInterfaceFactoryFactoryInterface::class => Container\ConnectionInterfaceFactoryFactory::class, + DriverInterfaceFactoryFactoryInterface::class => Container\DriverInterfaceFactoryFactory::class, + PlatformInterfaceFactoryFactoryInterface::class => Container\PlatformInterfaceFactoryFactory::class, ], - 'factories' => [ + 'factories' => [ AdapterInterface::class => Container\AdapterFactory::class, Driver\Mysqli\Mysqli::class => Container\MysqliDriverFactory::class, Driver\Mysqli\Connection::class => Container\MysqliConnectionFactory::class, @@ -80,6 +90,14 @@ public function getAdapterManagerConfig(): array Profiler\Profiler::class => InvokableFactory::class, ResultSet\ResultSet::class => InvokableFactory::class, ], + 'invokables' => [ + Container\ConnectionInterfaceFactoryFactory::class + => Container\ConnectionInterfaceFactoryFactory::class, + Container\DriverInterfaceFactoryFactory::class + => Container\DriverInterfaceFactoryFactory::class, + Container\PlatformInterfaceFactoryFactory::class + => Container\PlatformInterfaceFactoryFactory::class, + ], ]; } } diff --git a/src/Container/AdapterManagerDelegator.php b/src/Container/AdapterManagerDelegator.php index 7ee69a7..c93cf39 100644 --- a/src/Container/AdapterManagerDelegator.php +++ b/src/Container/AdapterManagerDelegator.php @@ -5,7 +5,7 @@ namespace PhpDb\Adapter\Mysql\Container; use Laminas\ServiceManager\Factory\DelegatorFactoryInterface; -use PhpDB\Adapter\Mysql\ConfigProvider; +use PhpDb\Adapter\Mysql\ConfigProvider; use PhpDb\Container\AdapterManager; use Psr\Container\ContainerInterface; diff --git a/src/Container/ConnectionInterfaceFactoryFactory.php b/src/Container/ConnectionInterfaceFactoryFactory.php new file mode 100644 index 0000000..d5f0cdf --- /dev/null +++ b/src/Container/ConnectionInterfaceFactoryFactory.php @@ -0,0 +1,48 @@ +get('config')['db']['adapters'] ?? []; + if (! isset($adapterConfig[$requestedName]['driver'])) { + throw new RuntimeException(sprintf( + 'Named adapter "%s" is not configured with a driver', + $requestedName + )); + } + $adapterServices = $container->get('config')[AdapterManager::class]; + $configuredDriver = $adapterConfig[$requestedName]['driver']; + if (array_key_exists($configuredDriver, $adapterServices['aliases'])) { + $aliasTo = $adapterServices['aliases'][$configuredDriver]; + } else { + $aliasTo = $configuredDriver; + } + return match ($aliasTo) { + Mysqli::class => new MysqliConnectionFactory(), + Pdo::class => new PdoConnectionFactory(), + default => throw new RuntimeException(sprintf( + 'No connection factory found for driver "%s"', + $configuredDriver + )), + }; + } +} diff --git a/src/Container/DriverInterfaceFactoryFactory.php b/src/Container/DriverInterfaceFactoryFactory.php new file mode 100644 index 0000000..11190a1 --- /dev/null +++ b/src/Container/DriverInterfaceFactoryFactory.php @@ -0,0 +1,34 @@ +get('config')['db']['adapters'] ?? []; + if (! isset($adapterConfig[$requestedName]['driver'])) { + throw new RuntimeException(sprintf( + 'Named adapter "%s" is not configured with a driver', + $requestedName + )); + } + $adapterServices = $container->get('config')[AdapterManager::class]; + + $configuredDriver = $adapterConfig[$requestedName]['driver']; + $aliasTo ??= $adapterServices['aliases'][$configuredDriver] ?? $configuredDriver; + $driverFactory = $adapterServices['factories'][$aliasTo]; + return new $driverFactory(); + } +} diff --git a/src/Container/MysqliConnectionFactory.php b/src/Container/MysqliConnectionFactory.php index 8c084ce..01117eb 100644 --- a/src/Container/MysqliConnectionFactory.php +++ b/src/Container/MysqliConnectionFactory.php @@ -4,14 +4,18 @@ namespace PhpDb\Adapter\Mysql\Container; +use Laminas\ServiceManager\Factory\FactoryInterface; use PhpDb\Adapter\Driver\ConnectionInterface; use PhpDb\Adapter\Mysql\Driver\Mysqli\Connection; use Psr\Container\ContainerInterface; -final class MysqliConnectionFactory +final class MysqliConnectionFactory implements FactoryInterface { - public function __invoke(ContainerInterface $container): ConnectionInterface&Connection - { + public function __invoke( + ContainerInterface $container, + string $requestedName, + ?array $options = null + ): ConnectionInterface&Connection { /** @var array $config */ $config = $container->get('config'); @@ -23,4 +27,12 @@ public function __invoke(ContainerInterface $container): ConnectionInterface&Con return new Connection($connectionConfig); } + + public static function createFromConfig( + ContainerInterface $container, + string $requestedName + ): ConnectionInterface&Connection { + $adapterConfig = $container->get('config')['db']['adapters'][$requestedName] ?? []; + return new Connection($adapterConfig['connection'] ?? []); + } } diff --git a/src/Container/MysqliDriverFactory.php b/src/Container/MysqliDriverFactory.php index 310bd3a..4b87376 100644 --- a/src/Container/MysqliDriverFactory.php +++ b/src/Container/MysqliDriverFactory.php @@ -41,4 +41,28 @@ public function __invoke(ContainerInterface $container): Driver\DriverInterface& $options ); } + + public static function createFromConfig( + ContainerInterface $container, + string $requestedName, + ): Driver\DriverInterface&Mysqli\Mysqli { + /** @var AdapterManager $adapterManager */ + $adapterManager = $container->get(AdapterManager::class); + $connectionFactory = ( + $adapterManager->get(ConnectionInterfaceFactoryFactory::class) + )($container, $requestedName); + /** @var array $config */ + $config = $container->get('config'); + /** @var array $dbConfig */ + $dbConfig = $config['db'] ?? []; + /** @var array $adapterConfig */ + $adapterConfig = $dbConfig['adapters'][$requestedName] ?? []; + + return new Mysqli\Mysqli( + $connectionFactory::createFromConfig($container, $requestedName), + $adapterManager->get(Mysqli\Statement::class), + $adapterManager->get(Mysqli\Result::class), + $adapterConfig['options'] ?? [] + ); + } } diff --git a/src/Container/PdoConnectionFactory.php b/src/Container/PdoConnectionFactory.php index 5b07458..1370281 100644 --- a/src/Container/PdoConnectionFactory.php +++ b/src/Container/PdoConnectionFactory.php @@ -23,4 +23,12 @@ public function __invoke(ContainerInterface $container): ConnectionInterface&Con return new Connection($connectionConfig); } + + public static function createFromConfig( + ContainerInterface $container, + string $requestedName + ): ConnectionInterface&Connection { + $adapterConfig = $container->get('config')['db']['adapters'][$requestedName] ?? []; + return new Connection($adapterConfig['connection'] ?? []); + } } diff --git a/src/Container/PdoDriverFactory.php b/src/Container/PdoDriverFactory.php index 2d5420b..5e82d45 100644 --- a/src/Container/PdoDriverFactory.php +++ b/src/Container/PdoDriverFactory.php @@ -37,4 +37,39 @@ public function __invoke(ContainerInterface $container): PdoDriverInterface&PdoD $resultInstance ); } + + public static function createFromConfig( + ContainerInterface $container, + string $requestedName, + ): PdoDriverInterface&PdoDriver { + /** @var AdapterManager $adapterManager */ + $adapterManager = $container->get(AdapterManager::class); + $connectionFactory = ( + $adapterManager->get(ConnectionInterfaceFactoryFactory::class) + )($container, $requestedName); + /** @var array $config */ + $config = $container->get('config'); + /** @var array $dbConfig */ + $dbConfig = $config['db'] ?? []; + /** @var array $adapterConfig */ + $adapterConfig = $dbConfig['adapters'][$requestedName] ?? []; + /** @var array $options */ + $options = $adapterConfig['options'] ?? []; + + /** @var ConnectionInterface&Connection $connectionInstance */ + $connectionInstance = $connectionFactory::createFromConfig($container, $requestedName); + + /** @var StatementInterface&Statement $statementInstance */ + $statementInstance = $adapterManager->get(Statement::class); + + /** @var ResultInterface&Result $resultInstance */ + $resultInstance = $adapterManager->get(Result::class); + + return new PdoDriver( + $connectionInstance, + $statementInstance, + $resultInstance, + $options + ); + } } diff --git a/src/Container/PlatformInterfaceFactory.php b/src/Container/PlatformInterfaceFactory.php index fdac197..7edbefd 100644 --- a/src/Container/PlatformInterfaceFactory.php +++ b/src/Container/PlatformInterfaceFactory.php @@ -33,4 +33,9 @@ public function __invoke(ContainerInterface $container): PlatformInterface&Mysql return new Mysql($driverInstance); } + + public static function fromDriver(DriverInterface $driverInstance): PlatformInterface&Mysql + { + return new Mysql($driverInstance); + } } diff --git a/src/Container/PlatformInterfaceFactoryFactory.php b/src/Container/PlatformInterfaceFactoryFactory.php new file mode 100644 index 0000000..01b4a36 --- /dev/null +++ b/src/Container/PlatformInterfaceFactoryFactory.php @@ -0,0 +1,16 @@ +container); + $connection = $factory($this->container, Connection::class); self::assertInstanceOf(ConnectionInterface::class, $connection); self::assertInstanceOf(Connection::class, $connection); diff --git a/test/integration/Container/TestAsset/SetupTrait.php b/test/integration/Container/TestAsset/SetupTrait.php index 3b728b3..57fd919 100644 --- a/test/integration/Container/TestAsset/SetupTrait.php +++ b/test/integration/Container/TestAsset/SetupTrait.php @@ -11,8 +11,8 @@ use PhpDb\Adapter\Driver\DriverInterface; use PhpDb\Adapter\Mysql\ConfigProvider; use PhpDb\Adapter\Mysql\Driver\Pdo\Pdo; +use PhpDb\ConfigProvider as LaminasDbConfigProvider; use PhpDb\Container\AdapterManager; -use PhpDb\Container\ConfigProvider as LaminasDbConfigProvider; use Psr\Container\ContainerInterface; use function getenv;