1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Robin Appelman <robin@icewind.nl>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Core\Command\Db;
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Types\PhpIntegerMappingType;
use Doctrine\DBAL\Types\Type;
class SchemaEncoder {
/**
* Encode a DBAL schema to json, performing some normalization based on the database platform
*
* @param Schema $schema
* @param AbstractPlatform $platform
* @return array
*/
public function encodeSchema(Schema $schema, AbstractPlatform $platform): array {
$encoded = ['tables' => [], 'sequences' => []];
foreach ($schema->getTables() as $table) {
$encoded[$table->getName()] = $this->encodeTable($table, $platform);
}
ksort($encoded);
return $encoded;
}
/**
* @psalm-type ColumnArrayType =
*/
private function encodeTable(Table $table, AbstractPlatform $platform): array {
$encoded = ['columns' => [], 'indexes' => []];
foreach ($table->getColumns() as $column) {
/**
* @var array{
* name: string,
* default: mixed,
* notnull: bool,
* length: ?int,
* precision: int,
* scale: int,
* unsigned: bool,
* fixed: bool,
* autoincrement: bool,
* comment: string,
* columnDefinition: ?string,
* collation?: string,
* charset?: string,
* jsonb?: bool,
* } $data
**/
$data = $column->toArray();
$data['type'] = Type::getTypeRegistry()->lookupName($column->getType());
$data['default'] = $column->getType()->convertToPHPValue($column->getDefault(), $platform);
if ($platform instanceof PostgreSQLPlatform) {
$data['unsigned'] = false;
if ($column->getType() instanceof PhpIntegerMappingType) {
$data['length'] = null;
}
unset($data['jsonb']);
} elseif ($platform instanceof AbstractMySqlPlatform) {
if ($column->getType() instanceof PhpIntegerMappingType) {
$data['length'] = null;
} elseif (in_array($data['type'], ['text', 'blob', 'datetime', 'float', 'json'])) {
$data['length'] = 0;
}
unset($data['collation']);
unset($data['charset']);
}
if ($data['type'] === 'string' && $data['length'] === null) {
$data['length'] = 255;
}
$encoded['columns'][$column->getName()] = $data;
}
ksort($encoded['columns']);
foreach ($table->getIndexes() as $index) {
$options = $index->getOptions();
if (isset($options['lengths']) && count(array_filter($options['lengths'])) === 0) {
unset($options['lengths']);
}
if ($index->isPrimary()) {
if ($platform instanceof PostgreSqlPlatform) {
$name = $table->getName() . '_pkey';
} elseif ($platform instanceof AbstractMySQLPlatform) {
$name = 'PRIMARY';
} else {
$name = $index->getName();
}
} else {
$name = $index->getName();
}
if ($platform instanceof PostgreSqlPlatform) {
$name = strtolower($name);
}
$encoded['indexes'][$name] = [
'name' => $name,
'columns' => $index->getColumns(),
'unique' => $index->isUnique(),
'primary' => $index->isPrimary(),
'flags' => $index->getFlags(),
'options' => $options,
];
}
ksort($encoded['indexes']);
return $encoded;
}
}
|