1 | <?php |
||
2 | |||
3 | namespace HexMakina\Crudites; |
||
4 | |||
5 | use \HexMakina\Crudites\Queries\Select; |
||
6 | use \HexMakina\Crudites\Queries\Describe; |
||
7 | use \HexMakina\Crudites\Table\Manipulation; |
||
8 | use \HexMakina\Crudites\Table\Column; |
||
9 | use \HexMakina\Crudites\Interfaces\ConnectionInterface; |
||
10 | use \HexMakina\Crudites\Interfaces\DatabaseInterface; |
||
11 | use \HexMakina\Crudites\Interfaces\TableManipulationInterface; |
||
12 | |||
13 | class Database implements DatabaseInterface |
||
14 | { |
||
15 | private $connection = null; |
||
16 | private $table_cache = []; |
||
17 | private $fk_by_table = []; |
||
18 | private $unique_by_table = []; |
||
19 | |||
20 | public function __construct(ConnectionInterface $connection) |
||
21 | { |
||
22 | $this->connection = $connection; |
||
23 | $this->introspect(); |
||
24 | } |
||
25 | |||
26 | public function name() |
||
27 | { |
||
28 | return $this->connection()->database_name(); |
||
29 | } |
||
30 | |||
31 | public function connection(): ConnectionInterface |
||
32 | { |
||
33 | return $this->connection; |
||
34 | } |
||
35 | |||
36 | public function introspect() |
||
37 | { |
||
38 | $statement = 'SELECT TABLE_NAME, CONSTRAINT_NAME, ORDINAL_POSITION, COLUMN_NAME, POSITION_IN_UNIQUE_CONSTRAINT, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = "%s" ORDER BY TABLE_NAME, CONSTRAINT_NAME, ORDINAL_POSITION'; |
||
39 | |||
40 | $this->connection->useDatabase('INFORMATION_SCHEMA'); |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
41 | $res = $this->connection->query(sprintf($statement,$this->name()))->fetchAll(); |
||
42 | $this->connection->useDatabase($this->name()); |
||
43 | |||
44 | foreach ($res as $key_usage) { |
||
45 | $table_name = $key_usage['TABLE_NAME']; |
||
46 | |||
47 | if (isset($key_usage['REFERENCED_TABLE_NAME'])) { // FOREIGN KEYS |
||
48 | $this->fk_by_table[$table_name] = $this->fk_by_table[$table_name] ?? []; |
||
49 | $this->fk_by_table[$table_name][$key_usage['COLUMN_NAME']] = [$key_usage['REFERENCED_TABLE_NAME'], $key_usage['REFERENCED_COLUMN_NAME']]; |
||
50 | } |
||
51 | |||
52 | if (!isset($key_usage['POSITION_IN_UNIQUE_CONSTRAINT'])) { // PRIMARY & UNIQUES |
||
53 | $constraint_name = $key_usage['CONSTRAINT_NAME']; |
||
54 | $column_name = $key_usage['COLUMN_NAME']; |
||
55 | |||
56 | $this->unique_by_table[$table_name] = $this->unique_by_table[$table_name] ?? []; |
||
57 | $this->unique_by_table[$table_name][$constraint_name] = $this->unique_by_table[$table_name][$constraint_name] ?? []; |
||
58 | $this->unique_by_table[$table_name][$constraint_name][$key_usage['ORDINAL_POSITION']] = $column_name; |
||
59 | } |
||
60 | } |
||
61 | |||
62 | foreach ($this->unique_by_table as $table_name => $uniques) { |
||
63 | foreach ($uniques as $constraint_name => $columns) { |
||
64 | foreach ($columns as $column_name) { |
||
65 | $this->unique_by_table[$table_name][$column_name] = [0 => $constraint_name] + $columns; |
||
66 | } |
||
67 | unset($this->unique_by_table[$table_name][$constraint_name]); |
||
68 | } |
||
69 | } |
||
70 | } |
||
71 | |||
72 | public function inspect($table_name): TableManipulationInterface |
||
73 | { |
||
74 | if (isset($this->table_cache[$table_name])) { |
||
75 | return $this->table_cache[$table_name]; |
||
76 | } |
||
77 | |||
78 | |||
79 | $describe = (new Describe($table_name)); |
||
80 | $describe->connection($this->connection()); |
||
81 | $description = $describe->ret(); |
||
82 | |||
83 | // TODO test this when all is back to normal 2021.03.09 |
||
84 | if ($description === false) { |
||
85 | throw new \PDOException("Unable to describe $table_name"); |
||
86 | } |
||
87 | |||
88 | $table = new Manipulation($table_name, $this->connection()); |
||
89 | |||
90 | foreach ($description as $column_name => $specs) { |
||
91 | $column = new Column($table, $column_name, $specs); |
||
92 | |||
93 | // handling usage constraints |
||
94 | if (isset($this->unique_by_table[$table_name][$column_name])) { |
||
95 | $unique_name = $this->unique_by_table[$table_name][$column_name][0]; |
||
96 | |||
97 | switch (count($this->unique_by_table[$table_name][$column_name])) { |
||
98 | case 2: // constraint name + column |
||
99 | $column->uniqueName($unique_name); |
||
100 | $table->add_unique_key($unique_name, $column_name); |
||
101 | break; |
||
102 | |||
103 | default: |
||
104 | $column->uniqueGroupName($unique_name); |
||
105 | unset($this->unique_by_table[$table_name][$column_name][0]); |
||
106 | $table->add_unique_key($unique_name, $this->unique_by_table[$table_name][$column_name]); |
||
107 | break; |
||
108 | } |
||
109 | } |
||
110 | // handling usage foreign keys |
||
111 | if (($reference = $this->getForeignKey($table_name, $column_name)) !== false) { |
||
112 | $column->isForeign(true); |
||
113 | $column->setForeignTableName($reference[0]); |
||
114 | $column->setForeignColumnName($reference[1]); |
||
115 | |||
116 | $table->add_foreign_key($column); |
||
117 | } |
||
118 | $table->add_column($column); |
||
119 | } |
||
120 | // ddt($table); |
||
121 | $this->table_cache[$table_name] = $table; |
||
122 | |||
123 | return $this->table_cache[$table_name]; |
||
124 | } |
||
125 | |||
126 | public function getForeignKey($table_name, $column_name) |
||
127 | { |
||
128 | return $this->fk_by_table[$table_name][$column_name] ?? false; |
||
129 | } |
||
130 | } |
||
131 |