From 0eceb268b1a0a75f049564fbb64d0525e93abde5 Mon Sep 17 00:00:00 2001 From: Joey Smith Date: Thu, 8 Jan 2026 22:11:06 -0600 Subject: [PATCH] Delegates adapter creation back to php-db/phpdb Updates existing test Signed-off-by: Joey Smith Signed-off-by: Joey Smith --- src/ConfigProvider.php | 3 + .../AbstractAdapterInterfaceFactory.php | 41 ++++------ ...ator.php => AdapterInterfaceDelegator.php} | 2 +- src/Container/AdapterInterfaceFactory.php | 77 +++++++++++++++++++ ....php => AdapterInterfaceDelegatorTest.php} | 18 ++--- test/unit/ConfigProviderTest.php | 17 +++- 6 files changed, 118 insertions(+), 40 deletions(-) rename src/Container/{AdapterServiceDelegator.php => AdapterInterfaceDelegator.php} (98%) create mode 100644 src/Container/AdapterInterfaceFactory.php rename test/unit/Adapter/Container/{AdapterServiceDelegatorTest.php => AdapterInterfaceDelegatorTest.php} (94%) diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 50981c3c..1fde2b58 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -38,6 +38,9 @@ public function getDependencies(): array 'aliases' => [ Adapter\AdapterInterface::class => Adapter\Adapter::class, ], + 'factories' => [ + Adapter\Adapter::class => Container\AdapterInterfaceFactory::class, + ], ]; } } diff --git a/src/Container/AbstractAdapterInterfaceFactory.php b/src/Container/AbstractAdapterInterfaceFactory.php index 454f8e57..56ba2574 100644 --- a/src/Container/AbstractAdapterInterfaceFactory.php +++ b/src/Container/AbstractAdapterInterfaceFactory.php @@ -14,6 +14,7 @@ use PhpDb\Adapter\Profiler\ProfilerInterface; use PhpDb\ConfigProvider; use PhpDb\Exception\ContainerException; +use PhpDb\ResultSet\ResultSet; use PhpDb\ResultSet\ResultSetInterface; use Psr\Container\ContainerInterface; @@ -26,7 +27,7 @@ * * @internal */ -class AbstractAdapterInterfaceFactory implements AbstractFactoryInterface +final class AbstractAdapterInterfaceFactory implements AbstractFactoryInterface { protected ?array $config = null; @@ -49,7 +50,7 @@ public function canCreate(ContainerInterface $container, $requestedName): bool } /** - * Create a DB adapter + * Create a "Named" DB adapter * * @phpstan-param ContainerInterface&ServiceManager $container * @param string $requestedName @@ -59,7 +60,7 @@ public function __invoke( $requestedName, ?array $options = null ): AdapterInterface&Adapter { - /** @var string|null $driverClass */ + /** @var class-string|class-string|null $driverClass */ $driverClass = $this->config[$requestedName]['driver'] ?? null; if ($driverClass === null) { @@ -72,44 +73,30 @@ public function __invoke( /** @var DriverInterface|PdoDriverInterface $driver */ $driver = $container->build($driverClass, $this->config[$requestedName]); + /** @var PlatformInterface $platform */ $platform = $container->build(PlatformInterface::class, ['driver' => $driver]); + /** @var ResultSetInterface|null $resultSet */ $resultSet = $container->has(ResultSetInterface::class) ? $container->build(ResultSetInterface::class) - : null; + : new ResultSet(); + /** @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, - ), - }; + return new Adapter( + driver: $driver, + platform: $platform, + queryResultSetPrototype: $resultSet, + profiler: $profiler, + ); } /** * Get db configuration, if any - * todo: refactor to use PhpDb\ConfigProvider::NAMED_ADAPTER_KEY instead of hardcoding 'adapters' */ protected function getConfig(ContainerInterface $container): array { diff --git a/src/Container/AdapterServiceDelegator.php b/src/Container/AdapterInterfaceDelegator.php similarity index 98% rename from src/Container/AdapterServiceDelegator.php rename to src/Container/AdapterInterfaceDelegator.php index 0ef0d113..63a04cb8 100644 --- a/src/Container/AdapterServiceDelegator.php +++ b/src/Container/AdapterInterfaceDelegator.php @@ -14,7 +14,7 @@ use function sprintf; -class AdapterServiceDelegator +class AdapterInterfaceDelegator { public function __construct( protected readonly string $adapterName = AdapterInterface::class diff --git a/src/Container/AdapterInterfaceFactory.php b/src/Container/AdapterInterfaceFactory.php new file mode 100644 index 00000000..7e8921a1 --- /dev/null +++ b/src/Container/AdapterInterfaceFactory.php @@ -0,0 +1,77 @@ +has('config')) { + throw ContainerException::forService( + $requestedName, + self::class, + 'Container is missing a config service' + ); + } + $config = $container->get('config') ?? []; + $adapterConfig = $config[AdapterInterface::class] ?? $config[Adapter::class] ?? []; + + if ($adapterConfig === []) { + throw ContainerException::forService( + AdapterInterface::class, + self::class, + 'No configuration found for ' . $requestedName + ); + } + + /** @var class-string|class-string|null $driverClass */ + $driverClass = $adapterConfig['driver'] ?? null; + + if ($driverClass === null || ! $container->has($driverClass)) { + throw ContainerException::forService( + AdapterInterface::class, + self::class, + 'Invalid or missing driver provided for ' . $requestedName + ); + } + + /** @var DriverInterface|PdoDriverInterface $driver */ + $driver = $container->build($driverClass, $adapterConfig); + + /** @var PlatformInterface $adapterPlatform */ + $adapterPlatform = $container->build(PlatformInterface::class, ['driver' => $driver]); + + /** @var ProfilerInterface|null $profilerInterface */ + $profilerInterface = $container->has(ProfilerInterface::class) + ? $container->build(ProfilerInterface::class) + : null; + + /** @var ResultSetInterface|null $queryResultSetPrototype */ + $queryResultSetPrototype = $container->has(ResultSetInterface::class) + ? $container->get(ResultSetInterface::class) + : new ResultSet(); + + return new Adapter( + driver: $driver, + platform: $adapterPlatform, + queryResultSetPrototype: $queryResultSetPrototype, + profiler: $profilerInterface, + ); + } +} diff --git a/test/unit/Adapter/Container/AdapterServiceDelegatorTest.php b/test/unit/Adapter/Container/AdapterInterfaceDelegatorTest.php similarity index 94% rename from test/unit/Adapter/Container/AdapterServiceDelegatorTest.php rename to test/unit/Adapter/Container/AdapterInterfaceDelegatorTest.php index 9d062c93..e42c3ae2 100644 --- a/test/unit/Adapter/Container/AdapterServiceDelegatorTest.php +++ b/test/unit/Adapter/Container/AdapterInterfaceDelegatorTest.php @@ -11,7 +11,7 @@ use PhpDb\Adapter\AdapterInterface; use PhpDb\Adapter\Driver\DriverInterface; use PhpDb\Adapter\Platform\PlatformInterface; -use PhpDb\Container\AdapterServiceDelegator; +use PhpDb\Container\AdapterInterfaceDelegator; use PhpDb\Exception\RuntimeException; use PhpDb\ResultSet\ResultSetInterface; use PhpDbTest\Adapter\TestAsset\ConcreteAdapterAwareObject; @@ -22,7 +22,7 @@ use Psr\Container\NotFoundExceptionInterface; use stdClass; -final class AdapterServiceDelegatorTest extends TestCase +final class AdapterInterfaceDelegatorTest extends TestCase { /** * @throws Exception @@ -44,7 +44,7 @@ public function testSetAdapterShouldBeCalledForExistingAdapter(): void $callback = static fn(): ConcreteAdapterAwareObject => new ConcreteAdapterAwareObject(); /** @var ConcreteAdapterAwareObject $result */ - $result = (new AdapterServiceDelegator())( + $result = (new AdapterInterfaceDelegator())( $container, ConcreteAdapterAwareObject::class, $callback @@ -78,7 +78,7 @@ public function testSetAdapterShouldBeCalledForOnlyConcreteAdapter(): void $callback = static fn(): ConcreteAdapterAwareObject => new ConcreteAdapterAwareObject(); /** @var ConcreteAdapterAwareObject $result */ - $result = (new AdapterServiceDelegator())( + $result = (new AdapterInterfaceDelegator())( $container, ConcreteAdapterAwareObject::class, $callback @@ -110,7 +110,7 @@ public function testSetAdapterShouldNotBeCalledForMissingAdapter(): void $this->expectException(ServiceNotFoundException::class); $this->expectExceptionMessage('Service "PhpDb\Adapter\AdapterInterface" not found in container'); - (new AdapterServiceDelegator())( + (new AdapterInterfaceDelegator())( $container, ConcreteAdapterAwareObject::class, $callback @@ -134,7 +134,7 @@ public function testSetAdapterShouldNotBeCalledForWrongClassInstance(): void 'Delegated service "stdClass" must implement PhpDb\Adapter\AdapterAwareInterface' ); - (new AdapterServiceDelegator())( + (new AdapterInterfaceDelegator())( $container, stdClass::class, $callback @@ -163,7 +163,7 @@ public function testDelegatorWithServiceManager(): void ], 'delegators' => [ ConcreteAdapterAwareObject::class => [ - AdapterServiceDelegator::class, + AdapterInterfaceDelegator::class, ], ], ]); @@ -198,7 +198,7 @@ public function testDelegatorWithServiceManagerAndCustomAdapterName(): void ], 'delegators' => [ ConcreteAdapterAwareObject::class => [ - new AdapterServiceDelegator('alternate-database-adapter'), + new AdapterInterfaceDelegator('alternate-database-adapter'), ], ], ]); @@ -236,7 +236,7 @@ public function testDelegatorWithPluginManager(): void ], 'delegators' => [ ConcreteAdapterAwareObject::class => [ - AdapterServiceDelegator::class, + AdapterInterfaceDelegator::class, ], ], ]; diff --git a/test/unit/ConfigProviderTest.php b/test/unit/ConfigProviderTest.php index fa0fa179..0e9242f1 100644 --- a/test/unit/ConfigProviderTest.php +++ b/test/unit/ConfigProviderTest.php @@ -6,21 +6,32 @@ use PhpDb\Adapter; use PhpDb\ConfigProvider; -use PhpDb\Container\AbstractAdapterInterfaceFactory; +use PhpDb\Container; use PHPUnit\Framework\TestCase; class ConfigProviderTest extends TestCase { - /** @phpstan-var array{'dependencies': array{abstract_factories: list, aliases: array}} */ + /** + * @phpstan-var array{ + * 'dependencies': array{ + * abstract_factories: list, + * aliases: array, + * factories: array, + * } + * } + * */ private array $config = [ Adapter\AdapterInterface::class => [], 'dependencies' => [ 'abstract_factories' => [ - AbstractAdapterInterfaceFactory::class, + Container\AbstractAdapterInterfaceFactory::class, ], 'aliases' => [ Adapter\AdapterInterface::class => Adapter\Adapter::class, ], + 'factories' => [ + Adapter\Adapter::class => Container\AdapterInterfaceFactory::class, + ], ], ];