From cf6df7313f75278fd411788f9f0104138b0a364d Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 29 Aug 2024 04:54:35 +0200 Subject: [PATCH] added Factory::createFromParameters() & createFromDsn() [WIP] merging Connection & Explorer classes into one (BC break) [WIP] --- src/Bridges/DatabaseDI/DatabaseExtension.php | 9 ++- src/Database/Explorer.php | 6 +- src/Database/Factory.php | 71 ++++++++++++++++---- tests/Database/connection.option.lazy.phpt | 9 +++ 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/Bridges/DatabaseDI/DatabaseExtension.php b/src/Bridges/DatabaseDI/DatabaseExtension.php index 779df049c..ba41c4cb1 100644 --- a/src/Bridges/DatabaseDI/DatabaseExtension.php +++ b/src/Bridges/DatabaseDI/DatabaseExtension.php @@ -93,11 +93,18 @@ private function setupDatabase(\stdClass $config, string $name): void $cacheId = 'Nette.Database.' . hash('xxh128', $name . $config->dsn); $cache = new Statement(Nette\Caching\Cache::class, [1 => $cacheId]); + $lazy = $config->options['lazy'] ?? null; + unset($config->options['lazy']); + $explorer = $builder->addDefinition($this->prefix($name)) - ->setFactory(Nette\Database\Explorer::class, [$config->dsn, $config->user, $config->password, $config->options]) + ->setFactory([Nette\Database\Factory::class, 'createFromDsn'], [$config->dsn, $config->user, $config->password, $config->options]) ->addSetup('setCache', [$cache]) ->setAutowired($config->autowired); + if ($lazy === false) { + $explorer->addSetup('connect'); + } + if (!$config->conventions || $config->conventions === 'discovered') { } elseif (is_string($config->conventions)) { diff --git a/src/Database/Explorer.php b/src/Database/Explorer.php index 6cf59d4ff..0d9e1bcf6 100644 --- a/src/Database/Explorer.php +++ b/src/Database/Explorer.php @@ -46,8 +46,10 @@ public function __construct( $lazy = $options['lazy'] ?? false; unset($options['lazy']); - Factory::configure($this, $options); - $this->driver = Factory::createDriverFromDsn($dsn, $user, $password, $options); + $explorer = Factory::createFromDsn($dsn, $user, $password, $options); + $this->driver = $explorer->driver; + $this->typeConverter = $explorer->typeConverter; + if (!$lazy) { $this->connect(); } diff --git a/src/Database/Factory.php b/src/Database/Factory.php index 520e60453..4f55dbfde 100644 --- a/src/Database/Factory.php +++ b/src/Database/Factory.php @@ -28,41 +28,88 @@ final class Factory private const TypeConverterOptions = ['convertBoolean', 'convertDateTime', 'convertDecimal', 'newDateTime']; - /** @internal */ - public static function createDriverFromDsn( + public static function createFromParameters( + #[\SensitiveParameter] + ...$params, + ): Explorer + { + $params = count($params) === 1 && is_array($params[0] ?? null) ? $params[0] : $params; + $driver = self::createDriverFromParameters($params); + return self::createExplorer($driver, $params); + } + + + public static function createFromDsn( string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, array $options = [], + ): Explorer + { + $driver = self::createDriverFromDsn($dsn, $username, $password, $options); + return self::createExplorer($driver, $options); + } + + + private static function createDriverFromParameters( + #[\SensitiveParameter] + array $params, ): Drivers\Driver { if ($class = $params['driverClass'] ?? null) { if (!is_subclass_of($class, Drivers\Driver::class)) { throw new \LogicException("Driver class '$class' is not subclass of " . Drivers\Driver::class); } + unset($params['driverClass']); - } else { - $driver = explode(':', $dsn)[0]; - $class = self::Drivers['pdo-' . $driver] ?? null; + } elseif ($driver = $params['driver'] ?? null) { + $class = self::Drivers[$driver] ?? null; if (!$class) { - throw new \LogicException("Unknown PDO driver '$driver'."); + throw new \LogicException("Unknown driver '$driver'."); } + unset($params['driver']); + + } elseif ($params['dsn'] ?? null) { + return self::createDriverFromDsn(...$params); + + } else { + throw new \LogicException("Missing options 'driver' or 'driverClass'."); } + $params = array_diff_key($params, array_flip(self::TypeConverterOptions)); + return new $class($params); + } + + + private static function createDriverFromDsn( + string $dsn, + ?string $username, + #[\SensitiveParameter] + ?string $password, + array $options = [], + ): Drivers\Driver + { + $options = array_diff_key($options, array_flip(self::TypeConverterOptions)); + $driver = explode(':', $dsn)[0]; + $class = self::Drivers['pdo-' . $driver] ?? null; + if (!$class) { + throw new \LogicException("Unknown PDO driver '$driver'."); + } return new $class(['dsn' => $dsn, 'username' => $username, 'password' => $password, 'options' => $options]); } - /** @internal */ - public static function configure(Explorer $explorer, array $options): void + private static function createExplorer(Drivers\Driver $driver, array $options): Explorer { + $explorer = new Explorer($driver); $converter = $explorer->getTypeConverter(); - foreach (self::TypeConverterOptions as $opt) { - if (isset($options[$opt])) { - $converter->$opt = (bool) $options[$opt]; - unset($options[$opt]); + foreach (self::TypeConverterOptions as $key) { + if (isset($options[$key])) { + $converter->$key = (bool) $options[$key]; + unset($options[$key]); } } + return $explorer; } } diff --git a/tests/Database/connection.option.lazy.phpt b/tests/Database/connection.option.lazy.phpt index b8ee1a5dc..675268e6c 100644 --- a/tests/Database/connection.option.lazy.phpt +++ b/tests/Database/connection.option.lazy.phpt @@ -30,6 +30,15 @@ test('lazy', function () { }); +test('lazy factory', function () { + $connection = Nette\Database\Factory::createFromDsn('mysql:', 'user', 'password'); + Assert::exception( + fn() => $connection->quote('x'), + Nette\Database\DriverException::class, + ); +}); + + test('connect & disconnect', function () { $options = Tester\Environment::loadData() + ['username' => null, 'password' => null]; $connections = 1;