Unverified Commit 0dd84bf6 authored by Sergei Morozov's avatar Sergei Morozov

Merge branch '3.0.x' into master

parents 74419019 66c17e24
......@@ -132,6 +132,9 @@ jobs:
- stage: Test
php: 7.4
env: DB=mysqli.docker IMAGE=mysql:8.0
- stage: Test
php: 7.4
env: DB=mysqli-tls.docker IMAGE=mysql:8.0 TLS=yes
- stage: Test
php: 7.4
env: DB=mariadb.docker IMAGE=mariadb:10.3
......
......@@ -254,6 +254,10 @@ The Doctrine\DBAL\Version class is no longer available: please refrain from chec
# Upgrade to 3.0
## BC BREAK: removed `Synchronizer` package
The `Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer` interface and all its implementations have been removed.
## BC BREAK: removed wrapper `Connection` methods
The following methods of the `Connection` class have been removed:
......@@ -597,6 +601,10 @@ Please use other database client applications for import, e.g.:
# Upgrade to 2.11
## Deprecated `Synchronizer` package
The `Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer` interface and all its implementations are deprecated.
## Deprecated usage of wrapper-level components as implementations of driver-level interfaces
The usage of the wrapper `Connection` and `Statement` classes as implementations of the `Driver\Connection` and `Driver\Statement` interfaces is deprecated.
......
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -40,3 +40,11 @@ while true; do
;;
esac
done
if [[ "$TLS" == "yes" ]]
then
for file in "ca.pem" "client-cert.pem" "client-key.pem"
do
docker cp "rdbms:/var/lib/mysql/$file" .
done
fi
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/schema/9.3.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
>
<php>
<var name="db_driver" value="mysqli"/>
<var name="db_host" value="127.0.0.1"/>
<var name="db_port" value="33306"/>
<var name="db_ssl_ca" value="ca.pem"/>
<var name="db_ssl_cert" value="client-cert.pem"/>
<var name="db_ssl_key" value="client-key.pem"/>
<!-- Use MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT since there's no way to generate a certificate
with a proper common name (CN) on Travis. This flag must be not used in production settings. -->
<var name="db_driver_option_flags" value="64"/>
<var name="db_user" value="root"/>
<var name="db_dbname" value="doctrine_tests"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../tests</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">../../src</directory>
</include>
</coverage>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -27,11 +27,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -22,11 +22,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -28,11 +28,4 @@
<directory suffix=".php">../../src</directory>
</include>
</coverage>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
......@@ -8,24 +8,24 @@
"packages": [
{
"name": "composer/package-versions-deprecated",
"version": "1.8.1",
"version": "1.10.99.1",
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
"reference": "b9805885293f3957ee0dd42616ac6915c4ac9a4b"
"reference": "68c9b502036e820c33445ff4d174327f6bb87486"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b9805885293f3957ee0dd42616ac6915c4ac9a4b",
"reference": "b9805885293f3957ee0dd42616ac6915c4ac9a4b",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/68c9b502036e820c33445ff4d174327f6bb87486",
"reference": "68c9b502036e820c33445ff4d174327f6bb87486",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1.0 || ^2.0",
"php": "^7"
"php": "^7 || ^8"
},
"replace": {
"ocramius/package-versions": "1.8.99"
"ocramius/package-versions": "1.10.99"
},
"require-dev": {
"composer/composer": "^1.9.3 || ^2.0@dev",
......@@ -59,6 +59,10 @@
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"support": {
"issues": "https://github.com/composer/package-versions-deprecated/issues",
"source": "https://github.com/composer/package-versions-deprecated/tree/1.10.99.1"
},
"funding": [
{
"url": "https://packagist.com",
......@@ -73,7 +77,7 @@
"type": "tidelift"
}
],
"time": "2020-06-19T07:59:31+00:00"
"time": "2020-08-13T12:55:41+00:00"
},
{
"name": "doctrine/cache",
......
......@@ -50,7 +50,7 @@ constants:
The default transaction isolation level of a
``Doctrine\DBAL\Connection`` is chosen by the underlying platform
but it is always at least READ\_COMMITTED.
but it is always at least ``READ_COMMITTED``.
Transaction Nesting
-------------------
......
......@@ -19,7 +19,7 @@ final class Driver extends AbstractDB2Driver
isset($params['persistent']) && $params['persistent'] === true,
$params['user'] ?? '',
$params['password'] ?? '',
$params['driver_options'] ?? []
$params['driverOptions'] ?? []
);
}
}
......@@ -36,8 +36,8 @@ final class Driver extends AbstractMySQLDriver
$preInitializers = $postInitializers = [];
if (isset($params['driver_options'])) {
$driverOptions = $params['driver_options'];
if (isset($params['driverOptions'])) {
$driverOptions = $params['driverOptions'];
if (isset($driverOptions[Connection::OPTION_FLAGS])) {
$flags = $driverOptions[Connection::OPTION_FLAGS];
......@@ -94,11 +94,11 @@ final class Driver extends AbstractMySQLDriver
isset($params['ssl_cipher'])
) {
$initializers[] = new Secure(
$params['ssl_key'] ?? null,
$params['ssl_cert'] ?? null,
$params['ssl_ca'] ?? null,
$params['ssl_capath'] ?? null,
$params['ssl_cipher'] ?? null
$params['ssl_key'] ?? '',
$params['ssl_cert'] ?? '',
$params['ssl_ca'] ?? '',
$params['ssl_capath'] ?? '',
$params['ssl_cipher'] ?? ''
);
}
......
......@@ -9,22 +9,22 @@ use mysqli;
final class Secure implements Initializer
{
/** @var string|null */
/** @var string */
private $key;
/** @var string|null */
/** @var string */
private $cert;
/** @var string|null */
/** @var string */
private $ca;
/** @var string|null */
/** @var string */
private $capath;
/** @var string|null */
/** @var string */
private $cipher;
public function __construct(?string $key, ?string $cert, ?string $ca, ?string $capath, ?string $cipher)
public function __construct(string $key, string $cert, string $ca, string $capath, string $cipher)
{
$this->key = $key;
$this->cert = $cert;
......
......@@ -16,7 +16,7 @@ final class Driver extends AbstractMySQLDriver
*/
public function connect(array $params): ConnectionInterface
{
$driverOptions = $params['driver_options'] ?? [];
$driverOptions = $params['driverOptions'] ?? [];
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
......
......@@ -16,7 +16,7 @@ final class Driver extends AbstractOracleDriver
*/
public function connect(array $params): ConnectionInterface
{
$driverOptions = $params['driver_options'] ?? [];
$driverOptions = $params['driverOptions'] ?? [];
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
......
......@@ -18,7 +18,7 @@ final class Driver extends AbstractPostgreSQLDriver
*/
public function connect(array $params): ConnectionInterface
{
$driverOptions = $params['driver_options'] ?? [];
$driverOptions = $params['driverOptions'] ?? [];
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
......
......@@ -25,8 +25,8 @@ final class Driver extends AbstractSQLServerDriver
{
$pdoOptions = $dsnOptions = [];
if (isset($params['driver_options'])) {
foreach ($params['driver_options'] as $option => $value) {
if (isset($params['driverOptions'])) {
foreach ($params['driverOptions'] as $option => $value) {
if (is_int($option)) {
$pdoOptions[$option] = $value;
} else {
......
......@@ -25,7 +25,7 @@ final class Driver extends AbstractSQLiteDriver
*/
public function connect(array $params): ConnectionInterface
{
$driverOptions = $params['driver_options'] ?? [];
$driverOptions = $params['driverOptions'] ?? [];
if (isset($driverOptions['userDefinedFunctions'])) {
$this->userDefinedFunctions = array_merge(
......
......@@ -30,7 +30,7 @@ final class Driver extends AbstractSQLServerDriver
throw PortWithoutHost::new();
}
$driverOptions = $params['driver_options'] ?? [];
$driverOptions = $params['driverOptions'] ?? [];
if (isset($params['dbname'])) {
$driverOptions['Database'] = $params['dbname'];
......
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Schema\Synchronizer;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Throwable;
/**
* Abstract schema synchronizer with methods for executing batches of SQL.
*/
abstract class AbstractSchemaSynchronizer implements SchemaSynchronizer
{
/** @var Connection */
protected $conn;
public function __construct(Connection $conn)
{
$this->conn = $conn;
}
/**
* @param array<int, string> $sql
*/
protected function processSqlSafely(array $sql): void
{
foreach ($sql as $s) {
try {
$this->conn->executeStatement($s);
} catch (Throwable $e) {
}
}
}
/**
* @param array<int, string> $sql
*
* @throws DBALException
*/
protected function processSql(array $sql): void
{
foreach ($sql as $s) {
$this->conn->executeStatement($s);
}
}
}
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Schema\Synchronizer;
use Doctrine\DBAL\Schema\Schema;
/**
* The synchronizer knows how to synchronize a schema with the configured
* database.
*/
interface SchemaSynchronizer
{
/**
* Gets the SQL statements that can be executed to create the schema.
*
* @return array<int, string>
*/
public function getCreateSchema(Schema $createSchema): array;
/**
* Gets the SQL Statements to update given schema with the underlying db.
*
* @return array<int, string>
*/
public function getUpdateSchema(Schema $toSchema, bool $noDrops = false): array;
/**
* Gets the SQL Statements to drop the given schema from underlying db.
*
* @return string[]
*/
public function getDropSchema(Schema $dropSchema): array;
/**
* Gets the SQL statements to drop all schema assets from underlying db.
*
* @return array<int, string>
*/
public function getDropAllSchema(): array;
/**
* Creates the Schema.
*/
public function createSchema(Schema $createSchema): void;
/**
* Updates the Schema to new schema version.
*/
public function updateSchema(Schema $toSchema, bool $noDrops = false): void;
/**
* Drops the given database schema from the underlying db.
*/
public function dropSchema(Schema $dropSchema): void;
/**
* Drops all assets from the underlying db.
*/
public function dropAllSchema(): void;
}
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Schema\Synchronizer;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
use function count;
/**
* Schema Synchronizer for Default DBAL Connection.
*/
final class SingleDatabaseSynchronizer extends AbstractSchemaSynchronizer
{
/** @var AbstractPlatform */
private $platform;
public function __construct(Connection $conn)
{
parent::__construct($conn);
$this->platform = $conn->getDatabasePlatform();
}
/**
* {@inheritdoc}
*/
public function getCreateSchema(Schema $createSchema): array
{
return $createSchema->toSql($this->platform);
}
/**
* {@inheritdoc}
*/
public function getUpdateSchema(Schema $toSchema, bool $noDrops = false): array
{
$comparator = new Comparator();
$sm = $this->conn->getSchemaManager();
$fromSchema = $sm->createSchema();
$schemaDiff = $comparator->compare($fromSchema, $toSchema);
if ($noDrops) {
return $schemaDiff->toSaveSql($this->platform);
}
return $schemaDiff->toSql($this->platform);
}
/**
* {@inheritdoc}
*/
public function getDropSchema(Schema $dropSchema): array
{
$visitor = new DropSchemaSqlCollector($this->platform);
$sm = $this->conn->getSchemaManager();
$fullSchema = $sm->createSchema();
foreach ($fullSchema->getTables() as $table) {
if ($dropSchema->hasTable($table->getName())) {
$visitor->acceptTable($table);
}
foreach ($table->getForeignKeys() as $foreignKey) {
if (! $dropSchema->hasTable($table->getName())) {
continue;
}
if (! $dropSchema->hasTable($foreignKey->getForeignTableName())) {
continue;
}
$visitor->acceptForeignKey($table, $foreignKey);
}
}
if (! $this->platform->supportsSequences()) {
return $visitor->getQueries();
}
foreach ($dropSchema->getSequences() as $sequence) {
$visitor->acceptSequence($sequence);
}
foreach ($dropSchema->getTables() as $table) {
$primaryKey = $table->getPrimaryKey();
if ($primaryKey === null) {
continue;
}
$columns = $primaryKey->getColumns();
if (count($columns) > 1) {
continue;
}
$checkSequence = $table->getName() . '_' . $columns[0] . '_seq';
if (! $fullSchema->hasSequence($checkSequence)) {
continue;
}
$visitor->acceptSequence($fullSchema->getSequence($checkSequence));
}
return $visitor->getQueries();
}
/**
* {@inheritdoc}
*/
public function getDropAllSchema(): array
{
$sm = $this->conn->getSchemaManager();
$visitor = new DropSchemaSqlCollector($this->platform);
$schema = $sm->createSchema();
$schema->visit($visitor);
return $visitor->getQueries();
}
public function createSchema(Schema $createSchema): void
{
$this->processSql($this->getCreateSchema($createSchema));
}
public function updateSchema(Schema $toSchema, bool $noDrops = false): void
{
$this->processSql($this->getUpdateSchema($toSchema, $noDrops));
}
public function dropSchema(Schema $dropSchema): void
{
$this->processSqlSafely($this->getDropSchema($dropSchema));
}
public function dropAllSchema(): void
{
$this->processSql($this->getDropAllSchema());
}
}
......@@ -73,7 +73,7 @@ class DriverTest extends AbstractPostgreSQLDriverTest
return $this->createDriver()->connect(
array_merge(
TestUtil::getConnectionParams(),
['driver_options' => $driverOptions]
['driverOptions' => $driverOptions]
)
);
}
......
......@@ -63,10 +63,18 @@ class ConnectionTest extends FunctionalTestCase
{
$params = TestUtil::getConnectionParams();
if (isset($params['driverOptions'])) {
// Currently, MySQLi driver options may be either numeric MYSQLI_* keys
// or the {@link Connection::OPTION_FLAGS} string key.
// The options should be merged using array union instead of array_merge()
// to preserve the numeric keys.
$driverOptions += $params['driverOptions'];
}
return (new Driver())->connect(
array_merge(
$params,
['driver_options' => $driverOptions]
['driverOptions' => $driverOptions]
)
);
}
......
......@@ -44,10 +44,16 @@ class DriverTest extends AbstractDriverTest
*/
private function getConnection(array $driverOptions): Connection
{
$params = TestUtil::getConnectionParams();
if (isset($params['driverOptions'])) {
$driverOptions = array_merge($params['driverOptions'], $driverOptions);
}
return (new Driver())->connect(
array_merge(
TestUtil::getConnectionParams(),
['driver_options' => $driverOptions]
$params,
['driverOptions' => $driverOptions]
)
);
}
......
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Tests\Schema\Synchronizer;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer;
use PHPUnit\Framework\TestCase;
/**
* @requires extension pdo_sqlite
*/
class SingleDatabaseSynchronizerTest extends TestCase
{
/** @var Connection */
private $conn;
/** @var SingleDatabaseSynchronizer */
private $synchronizer;
protected function setUp(): void
{
$this->conn = DriverManager::getConnection([
'driver' => 'pdo_sqlite',
'memory' => true,
]);
$this->synchronizer = new SingleDatabaseSynchronizer($this->conn);
}
public function testGetCreateSchema(): void
{
$schema = new Schema();
$table = $schema->createTable('test');
$table->addColumn('id', 'integer');
$table->setPrimaryKey(['id']);
$sql = $this->synchronizer->getCreateSchema($schema);
self::assertEquals(['CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))'], $sql);
}
public function testGetUpdateSchema(): void
{
$schema = new Schema();
$table = $schema->createTable('test');
$table->addColumn('id', 'integer');
$table->setPrimaryKey(['id']);
$sql = $this->synchronizer->getUpdateSchema($schema);
self::assertEquals(['CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))'], $sql);
}
public function testGetDropSchema(): void
{
$schema = new Schema();
$table = $schema->createTable('test');
$table->addColumn('id', 'integer');
$table->setPrimaryKey(['id']);
$this->synchronizer->createSchema($schema);
$sql = $this->synchronizer->getDropSchema($schema);
self::assertEquals(['DROP TABLE test'], $sql);
}
public function testGetDropAllSchema(): void
{
$schema = new Schema();
$table = $schema->createTable('test');
$table->addColumn('id', 'integer');
$table->setPrimaryKey(['id']);
$this->synchronizer->createSchema($schema);
$sql = $this->synchronizer->getDropAllSchema();
self::assertEquals(['DROP TABLE test'], $sql);
}
}
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Tests;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Mysqli;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
......@@ -18,6 +19,9 @@ use function explode;
use function extension_loaded;
use function implode;
use function is_string;
use function strlen;
use function strpos;
use function substr;
use function unlink;
/**
......@@ -196,6 +200,11 @@ class TestUtil
'dbname',
'port',
'server',
'ssl_key',
'ssl_cert',
'ssl_ca',
'ssl_capath',
'ssl_cipher',
'unix_socket',
] as $parameter
) {
......@@ -210,6 +219,20 @@ class TestUtil
$parameters['port'] = (int) $parameters['port'];
}
foreach ($configuration as $param => $value) {
if (strpos($param, $prefix . 'driver_option_') !== 0) {
continue;
}
$option = substr($param, strlen($prefix . 'driver_option_'));
if ($option === Mysqli\Connection::OPTION_FLAGS) {
$value = (int) $value;
}
$parameters['driverOptions'][$option] = $value;
}
return $parameters;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment