Skip to content

Commit

Permalink
Introduce the SchemaManagerFactory interface
Browse files Browse the repository at this point in the history
… to allow apps to override the default schema managers
  • Loading branch information
derrabus committed Jan 28, 2023
1 parent e4f65b5 commit 537b711
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 14 deletions.
19 changes: 19 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@ awareness about deprecated code.

# Upgrade to 3.6

## Deprecated not setting a schema manager factory

DBAL 4 will change the way the schema manager is created. To opt in to the new
behavior, please configure the schema manager factory:

```php
$configuration = new Configuration();
$configuration->setSchemaManagerFactory(new DefaultSchemaManagerFactory());

$connection = DriverManager::getConnection(
[/* your parameters */],
$configuration,
);
```

If you use a custom platform implementation, please make sure it implements
the `createSchemaManager()`method . Otherwise, the connection will fail to
create a schema manager.

## Deprecated the `url` connection parameter

DBAL ships with a new and configurable DSN parser that can be used to parse a
Expand Down
63 changes: 55 additions & 8 deletions docs/en/reference/schema-manager.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ A Schema Manager instance helps you with the abstraction of the
generation of SQL assets such as Tables, Sequences, Foreign Keys
and Indexes.

To retrieve the ``SchemaManager`` for your connection you can use
the ``getSchemaManager()`` method:
To create a schema manager for your connection you can use
the ``createSchemaManager()`` method:

.. code-block:: php
<?php
$sm = $conn->getSchemaManager();
$sm = $conn->createSchemaManager();
Now with the ``SchemaManager`` instance in ``$sm`` you can use the
Now with the schema manager instance in ``$sm`` you can use the
available methods to learn about your database schema:

.. note::
Expand All @@ -36,7 +36,7 @@ Retrieve an array of databases on the configured connection:
$databases = $sm->listDatabases();
listSequences()
-------------------------------
---------------

Retrieve an array of ``Doctrine\DBAL\Schema\Sequence`` instances
that exist for a database:
Expand All @@ -63,7 +63,7 @@ Now you can loop over the array inspecting each sequence object:
}
listTableColumns()
----------------------------
------------------

Retrieve an array of ``Doctrine\DBAL\Schema\Column`` instances that
exist for the given table:
Expand Down Expand Up @@ -102,7 +102,7 @@ schema for that table. For example we can add a new column:
$table->addColumn('email_address', 'string');
listTableForeignKeys()
--------------------------------
----------------------

Retrieve an array of ``Doctrine\DBAL\Schema\ForeignKeyConstraint``
instances that exist for the given table:
Expand All @@ -123,7 +123,7 @@ object:
}
listTableIndexes()
----------------------------
------------------

Retrieve an array of ``Doctrine\DBAL\Schema\Index`` instances that
exist for the given table:
Expand Down Expand Up @@ -232,3 +232,50 @@ table:
0 => 'DROP TABLE user'
)
*/
Overriding the schema manager
-----------------------------

All schema manager classes can be overridden, for instance if your application needs to modify SQL statements emitted
by the schema manager or the comparator. If you want your own schema manager to be returned by
``Connection::createSchemaManager()`` you need to configure a factory for it.

.. code-block:: php
<?php
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\MySQLSchemaManager;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
class MyCustomMySQLSchemaManager extends MySQLSchemaManager
{
// .. your custom logic.
}
final class MySchemaManagerFactory implements SchemaManagerFactory
{
private readonly SchemaManagerFactory $defaultFactory;
public function __construct()
{
$this->defaultFactory = new DefaultSchemaManagerFactory();
}
public function createSchemaManager(Connection $connection): AbstractSchemaManager
{
$platform = $connection->getDatabasePlatform();
if ($platform instanceof AbstractMySQLPlatform) {
return new MyCustomMySQLSchemaManager($connection, $platform);
}
return $this->defaultFactory->createSchemaManager($connection);
}
}
$configuration = new Configuration();
$configuration->setSchemaManagerFactory(new MySchemaManagerFactory());
$connection = DriverManager::getConnection([/* your connection parameters */], $configuration);
16 changes: 16 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\DBAL\Driver\Middleware;
use Doctrine\DBAL\Logging\SQLLogger;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
use Doctrine\Deprecations\Deprecation;
use Psr\Cache\CacheItemPoolInterface;

Expand Down Expand Up @@ -55,6 +56,8 @@ class Configuration
*/
protected $autoCommit = true;

private ?SchemaManagerFactory $schemaManagerFactory = null;

public function __construct()
{
$this->schemaAssetsFilter = static function (): bool {
Expand Down Expand Up @@ -225,4 +228,17 @@ public function getMiddlewares(): array
{
return $this->middlewares;
}

public function getSchemaManagerFactory(): ?SchemaManagerFactory
{
return $this->schemaManagerFactory;
}

/** @return $this */
public function setSchemaManagerFactory(SchemaManagerFactory $schemaManagerFactory): self
{
$this->schemaManagerFactory = $schemaManagerFactory;

return $this;
}
}
25 changes: 21 additions & 4 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
use Doctrine\DBAL\Query\Expression\ExpressionBuilder;
use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\LegacySchemaManagerFactory;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
use Doctrine\DBAL\SQL\Parser;
use Doctrine\DBAL\Types\Type;
use Doctrine\Deprecations\Deprecation;
Expand Down Expand Up @@ -160,6 +163,8 @@ class Connection
*/
private bool $isRollbackOnly = false;

private SchemaManagerFactory $schemaManagerFactory;

/**
* Initializes a new instance of the Connection class.
*
Expand Down Expand Up @@ -209,6 +214,21 @@ public function __construct(
$this->_expr = $this->createExpressionBuilder();

$this->autoCommit = $config->getAutoCommit();

$schemaManagerFactory = $config->getSchemaManagerFactory();
if ($schemaManagerFactory === null) {
Deprecation::trigger(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/5812',
'Not configuring a schema manager factory is deprecated.'
. ' Use %s which is going to be the default in DBAL 4.',
DefaultSchemaManagerFactory::class,
);

$schemaManagerFactory = new LegacySchemaManagerFactory();
}

$this->schemaManagerFactory = $schemaManagerFactory;
}

/**
Expand Down Expand Up @@ -1654,10 +1674,7 @@ public function getNativeConnection()
*/
public function createSchemaManager(): AbstractSchemaManager
{
return $this->_driver->getSchemaManager(
$this,
$this->getDatabasePlatform(),
);
return $this->schemaManagerFactory->createSchemaManager($this);
}

/**
Expand Down
20 changes: 20 additions & 0 deletions src/Schema/DefaultSchemaManagerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;

/**
* A schema manager factory that returns the default schema manager for the given platform.
*/
final class DefaultSchemaManagerFactory implements SchemaManagerFactory
{
/** @throws Exception If the platform does not support creating schema managers yet. */
public function createSchemaManager(Connection $connection): AbstractSchemaManager
{
return $connection->getDatabasePlatform()->createSchemaManager($connection);
}
}
19 changes: 19 additions & 0 deletions src/Schema/LegacySchemaManagerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Connection;

/** @internal Will be removed in 4.0. */
final class LegacySchemaManagerFactory implements SchemaManagerFactory
{
public function createSchemaManager(Connection $connection): AbstractSchemaManager
{
return $connection->getDriver()->getSchemaManager(
$connection,
$connection->getDatabasePlatform(),
);
}
}
17 changes: 17 additions & 0 deletions src/Schema/SchemaManagerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Connection;

/**
* Creates a schema manager for the given connection.
*
* This interface is an extension point for applications that need to override schema managers.
*/
interface SchemaManagerFactory
{
public function createSchemaManager(Connection $connection): AbstractSchemaManager;
}
28 changes: 27 additions & 1 deletion tests/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Result;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
use Doctrine\DBAL\Schema\SqliteSchemaManager;
use Doctrine\DBAL\VersionAwarePlatformDriver;
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
use PHPUnit\Framework\MockObject\MockObject;
Expand Down Expand Up @@ -50,7 +53,7 @@ protected function setUp(): void
}

/** @return Connection&MockObject */
private function getExecuteStatementMockConnection()
private function getExecuteStatementMockConnection(): Connection
{
$driverMock = $this->createMock(Driver::class);

Expand Down Expand Up @@ -892,6 +895,29 @@ public function testExecuteCacheQueryStripsPlatformFromConnectionParamsBeforeGen

$connection->executeCacheQuery($query, [], [], $queryCacheProfile);
}

public function testCustomSchemaManagerFactory(): void
{
$schemaManager = $this->createStub(AbstractSchemaManager::class);
$factory = $this->createMock(SchemaManagerFactory::class);
$factory->expects(self::once())->method('createSchemaManager')->willReturn($schemaManager);

$configuration = new Configuration();
$configuration->setSchemaManagerFactory($factory);

$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/dbal/issues/5812');

$connection = DriverManager::getConnection(['driver' => 'sqlite3', 'memory' => true], $configuration);
self::assertSame($schemaManager, $connection->createSchemaManager());
}

public function testLegacySchemaManagerFactory(): void
{
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/dbal/issues/5812');

$connection = DriverManager::getConnection(['driver' => 'sqlite3', 'memory' => true]);
self::assertInstanceOf(SqliteSchemaManager::class, $connection->createSchemaManager());
}
}

interface ConnectDispatchEventListener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ protected function setUp(): void
self::markTestSkipped(sprintf('Skipping since connected to %s', get_class($platform)));
}

$this->schemaManager = $this->connection->getSchemaManager();
$this->schemaManager = $this->connection->createSchemaManager();
}

protected function tearDown(): void
Expand Down
3 changes: 3 additions & 0 deletions tests/TestUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Doctrine\DBAL\Platforms\DB2Platform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use PHPUnit\Framework\Assert;

use function array_keys;
Expand Down Expand Up @@ -155,6 +156,8 @@ private static function createConfiguration(string $driver): Configuration
break;
}

$configuration->setSchemaManagerFactory(new DefaultSchemaManagerFactory());

return $configuration;
}

Expand Down

0 comments on commit 537b711

Please sign in to comment.