Completed
Push — master ( 45c7cd...b1ef76 )
by David
16s queued 14s
created

ColumnsReorderer::reorderTableColumns()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 2
nc 2
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
    {
53
        $primaryKey = $table->getPrimaryKey();
54
        if ($primaryKey !== null) {
55
            $pkColumns = $primaryKey->getUnquotedColumns();
56
        } else {
57
            $pkColumns = [];
58
        }
59
        $fks = $table->getForeignKeys();
60
61
        $fkColumns = [];
62
63
        foreach ($fks as $fk) {
64
            $fkColumns = array_merge($fkColumns, $fk->getUnquotedLocalColumns());
65
        }
66
67
        $first = [];
68
        $second = [];
69
        $last = [];
70
71
        foreach ($table->getColumns() as $column) {
72
            if (in_array($column->getName(), $pkColumns, true)) {
73
                $first[] = $column;
74
            } elseif (in_array($column->getName(), $fkColumns, true)) {
75
                $second[] = $column;
76
            } else {
77
                $last[] = $column;
78
            }
79
        }
80
        return array_merge($first, $second, $last);
81
    }
82
}
83