Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public function getDependencies(): array
'aliases' => [
Adapter\AdapterInterface::class => Adapter\Adapter::class,
],
'factories' => [
Adapter\Adapter::class => Container\AdapterInterfaceFactory::class,
],
];
}
}
41 changes: 14 additions & 27 deletions src/Container/AbstractAdapterInterfaceFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -26,7 +27,7 @@
*
* @internal
*/
class AbstractAdapterInterfaceFactory implements AbstractFactoryInterface
final class AbstractAdapterInterfaceFactory implements AbstractFactoryInterface
{
protected ?array $config = null;

Expand All @@ -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
Expand All @@ -59,7 +60,7 @@ public function __invoke(
$requestedName,
?array $options = null
): AdapterInterface&Adapter {
/** @var string|null $driverClass */
/** @var class-string<DriverInterface>|class-string<PdoDriverInterface>|null $driverClass */
$driverClass = $this->config[$requestedName]['driver'] ?? null;

if ($driverClass === null) {
Expand All @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use function sprintf;

class AdapterServiceDelegator
class AdapterInterfaceDelegator
{
public function __construct(
protected readonly string $adapterName = AdapterInterface::class
Expand Down
77 changes: 77 additions & 0 deletions src/Container/AdapterInterfaceFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace PhpDb\Container;

use Laminas\ServiceManager\ServiceManager;
use PhpDb\Adapter\Adapter;
use PhpDb\Adapter\AdapterInterface;
use PhpDb\Adapter\Driver\DriverInterface;
use PhpDb\Adapter\Driver\PdoDriverInterface;
use PhpDb\Adapter\Platform\PlatformInterface;
use PhpDb\Adapter\Profiler\ProfilerInterface;
use PhpDb\Exception\ContainerException;
use PhpDb\ResultSet\ResultSet;
use PhpDb\ResultSet\ResultSetInterface;
use Psr\Container\ContainerInterface;

final class AdapterInterfaceFactory
{
public function __invoke(
ContainerInterface&ServiceManager $container,
string $requestedName,
): AdapterInterface&Adapter {
if (! $container->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<DriverInterface>|class-string<PdoDriverInterface>|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,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,7 +22,7 @@
use Psr\Container\NotFoundExceptionInterface;
use stdClass;

final class AdapterServiceDelegatorTest extends TestCase
final class AdapterInterfaceDelegatorTest extends TestCase
{
/**
* @throws Exception
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -134,7 +134,7 @@ public function testSetAdapterShouldNotBeCalledForWrongClassInstance(): void
'Delegated service "stdClass" must implement PhpDb\Adapter\AdapterAwareInterface'
);

(new AdapterServiceDelegator())(
(new AdapterInterfaceDelegator())(
$container,
stdClass::class,
$callback
Expand Down Expand Up @@ -163,7 +163,7 @@ public function testDelegatorWithServiceManager(): void
],
'delegators' => [
ConcreteAdapterAwareObject::class => [
AdapterServiceDelegator::class,
AdapterInterfaceDelegator::class,
],
],
]);
Expand Down Expand Up @@ -198,7 +198,7 @@ public function testDelegatorWithServiceManagerAndCustomAdapterName(): void
],
'delegators' => [
ConcreteAdapterAwareObject::class => [
new AdapterServiceDelegator('alternate-database-adapter'),
new AdapterInterfaceDelegator('alternate-database-adapter'),
],
],
]);
Expand Down Expand Up @@ -236,7 +236,7 @@ public function testDelegatorWithPluginManager(): void
],
'delegators' => [
ConcreteAdapterAwareObject::class => [
AdapterServiceDelegator::class,
AdapterInterfaceDelegator::class,
],
],
];
Expand Down
17 changes: 14 additions & 3 deletions test/unit/ConfigProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<class-string>, aliases: array<class-string, class-string>}} */
/**
* @phpstan-var array{
* 'dependencies': array{
* abstract_factories: list<class-string>,
* aliases: array<class-string, class-string>,
* factories: array<class-string, class-string>,
* }
* }
* */
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,
],
],
];

Expand Down