diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b49db229..08f3dcf5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ - New #899: Add `ColumnSchemaInterface::hasDefaultValue()` and `ColumnSchemaInterface::null()` methods (@Tigrov) - New #902: Add `QueryBuilderInterface::prepareParam()` and `QueryBuilderInterface::prepareValue()` methods (@Tigrov) - Enh #902: Refactor `Quoter::quoteValue()` method (@Tigrov) +- New #906: Add `ServerInfoInterface` and its implementation (@Tigrov) ## 1.3.0 March 21, 2024 diff --git a/UPGRADE.md b/UPGRADE.md index c03633004..019c57575 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -110,6 +110,8 @@ Each table column has its own class in the `Yiisoft\Db\Schema\Column` namespace - `QueryBuilderInterface::buildColumnDefinition()` - builds column definition for `CREATE TABLE` statement; - `QueryBuilderInterface::prepareParam()` - converts a `ParamInterface` object to its SQL representation; - `QueryBuilderInterface::prepareValue()` - converts a value to its SQL representation; +- `QueryBuilderInterface::getServerInfo()` - returns `ServerInfoInterface` instance which provides server information; +- `ConnectionInterface::getServerInfo()` - returns `ServerInfoInterface` instance which provides server information; ### Remove methods @@ -123,6 +125,7 @@ Each table column has its own class in the `Yiisoft\Db\Schema\Column` namespace - `Quoter::unquoteParts()` - `AbstractPdoCommand::logQuery()` - `ColumnSchemaInterface::phpType()` +- `ConnectionInterface::getServerVersion()` ### Remove deprecated parameters diff --git a/src/Connection/ConnectionInterface.php b/src/Connection/ConnectionInterface.php index a8aad3d1c..95ad92e92 100644 --- a/src/Connection/ConnectionInterface.php +++ b/src/Connection/ConnectionInterface.php @@ -128,14 +128,9 @@ public function getQuoter(): QuoterInterface; public function getSchema(): SchemaInterface; /** - * Returns a server version as a string comparable by {@see \version_compare()}. - * - * @throws Exception - * @throws InvalidConfigException - * - * @return string The server version as a string. + * Returns {@see ServerInfoInterface} instance that provides information about the database server. */ - public function getServerVersion(): string; + public function getServerInfo(): ServerInfoInterface; /** * Return table prefix for current DB connection. diff --git a/src/Connection/ServerInfoInterface.php b/src/Connection/ServerInfoInterface.php new file mode 100644 index 000000000..d24c54a1b --- /dev/null +++ b/src/Connection/ServerInfoInterface.php @@ -0,0 +1,16 @@ +connection->getSchema(); } - public function getServerVersion(): string + public function getServerInfo(): ServerInfoInterface { - return $this->connection->getServerVersion(); + return $this->connection->getServerInfo(); } public function getTablePrefix(): string diff --git a/src/Driver/Pdo/AbstractPdoConnection.php b/src/Driver/Pdo/AbstractPdoConnection.php index f6895545d..3a74f90e6 100644 --- a/src/Driver/Pdo/AbstractPdoConnection.php +++ b/src/Driver/Pdo/AbstractPdoConnection.php @@ -12,6 +12,7 @@ use Throwable; use Yiisoft\Db\Cache\SchemaCache; use Yiisoft\Db\Connection\AbstractConnection; +use Yiisoft\Db\Connection\ServerInfoInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidCallException; use Yiisoft\Db\Exception\InvalidConfigException; @@ -43,7 +44,7 @@ abstract class AbstractPdoConnection extends AbstractConnection implements PdoCo use ProfilerAwareTrait; protected PDO|null $pdo = null; - protected string $serverVersion = ''; + protected ServerInfoInterface|null $serverInfo = null; protected bool|null $emulatePrepare = null; protected QueryBuilderInterface|null $queryBuilder = null; protected QuoterInterface|null $quoter = null; @@ -169,15 +170,9 @@ public function getDriverName(): string return $this->driver->getDriverName(); } - public function getServerVersion(): string + public function getServerInfo(): ServerInfoInterface { - if ($this->serverVersion === '') { - /** @psalm-var mixed $version */ - $version = $this->getActivePDO()->getAttribute(PDO::ATTR_SERVER_VERSION); - $this->serverVersion = is_string($version) ? $version : 'Version could not be determined.'; - } - - return $this->serverVersion; + return $this->serverInfo ??= new PdoServerInfo($this); } public function isActive(): bool diff --git a/src/Driver/Pdo/PdoServerInfo.php b/src/Driver/Pdo/PdoServerInfo.php new file mode 100644 index 000000000..bdfaf8651 --- /dev/null +++ b/src/Driver/Pdo/PdoServerInfo.php @@ -0,0 +1,27 @@ +version === null) { + /** @var string */ + $this->version = $this->db->getActivePDO()?->getAttribute(PDO::ATTR_SERVER_VERSION) ?? ''; + } + + return $this->version; + } +} diff --git a/src/QueryBuilder/AbstractQueryBuilder.php b/src/QueryBuilder/AbstractQueryBuilder.php index 2dc0c5df5..603611611 100644 --- a/src/QueryBuilder/AbstractQueryBuilder.php +++ b/src/QueryBuilder/AbstractQueryBuilder.php @@ -8,6 +8,7 @@ use Yiisoft\Db\Command\DataType; use Yiisoft\Db\Command\ParamInterface; use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Db\Connection\ServerInfoInterface; use Yiisoft\Db\Constant\GettypeResult; use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Expression\Expression; @@ -67,6 +68,7 @@ abstract class AbstractQueryBuilder implements QueryBuilderInterface public function __construct( private QuoterInterface $quoter, private SchemaInterface $schema, + private ServerInfoInterface $serverInfo, private AbstractDDLQueryBuilder $ddlBuilder, private AbstractDMLQueryBuilder $dmlBuilder, private AbstractDQLQueryBuilder $dqlBuilder, @@ -386,6 +388,11 @@ public function getExpressionBuilder(ExpressionInterface $expression): object return $this->dqlBuilder->getExpressionBuilder($expression); } + public function getServerInfo(): ServerInfoInterface + { + return $this->serverInfo; + } + public function insert(string $table, QueryInterface|array $columns, array &$params = []): string { return $this->dmlBuilder->insert($table, $columns, $params); diff --git a/src/QueryBuilder/QueryBuilderInterface.php b/src/QueryBuilder/QueryBuilderInterface.php index c182a58bc..d85609e9a 100644 --- a/src/QueryBuilder/QueryBuilderInterface.php +++ b/src/QueryBuilder/QueryBuilderInterface.php @@ -6,6 +6,7 @@ use Yiisoft\Db\Command\ParamInterface; use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Db\Connection\ServerInfoInterface; use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Expression\ExpressionBuilderInterface; use Yiisoft\Db\Expression\ExpressionInterface; @@ -109,6 +110,11 @@ public function getColumnType(ColumnInterface|string $type): string; */ public function getExpressionBuilder(ExpressionInterface $expression): object; + /** + * Returns {@see ServerInfoInterface} instance that provides information about the database server. + */ + public function getServerInfo(): ServerInfoInterface; + /** * @return QuoterInterface The quoter instance. */ diff --git a/tests/AbstractPdoConnectionTest.php b/tests/AbstractPdoConnectionTest.php index 4576b6178..5dc21f364 100644 --- a/tests/AbstractPdoConnectionTest.php +++ b/tests/AbstractPdoConnectionTest.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Yiisoft\Db\Driver\Pdo\PdoDriverInterface; +use Yiisoft\Db\Driver\Pdo\PdoServerInfo; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Tests\Support\TestTrait; @@ -35,11 +36,11 @@ public function testGetDriver(): void $this->assertInstanceOf(PdoDriverInterface::class, $driver); } - public function testGetServerVersion(): void + public function testGetServerInfo(): void { $db = $this->getConnection(); - $this->assertIsString($db->getServerVersion()); + $this->assertInstanceOf(PdoServerInfo::class, $db->getServerInfo()); } /** diff --git a/tests/Common/CommonColumnSchemaBuilderTest.php b/tests/Common/CommonColumnSchemaBuilderTest.php index 29daa8acd..a579d9d48 100644 --- a/tests/Common/CommonColumnSchemaBuilderTest.php +++ b/tests/Common/CommonColumnSchemaBuilderTest.php @@ -100,7 +100,7 @@ protected function checkCreateColumn(string $expected, string $type, int|null $l $db = $this->getConnection(); if (str_contains($expected, 'UUID_TO_BIN')) { - $serverVersion = $db->getServerVersion(); + $serverVersion = $db->getServerInfo()->getVersion(); if (str_contains($serverVersion, 'MariaDB')) { $db->close(); $this->markTestSkipped('UUID_TO_BIN not supported MariaDB as defaultValue'); diff --git a/tests/Common/CommonPdoConnectionTest.php b/tests/Common/CommonPdoConnectionTest.php index 88b101987..761ba9c36 100644 --- a/tests/Common/CommonPdoConnectionTest.php +++ b/tests/Common/CommonPdoConnectionTest.php @@ -316,7 +316,7 @@ public function testTransactionRollbackTransactionOnLevel(): void 'getQueryBuilder', 'getQuoter', 'getSchema', - 'getServerVersion', + 'getServerInfo', 'isActive', 'open', 'quoteValue', diff --git a/tests/Db/Driver/PDO/PdoServerInfoTest.php b/tests/Db/Driver/PDO/PdoServerInfoTest.php new file mode 100644 index 000000000..df12df06d --- /dev/null +++ b/tests/Db/Driver/PDO/PdoServerInfoTest.php @@ -0,0 +1,21 @@ +getConnection(); + $serverInfo = $db->getServerInfo(); + + $this->assertIsString($serverInfo->getVersion()); + } +} diff --git a/tests/Db/QueryBuilder/QueryBuilderTest.php b/tests/Db/QueryBuilder/QueryBuilderTest.php index b48122be0..d3b2043d6 100644 --- a/tests/Db/QueryBuilder/QueryBuilderTest.php +++ b/tests/Db/QueryBuilder/QueryBuilderTest.php @@ -5,6 +5,7 @@ namespace Yiisoft\Db\Tests\Db\QueryBuilder; use JsonException; +use Yiisoft\Db\Connection\ServerInfoInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; @@ -62,7 +63,7 @@ public function testBatchInsert( $db = $this->getConnection(); $schemaMock = $this->createMock(Schema::class); - $qb = new QueryBuilder($db->getQuoter(), $schemaMock); + $qb = new QueryBuilder($db->getQuoter(), $schemaMock, $db->getServerInfo()); $params = []; try { @@ -147,7 +148,7 @@ public function testCreateView(): void $schemaMock = $this->createMock(Schema::class); $subQuery = (new Query($db))->select('{{bar}}')->from('{{testCreateViewTable}}')->where(['>', 'bar', '5']); - $qb = new QueryBuilder($db->getQuoter(), $schemaMock); + $qb = new QueryBuilder($db->getQuoter(), $schemaMock, $db->getServerInfo()); $this->assertSame( <<getConnection(); $schemaMock = $this->createMock(Schema::class); - $qb = new QueryBuilder($db->getQuoter(), $schemaMock); + $qb = new QueryBuilder($db->getQuoter(), $schemaMock, $db->getServerInfo()); $this->assertSame($expectedSQL, $qb->insert($table, $columns, $params)); $this->assertSame($expectedParams, $params); @@ -265,7 +266,7 @@ public function testUpdate( $db = $this->getConnection(); $schemaMock = $this->createMock(Schema::class); - $qb = new QueryBuilder($db->getQuoter(), $schemaMock); + $qb = new QueryBuilder($db->getQuoter(), $schemaMock, $db->getServerInfo()); $sql = $qb->update($table, $columns, $condition, $params); $sql = $qb->quoter()->quoteSql($sql); @@ -341,4 +342,12 @@ public function testPrepareValueNonStreamResource(): void $qb->prepareValue(stream_context_create()); } + + public function testGetServerInfo(): void + { + $db = $this->getConnection(); + $qb = $db->getQueryBuilder(); + + $this->assertInstanceOf(ServerInfoInterface::class, $qb->getServerInfo()); + } } diff --git a/tests/Support/Stub/Connection.php b/tests/Support/Stub/Connection.php index 8b0cee145..e5b193070 100644 --- a/tests/Support/Stub/Connection.php +++ b/tests/Support/Stub/Connection.php @@ -48,6 +48,7 @@ public function getQueryBuilder(): QueryBuilderInterface $this->queryBuilder = new QueryBuilder( $this->getQuoter(), $this->getSchema(), + $this->getServerInfo(), ); } diff --git a/tests/Support/Stub/QueryBuilder.php b/tests/Support/Stub/QueryBuilder.php index ad93dd8ce..c23eb957b 100644 --- a/tests/Support/Stub/QueryBuilder.php +++ b/tests/Support/Stub/QueryBuilder.php @@ -4,19 +4,23 @@ namespace Yiisoft\Db\Tests\Support\Stub; +use Yiisoft\Db\Connection\ServerInfoInterface; use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder; use Yiisoft\Db\Schema\QuoterInterface; use Yiisoft\Db\Schema\SchemaInterface; final class QueryBuilder extends AbstractQueryBuilder { - public function __construct(QuoterInterface $quoter, SchemaInterface $schema) + public function __construct(QuoterInterface $quoter, SchemaInterface $schema, ServerInfoInterface $serverInfo) { - $ddlBuilder = new DDLQueryBuilder($this, $quoter, $schema); - $dmlBuilder = new DMLQueryBuilder($this, $quoter, $schema); - $dqlBuilder = new DQLQueryBuilder($this, $quoter); - $columnDefinitionBuilder = new ColumnDefinitionBuilder($this); - - parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder, $columnDefinitionBuilder); + parent::__construct( + $quoter, + $schema, + $serverInfo, + new DDLQueryBuilder($this, $quoter, $schema), + new DMLQueryBuilder($this, $quoter, $schema), + new DQLQueryBuilder($this, $quoter), + new ColumnDefinitionBuilder($this), + ); } }