Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow using multiple connections for CLI commands #3956

Merged
merged 1 commit into from
May 13, 2020
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
15 changes: 8 additions & 7 deletions bin/doctrine-dbal.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Doctrine\DBAL\Tools\Console\ConnectionProvider;
use Doctrine\DBAL\Tools\Console\ConsoleRunner;
use Symfony\Component\Console\Helper\HelperSet;

Expand Down Expand Up @@ -41,17 +42,17 @@
exit(1);
}

$commands = [];
$helperSet = require $configFile;
$commands = [];
$helperSetOrConnectionProvider = require $configFile;

if (! $helperSet instanceof HelperSet) {
foreach ($GLOBALS as $helperSetCandidate) {
if ($helperSetCandidate instanceof HelperSet) {
$helperSet = $helperSetCandidate;
if (! $helperSetOrConnectionProvider instanceof HelperSet && ! $helperSetOrConnectionProvider instanceof ConnectionProvider) {
foreach ($GLOBALS as $candidate) {
if ($candidate instanceof HelperSet) {
$helperSetOrConnectionProvider = $candidate;

break;
}
}
}

ConsoleRunner::run($helperSet, $commands);
ConsoleRunner::run($helperSetOrConnectionProvider, $commands);
56 changes: 48 additions & 8 deletions lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
use Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords;
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
use Exception;
use InvalidArgumentException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -30,6 +32,9 @@
use function assert;
use function count;
use function implode;
use function is_string;
use function trigger_error;
use const E_USER_DEPRECATED;

class ReservedWordsCommand extends Command
{
Expand All @@ -54,6 +59,20 @@ class ReservedWordsCommand extends Command
'sqlanywhere16' => SQLAnywhere16Keywords::class,
];

/** @var ConnectionProvider|null */
private $connectionProvider;

public function __construct(?ConnectionProvider $connectionProvider = null)
{
parent::__construct();
$this->connectionProvider = $connectionProvider;
if ($connectionProvider !== null) {
return;
}

@trigger_error('Not passing a connection provider as the first constructor argument is deprecated', E_USER_DEPRECATED);
}

/**
* If you want to add or replace a keywords list use this command.
*
Expand All @@ -73,12 +92,14 @@ protected function configure()
$this
->setName('dbal:reserved-words')
->setDescription('Checks if the current database contains identifiers that are reserved.')
->setDefinition([new InputOption(
'list',
'l',
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
'Keyword-List name.'
),
->setDefinition([
new InputOption('connection', null, InputOption::VALUE_REQUIRED, 'The named database connection'),
new InputOption(
'list',
'l',
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
'Keyword-List name.'
),
])
->setHelp(<<<EOT
Checks if the current database contains tables and columns
Expand Down Expand Up @@ -121,8 +142,7 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$conn = $this->getHelper('db')->getConnection();
assert($conn instanceof Connection);
$conn = $this->getConnection($input);

$keywordLists = (array) $input->getOption('list');
if (! $keywordLists) {
Expand Down Expand Up @@ -178,4 +198,24 @@ protected function execute(InputInterface $input, OutputInterface $output)

return 0;
}

private function getConnection(InputInterface $input) : Connection
{
$connectionName = $input->getOption('connection');
assert(is_string($connectionName) || $connectionName === null);

if ($this->connectionProvider === null) {
if ($connectionName !== null) {
throw new Exception('Specifying a connection is only supported when a ConnectionProvider is used.');
}

return $this->getHelper('db')->getConnection();
}

if ($connectionName !== null) {
return $this->connectionProvider->getConnection($connectionName);
}

return $this->connectionProvider->getDefaultConnection();
}
}
42 changes: 41 additions & 1 deletion lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Doctrine\DBAL\Tools\Console\Command;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
use Doctrine\DBAL\Tools\Dumper;
use Exception;
use LogicException;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
Expand All @@ -14,20 +17,37 @@
use function is_numeric;
use function is_string;
use function stripos;
use function trigger_error;
use const E_USER_DEPRECATED;

/**
* Task for executing arbitrary SQL that can come from a file or directly from
* the command line.
*/
class RunSqlCommand extends Command
{
/** @var ConnectionProvider|null */
private $connectionProvider;

public function __construct(?ConnectionProvider $connectionProvider = null)
{
parent::__construct();
$this->connectionProvider = $connectionProvider;
if ($connectionProvider !== null) {
return;
}

@trigger_error('Not passing a connection provider as the first constructor argument is deprecated', E_USER_DEPRECATED);
}

/** @return void */
protected function configure()
{
$this
->setName('dbal:run-sql')
->setDescription('Executes arbitrary SQL directly from the command line.')
->setDefinition([
new InputOption('connection', null, InputOption::VALUE_REQUIRED, 'The named database connection'),
new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'),
new InputOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of result set.', 7),
new InputOption('force-fetch', null, InputOption::VALUE_NONE, 'Forces fetching the result.'),
Expand All @@ -43,7 +63,7 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$conn = $this->getHelper('db')->getConnection();
$conn = $this->getConnection($input);

$sql = $input->getArgument('sql');

Expand All @@ -69,4 +89,24 @@ protected function execute(InputInterface $input, OutputInterface $output)

return 0;
}

private function getConnection(InputInterface $input) : Connection
{
$connectionName = $input->getOption('connection');
assert(is_string($connectionName) || $connectionName === null);

if ($this->connectionProvider === null) {
if ($connectionName !== null) {
throw new Exception('Specifying a connection is only supported when a ConnectionProvider is used.');
}

return $this->getHelper('db')->getConnection();
}

if ($connectionName !== null) {
return $this->connectionProvider->getConnection($connectionName);
}

return $this->connectionProvider->getDefaultConnection();
}
}
9 changes: 9 additions & 0 deletions lib/Doctrine/DBAL/Tools/Console/ConnectionNotFound.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Doctrine\DBAL\Tools\Console;

use OutOfBoundsException;

final class ConnectionNotFound extends OutOfBoundsException
{
}
15 changes: 15 additions & 0 deletions lib/Doctrine/DBAL/Tools/Console/ConnectionProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Doctrine\DBAL\Tools\Console;

use Doctrine\DBAL\Connection;

interface ConnectionProvider
{
public function getDefaultConnection() : Connection;

/**
* @throws ConnectionNotFound in case a connection with the given name does not exist.
*/
public function getConnection(string $name) : Connection;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Doctrine\DBAL\Tools\Console\ConnectionProvider;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Tools\Console\ConnectionNotFound;
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
use function sprintf;

class SingleConnectionProvider implements ConnectionProvider
{
/** @var Connection */
private $connection;

/** @var string */
private $defaultConnectionName;

public function __construct(Connection $connection, string $defaultConnectionName = 'default')
{
$this->connection = $connection;
$this->defaultConnectionName = $defaultConnectionName;
}

public function getDefaultConnection() : Connection
{
return $this->connection;
}

public function getConnection(string $name) : Connection
{
if ($name !== $this->defaultConnectionName) {
throw new ConnectionNotFound(sprintf('Connection with name "%s" does not exist.', $name));
}

return $this->connection;
}
}
46 changes: 33 additions & 13 deletions lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\HelperSet;
use TypeError;
use function sprintf;
use function trigger_error;
use const E_USER_DEPRECATED;

/**
* Handles running the Console Tools inside Symfony Console context.
Expand All @@ -20,6 +24,8 @@ class ConsoleRunner
/**
* Create a Symfony Console HelperSet
*
* @deprecated use a ConnectionProvider instead.
*
* @return HelperSet
*/
public static function createHelperSet(Connection $connection)
Expand All @@ -30,20 +36,31 @@ public static function createHelperSet(Connection $connection)
}

/**
* Runs console with the given helperset.
* Runs console with the given connection provider or helperset (deprecated).
*
* @param Command[] $commands
* @param ConnectionProvider|HelperSet $helperSetOrConnectionProvider
* @param Command[] $commands
*
* @return void
*/
public static function run(HelperSet $helperSet, $commands = [])
public static function run($helperSetOrConnectionProvider, $commands = [])
{
$cli = new Application('Doctrine Command Line Interface', Version::VERSION);

$cli->setCatchExceptions(true);
$cli->setHelperSet($helperSet);

self::addCommands($cli);
$connectionProvider = null;
if ($helperSetOrConnectionProvider instanceof HelperSet) {
@trigger_error(sprintf('Passing an instance of "%s" as the first argument is deprecated. Pass an instance of "%s" instead.', HelperSet::class, ConnectionProvider::class), E_USER_DEPRECATED);
$connectionProvider = null;
$cli->setHelperSet($helperSetOrConnectionProvider);
} elseif ($helperSetOrConnectionProvider instanceof ConnectionProvider) {
$connectionProvider = $helperSetOrConnectionProvider;
} else {
throw new TypeError(sprintf('First argument must be an instance of "%s" or "%s"', HelperSet::class, ConnectionProvider::class));
}

self::addCommands($cli, $connectionProvider);

$cli->addCommands($commands);
$cli->run();
Expand All @@ -52,12 +69,12 @@ public static function run(HelperSet $helperSet, $commands = [])
/**
* @return void
*/
public static function addCommands(Application $cli)
public static function addCommands(Application $cli, ?ConnectionProvider $connectionProvider = null)
{
$cli->addCommands([
new RunSqlCommand(),
new RunSqlCommand($connectionProvider),
new ImportCommand(),
new ReservedWordsCommand(),
new ReservedWordsCommand($connectionProvider),
]);
}

Expand All @@ -74,14 +91,17 @@ public static function printCliConfigTemplate()
following sample as a template:

<?php
use Doctrine\DBAL\Tools\Console\ConsoleRunner;

// replace with the mechanism to retrieve DBAL connection in your app
$connection = getDBALConnection();
use Doctrine\DBAL\Tools\Console\ConnectionProvider\SingleConnectionProvider;

// You can append new commands to $commands array, if needed

return ConsoleRunner::createHelperSet($connection);
// replace with the mechanism to retrieve DBAL connection(s) in your app
// and return a Doctrine\DBAL\Tools\Console\ConnectionProvider instance.
$connection = getDBALConnection();

// in case you have a single connection you can use SingleConnectionProvider
// otherwise you need to implement the Doctrine\DBAL\Tools\Console\ConnectionProvider interface with your custom logic
return new SingleConnectionProvider($connection);

HELP;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

/**
* Doctrine CLI Connection Helper.
*
* @deprecated use a ConnectionProvider instead.
*/
class ConnectionHelper extends Helper
{
Expand Down