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

[11.x] Remove Doctrine DBAL #48864

Merged
merged 61 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
f6538ad
remove doctrine dbal from grammar
hafezdivandari Oct 31, 2023
8d882eb
remove unused imports
hafezdivandari Oct 31, 2023
c37884d
fix tests
hafezdivandari Oct 31, 2023
0346940
fix tests
hafezdivandari Oct 31, 2023
ba31106
remove mysql 5.7 tests
hafezdivandari Oct 31, 2023
ca78589
fix facade doctype
hafezdivandari Oct 31, 2023
f55b31e
use native column modifying by default
hafezdivandari Oct 31, 2023
90d1f8a
fix tests
hafezdivandari Oct 31, 2023
a5f4957
Merge branch 'master' into master-patch-2
hafezdivandari Nov 8, 2023
8c39f63
fix tests
hafezdivandari Nov 8, 2023
45310fd
wip
hafezdivandari Nov 8, 2023
19d5f92
Revert "remove mysql 5.7 tests"
hafezdivandari Nov 21, 2023
61208ea
support native column renaming on MySQL 5.7
hafezdivandari Nov 21, 2023
41837ca
fix style
hafezdivandari Nov 21, 2023
f612a13
wip
hafezdivandari Nov 21, 2023
019a868
Merge branch 'master' into master-patch-2
hafezdivandari Nov 28, 2023
fc2f9af
wip
hafezdivandari Nov 28, 2023
274fe12
remove doctrine usage on DatabaseTruncation
hafezdivandari Nov 28, 2023
a30d550
Merge branch 'master' into master-patch-2
hafezdivandari Dec 10, 2023
73754a4
wip
hafezdivandari Dec 10, 2023
f082214
rename index on sqlite
hafezdivandari Dec 10, 2023
254e099
remove doctrine/dbal from db commands
hafezdivandari Dec 10, 2023
49a0c3f
fix styles
hafezdivandari Dec 10, 2023
ba0d8ea
wip
hafezdivandari Dec 10, 2023
bd1bceb
wip
hafezdivandari Dec 11, 2023
ba4978e
support renaming columns on legacy MariaDB
hafezdivandari Dec 11, 2023
eae02d9
remove redundant non-standard tests
hafezdivandari Dec 11, 2023
a99792e
Merge branch 'master' into master-patch-2
hafezdivandari Dec 13, 2023
b5c3862
Merge branch 'master' into master-patch-2
hafezdivandari Dec 16, 2023
92d0ec9
add collation modifier to sqlite
hafezdivandari Dec 17, 2023
8b6c226
support native column modifying on sqlite
hafezdivandari Dec 17, 2023
402830d
fix styles
hafezdivandari Dec 17, 2023
9a7be0c
add user-defined types to db:show
hafezdivandari Dec 17, 2023
686ec27
wip
hafezdivandari Dec 17, 2023
d44e2c6
fix styles
hafezdivandari Dec 17, 2023
ebd9bee
fix dropForeign exception on SQLite
hafezdivandari Dec 17, 2023
46562fb
fix styles
hafezdivandari Dec 17, 2023
1cc64af
include generated and hidden columns on sqlite
hafezdivandari Dec 18, 2023
1d8510f
remove custom doctrine types
hafezdivandari Dec 18, 2023
86058a8
remove doctrine change column
hafezdivandari Dec 18, 2023
88c2752
styling
hafezdivandari Dec 18, 2023
298b43f
remove support for registering custom doctrine types
hafezdivandari Dec 18, 2023
b60b221
remove unused config methods and property
hafezdivandari Dec 18, 2023
35666b3
remove redundant semicolon
hafezdivandari Dec 19, 2023
8102add
Merge branch 'master' into master-patch-2
hafezdivandari Dec 21, 2023
3a8acd2
force re-run tests
hafezdivandari Dec 21, 2023
29cfb81
remove doctrine related conflicts
hafezdivandari Dec 22, 2023
fc4dd91
remove doctrine/dbal from require-dev
hafezdivandari Dec 22, 2023
fa197e0
Revert "remove doctrine/dbal from require-dev"
hafezdivandari Dec 22, 2023
2fb96c4
revert unrelated changes
hafezdivandari Dec 25, 2023
d7e1ddf
disable foreign key constraints when altering table on SQLite
hafezdivandari Dec 25, 2023
0aa3207
fix styling
hafezdivandari Dec 25, 2023
606663d
consider backticks when parsing collate on SQLite
hafezdivandari Dec 25, 2023
02eef27
update facade docblocks
hafezdivandari Dec 27, 2023
5e99d96
remove doctrine connection
hafezdivandari Dec 27, 2023
20f80bb
Merge branch 'master' into master-patch-2
hafezdivandari Jan 3, 2024
7110c42
formatting
hafezdivandari Jan 3, 2024
b88f803
Merge branch 'master' into master-patch-2
hafezdivandari Jan 5, 2024
f5a2c8a
Merge branch 'master' into master-patch-2
hafezdivandari Jan 9, 2024
055e1cd
fix conflicts
hafezdivandari Jan 9, 2024
63ea4d6
formatting
taylorotwell Jan 9, 2024
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
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@
"ably/ably-php": "Required to use the Ably broadcast driver (^1.0).",
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.235.5).",
"brianium/paratest": "Required to run tests in parallel (^6.0).",
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^4.0).",
crynobone marked this conversation as resolved.
Show resolved Hide resolved
"fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
"filp/whoops": "Required for friendly error pages in development (^2.14.3).",
"guzzlehttp/guzzle": "Required to use the HTTP Client and the ping methods on schedules (^7.6).",
Expand Down
97 changes: 10 additions & 87 deletions src/Illuminate/Database/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use Closure;
use DateTimeInterface;
use Doctrine\DBAL\Connection as DoctrineConnection;
use Doctrine\DBAL\Types\Type;
use Exception;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Events\QueryExecuted;
Expand Down Expand Up @@ -196,13 +195,6 @@ class Connection implements ConnectionInterface
*/
protected $doctrineConnection;

/**
* Type mappings that should be registered with new Doctrine connections.
*
* @var array<string, string>
*/
protected $doctrineTypeMappings = [];

/**
* The connection resolvers.
*
Expand Down Expand Up @@ -1208,52 +1200,6 @@ public function useWriteConnectionWhenReading($value = true)
return $this;
}

/**
* Is Doctrine available?
*
* @return bool
*/
public function isDoctrineAvailable()
{
return class_exists('Doctrine\DBAL\Connection');
}

/**
* Indicates whether native alter operations will be used when dropping, renaming, or modifying columns, even if Doctrine DBAL is installed.
*
* @return bool
*/
public function usingNativeSchemaOperations()
{
return ! $this->isDoctrineAvailable() || SchemaBuilder::$alwaysUsesNativeSchemaOperationsIfPossible;
}

/**
* Get a Doctrine Schema Column instance.
*
* @param string $table
* @param string $column
* @return \Doctrine\DBAL\Schema\Column
*/
public function getDoctrineColumn($table, $column)
{
$schema = $this->getDoctrineSchemaManager();

return $schema->introspectTable($table)->getColumn($column);
}

/**
* Get the Doctrine DBAL schema manager for the connection.
*
* @return \Doctrine\DBAL\Schema\AbstractSchemaManager
*/
public function getDoctrineSchemaManager()
{
$connection = $this->getDoctrineConnection();

return $connection->createSchemaManager();
}

/**
* Get the Doctrine DBAL database connection instance.
*
Expand All @@ -1270,44 +1216,11 @@ public function getDoctrineConnection()
'driver' => $driver->getName(),
'serverVersion' => $this->getConfig('server_version'),
]), $driver);

foreach ($this->doctrineTypeMappings as $name => $type) {
$this->doctrineConnection
->getDatabasePlatform()
->registerDoctrineTypeMapping($type, $name);
}
}

return $this->doctrineConnection;
}

/**
* Register a custom Doctrine mapping type.
*
* @param Type|class-string<Type> $class
* @param string $name
* @param string $type
* @return void
*
* @throws \Doctrine\DBAL\Exception
* @throws \RuntimeException
*/
public function registerDoctrineType(Type|string $class, string $name, string $type): void
{
if (! $this->isDoctrineAvailable()) {
throw new RuntimeException(
'Registering a custom Doctrine type requires Doctrine DBAL (doctrine/dbal).'
);
}

if (! Type::hasType($name)) {
Type::getTypeRegistry()
->register($name, is_string($class) ? new $class() : $class);
}

$this->doctrineTypeMappings[$name] = $type;
}

/**
* Get the current PDO connection.
*
Expand Down Expand Up @@ -1722,6 +1635,16 @@ public function withTablePrefix(Grammar $grammar)
return $grammar;
}

/**
* Get the server version for the connection.
*
* @return string
*/
public function getServerVersion(): string
{
return $this->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
}

/**
* Register a connection resolver.
*
Expand Down
204 changes: 20 additions & 184 deletions src/Illuminate/Database/Console/DatabaseInspectionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,169 +2,35 @@

namespace Illuminate\Database\Console;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Illuminate\Console\Command;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\MySqlConnection;
use Illuminate\Database\PostgresConnection;
use Illuminate\Database\QueryException;
use Illuminate\Database\SQLiteConnection;
use Illuminate\Database\SqlServerConnection;
use Illuminate\Support\Arr;
use Illuminate\Support\Composer;
use Symfony\Component\Process\Exception\ProcessSignaledException;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;

use function Laravel\Prompts\confirm;

abstract class DatabaseInspectionCommand extends Command
{
/**
* A map of database column types.
*
* @var array
*/
protected $typeMappings = [
'bit' => 'string',
'citext' => 'string',
'enum' => 'string',
'geometry' => 'string',
'geomcollection' => 'string',
'linestring' => 'string',
'ltree' => 'string',
'multilinestring' => 'string',
'multipoint' => 'string',
'multipolygon' => 'string',
'point' => 'string',
'polygon' => 'string',
'sysname' => 'string',
];

/**
* The Composer instance.
*
* @var \Illuminate\Support\Composer
*/
protected $composer;

/**
* Create a new command instance.
*
* @param \Illuminate\Support\Composer|null $composer
* @return void
*/
public function __construct(Composer $composer = null)
{
parent::__construct();

$this->composer = $composer ?? $this->laravel->make(Composer::class);
}

/**
* Register the custom Doctrine type mappings for inspection commands.
*
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
* @return void
*/
protected function registerTypeMappings(AbstractPlatform $platform)
{
foreach ($this->typeMappings as $type => $value) {
$platform->registerDoctrineTypeMapping($type, $value);
}
}

/**
* Get a human-readable platform name for the given platform.
* Get a human-readable name for the given connection.
*
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $database
* @return string
*/
protected function getPlatformName(AbstractPlatform $platform, $database)
{
return match (class_basename($platform)) {
'MySQLPlatform' => 'MySQL <= 5',
'MySQL57Platform' => 'MySQL 5.7',
'MySQL80Platform' => 'MySQL 8',
'PostgreSQL100Platform', 'PostgreSQLPlatform' => 'Postgres',
'SqlitePlatform' => 'SQLite',
'SQLServerPlatform' => 'SQL Server',
'SQLServer2012Platform' => 'SQL Server 2012',
default => $database,
};
}

/**
* Get the size of a table in bytes.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $table
* @return int|null
*/
protected function getTableSize(ConnectionInterface $connection, string $table)
protected function getConnectionName(ConnectionInterface $connection, $database)
{
return match (true) {
$connection instanceof MySqlConnection => $this->getMySQLTableSize($connection, $table),
$connection instanceof PostgresConnection => $this->getPostgresTableSize($connection, $table),
$connection instanceof SQLiteConnection => $this->getSqliteTableSize($connection, $table),
default => null,
$connection instanceof MySqlConnection && $connection->isMaria() => 'MariaDB',
$connection instanceof MySqlConnection => 'MySQL',
$connection instanceof PostgresConnection => 'PostgreSQL',
$connection instanceof SQLiteConnection => 'SQLite',
$connection instanceof SqlServerConnection => 'SQL Server',
default => $database,
};
}

/**
* Get the size of a MySQL table in bytes.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $table
* @return mixed
*/
protected function getMySQLTableSize(ConnectionInterface $connection, string $table)
{
$result = $connection->selectOne('SELECT (data_length + index_length) AS size FROM information_schema.TABLES WHERE table_schema = ? AND table_name = ?', [
$connection->getDatabaseName(),
$table,
]);

return Arr::wrap((array) $result)['size'];
}

/**
* Get the size of a Postgres table in bytes.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $table
* @return mixed
*/
protected function getPostgresTableSize(ConnectionInterface $connection, string $table)
{
$result = $connection->selectOne('SELECT pg_total_relation_size(?) AS size;', [
$table,
]);

return Arr::wrap((array) $result)['size'];
}

/**
* Get the size of a SQLite table in bytes.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $table
* @return mixed
*/
protected function getSqliteTableSize(ConnectionInterface $connection, string $table)
{
try {
$result = $connection->selectOne('SELECT SUM(pgsize) AS size FROM dbstat WHERE name=?', [
$table,
]);

return Arr::wrap((array) $result)['size'];
} catch (QueryException) {
return null;
}
}

/**
* Get the number of open connections for a database.
*
Expand All @@ -175,8 +41,8 @@ protected function getConnectionCount(ConnectionInterface $connection)
{
$result = match (true) {
$connection instanceof MySqlConnection => $connection->selectOne('show status where variable_name = "threads_connected"'),
$connection instanceof PostgresConnection => $connection->selectOne('select count(*) AS "Value" from pg_stat_activity'),
$connection instanceof SqlServerConnection => $connection->selectOne('SELECT COUNT(*) Value FROM sys.dm_exec_sessions WHERE status = ?', ['running']),
$connection instanceof PostgresConnection => $connection->selectOne('select count(*) as "Value" from pg_stat_activity'),
$connection instanceof SqlServerConnection => $connection->selectOne('select count(*) Value from sys.dm_exec_sessions where status = ?', ['running']),
default => null,
};

Expand All @@ -201,48 +67,18 @@ protected function getConfigFromDatabase($database)
}

/**
* Ensure the dependencies for the database commands are available.
*
* @return bool
*/
protected function ensureDependenciesExist()
{
return tap(interface_exists('Doctrine\DBAL\Driver'), function ($dependenciesExist) {
if (! $dependenciesExist && confirm('Inspecting database information requires the Doctrine DBAL (doctrine/dbal) package. Would you like to install it?', default: false)) {
$this->installDependencies();
}
});
}

/**
* Install the command's dependencies.
*
* @return void
* Remove the table prefix from a table name, if it exists.
*
* @throws \Symfony\Component\Process\Exception\ProcessSignaledException
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $table
* @return string
*/
protected function installDependencies()
protected function withoutTablePrefix(ConnectionInterface $connection, string $table)
{
$command = collect($this->composer->findComposer())
->push('require doctrine/dbal:^3.5.1')
->implode(' ');

$process = Process::fromShellCommandline($command, null, null, null, null);
$prefix = $connection->getTablePrefix();

if ('\\' !== DIRECTORY_SEPARATOR && file_exists('/dev/tty') && is_readable('/dev/tty')) {
try {
$process->setTty(true);
} catch (RuntimeException $e) {
$this->components->warn($e->getMessage());
}
}

try {
$process->run(fn ($type, $line) => $this->output->write($line));
} catch (ProcessSignaledException $e) {
if (extension_loaded('pcntl') && $e->getSignal() !== SIGINT) {
throw $e;
}
}
return str_starts_with($table, $prefix)
? substr($table, strlen($prefix))
: $table;
}
}
Loading