Passed
Pull Request — master (#224)
by David
03:07
created

ColumnsReorderer::getColumnsInExpectedOrder()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 20
c 2
b 1
f 0
dl 0
loc 29
rs 8.9777
cc 6
nc 16
nop 1
1
<?php
2
3
4
namespace TheCodingMachine\TDBM\Utils;
5
6
use Doctrine\DBAL\Schema\Column;
7
use Doctrine\DBAL\Schema\Schema;
8
use Doctrine\DBAL\Schema\Table;
9
use ReflectionClass;
10
use function array_merge;
11
use function in_array;
12
13
/**
14
 * The sole purpose of this class is to work around a DBAL bug related to Oracle that
15
 * does not return the columns in the same order as the other databases.
16
 * In order to have consistent results (and consistent tests), we need those columns in
17
 * the same order in all databases.
18
 */
19
class ColumnsReorderer
20
{
21
    public static function reorderTableColumns(Schema $schema): void
22
    {
23
        foreach ($schema->getTables() as $table) {
24
            self::reorderColumnsForTable($table);
25
        }
26
    }
27
28
    private static function reorderColumnsForTable(Table $table): void
29
    {
30
        $columns = self::getColumnsInExpectedOrder($table);
31
32
        // Note: the only way to rewrite columns order is to tap into a PROTECTED method.
33
        // This is bad BUT!
34
        // - we only do this for Oracle databases
35
        // - we know Doctrine consider protected methods as part of the API for BC changes so risk is limited.
36
        $refClass = new ReflectionClass(Table::class);
37
        $addColumnMethod = $refClass->getMethod('_addColumn');
38
        $addColumnMethod->setAccessible(true);
39
40
        foreach ($columns as $column) {
41
            $table->dropColumn($column->getName());
42
            $addColumnMethod->invoke($table, $column);
43
            //$table->_addColumn($column);
44
        }
45
    }
46
47
    /**
48
     * @param Table $table
49
     * @return Column[]
50
     */
51
    private static function getColumnsInExpectedOrder(Table $table): array {
52
        $primaryKey = $table->getPrimaryKey();
53
        if ($primaryKey !== null) {
54
            $pkColumns = $primaryKey->getUnquotedColumns();
55
        } else {
56
            $pkColumns = [];
57
        }
58
        $fks = $table->getForeignKeys();
59
60
        $fkColumns = [];
61
62
        foreach ($fks as $fk) {
63
            $fkColumns = array_merge($fkColumns, $fk->getUnquotedLocalColumns());
64
        }
65
66
        $first = [];
67
        $second = [];
68
        $last = [];
69
70
        foreach ($table->getColumns() as $column) {
71
            if (in_array($column->getName(), $pkColumns, true)) {
72
                $first[] = $column;
73
            } elseif (in_array($column->getName(), $fkColumns, true)) {
74
                $second[] = $column;
75
            } else {
76
                $last[] = $column;
77
            }
78
        }
79
        return array_merge($first, $second, $last);
80
    }
81
}
82