Completed
Push — master ( 7250b3...569794 )
by Sébastien
02:47 queued 21s
created

MysqlDriver51   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 280
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 98.61%

Importance

Changes 10
Bugs 3 Features 0
Metric Value
wmc 32
c 10
b 3
f 0
lcom 1
cbo 4
dl 0
loc 280
ccs 142
cts 144
cp 0.9861
rs 9.6

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
F getSchemaConfig() 0 148 27
B getQuery() 0 77 2
A executeQuery() 0 13 2
1
<?php
2
3
namespace Soluble\Schema\Source\Mysql;
4
5
use Soluble\DbWrapper\Adapter\AdapterInterface;
6
use ArrayObject;
7
use Zend\Config\Config;
8
use Soluble\Schema\Exception;
9
10
class MysqlDriver51 extends AbstractMysqlDriver
11
{
12
13
    /**
14
     * @var AdapterInterface
15
     */
16
    protected $adapter;
17
18
    /**
19
     * Schema name
20
     * @var string
21
     */
22
    protected $schema;
23
24
    /**
25
     * {@inheritdoc}
26
     */
27 23
    public function __construct(AdapterInterface $adapter, $schema)
28
    {
29 23
        parent::__construct($adapter, $schema);
30 23
    }
31
32
    /**
33
     * {@inheritdoc}
34
     * @throws Exception\ErrorException
35
     */
36 4
    public function getSchemaConfig($table = null, $include_options = true)
37
    {
38 4
        $results = $this->executeQuery($table);
39
40 4
        $references = [];
41 4
        $config = new Config(['tables' => []], true);
42 4
        $tables = $config->offsetGet('tables');
43
44 4
        foreach ($results as $r) {
45
            // Setting table information
46 1
            $table_name = $r['table_name'];
47 1
            if (!$tables->offsetExists($table_name)) {
48
                $table_def = [
49 1
                    'name'          => $table_name,
50 1
                    'columns'       => [],
51 1
                    'primary_keys'  => [],
52 1
                    'unique_keys'   => [],
53 1
                    'foreign_keys'  => [],
54 1
                    'references'    => [],
55 1
                    'indexes'       => [],
56 1
                ];
57 1
                if ($include_options) {
58 1
                    $table_def['options'] = [
59 1
                       'comment'   => $r['table_comment'],
60 1
                       'collation' => $r['table_collation'],
61 1
                       'type'      => $r['table_type'],
62 1
                       'engine'    => $r['engine']
63 1
                    ];
64 1
                }
65 1
                $tables->offsetSet($table_name, $table_def);
66 1
            }
67 1
            $table   = $tables->offsetGet($table_name);
68 1
            $columns = $table->columns;
69 1
            $column_name = $r['column_name'];
70
71 1
            $data_type = strtolower($r['data_type']);
72
73
            $col_def = [
74 1
                'type'          => $data_type,
75 1
                'primary'       => ($r['constraint_type'] == 'PRIMARY KEY'),
76 1
                'nullable'      => ($r['is_nullable'] == 'YES'),
77 1
                'default'       => $r['column_default']
78 1
            ];
79 1
            if (($r['constraint_type'] == 'PRIMARY KEY')) {
80 1
                $col_def['primary'] = true;
81 1
                $col_def['autoincrement'] = ($r['extra'] == 'auto_increment');
82 1
            }
83
84 1
            $has_charset = false;
85 1
            if (in_array($data_type, ['int', 'tinyint', 'mediumint', 'bigint', 'int', 'smallint', 'year'])) {
86 1
                $col_def['unsigned']  = (bool) preg_match('/unsigned/', strtolower($r['column_type']));
87 1
                $col_def['precision'] = is_numeric($r['numeric_precision']) ? (int) $r['numeric_precision'] : null;
88 1
            } elseif (in_array($data_type, ['real', 'double precision', 'decimal', 'numeric', 'float', 'dec', 'fixed'])) {
89 1
                $col_def['precision'] = is_numeric($r['numeric_precision']) ? (int) $r['numeric_precision'] : null;
90 1
                $col_def['scale']     = is_numeric($r['numeric_scale']) ? (int) $r['numeric_scale'] : null;
91 1
            } elseif (in_array($data_type, ['timestamp', 'date', 'time', 'datetime'])) {
92
                // nothing yet
93 1
            } elseif (in_array($data_type, ['char', 'varchar', 'binary', 'varbinary', 'text', 'tinytext', 'mediumtext', 'longtext'])) {
94 1
                $col_def['octet_length'] = is_numeric($r['character_octet_length']) ? (int) $r['character_octet_length'] : null;
95 1
                $col_def['length'] = is_numeric($r['character_maximum_length']) ? (int) $r['character_maximum_length'] : null;
96 1
                $has_charset = true;
97 1
            } elseif (in_array($data_type, ['blob', 'tinyblob', 'mediumblob', 'longblob'])) {
98 1
                $col_def['octet_length'] = (int) $r['character_octet_length'];
99 1
                $col_def['length'] = (int) $r['character_maximum_length'];
100 1
            } elseif (in_array($data_type, ['enum', 'set'])) {
101 1
                $col_def['octet_length'] = (int) $r['character_octet_length'];
102 1
                $col_def['length'] = (int) $r['character_maximum_length'];
103 1
                $def = $r['column_type'];
104
105 1
                preg_match_all("/'([^']+)'/", $def, $matches);
106 1
                if (is_array($matches[1]) && count($matches) > 0) {
107 1
                    $col_def['values'] = $matches[1];
108 1
                }
109 1
            }
110
111 1
            if ($include_options) {
112 1
                $col_def['options'] = [
113 1
                        'comment'           => $r['column_comment'],
114 1
                        'definition'        => $r['column_type'],
115 1
                        'column_key'        => $r['column_key'],
116 1
                        'ordinal_position'  => $r['ordinal_position'],
117 1
                        'constraint_type'   => $r['constraint_type'], // 'PRIMARY KEY', 'FOREIGN_KEY', 'UNIQUE'
118
                    ];
119 1
                if ($has_charset) {
120 1
                    $col_def['options']['charset']     = $r['character_set_name'];
121 1
                    $col_def['options']['collation']   = $r['collation_name'];
122 1
                }
123 1
            }
124
125 1
            $columns[$column_name] = $col_def;
126
127 1
            $foreign_keys = $table->foreign_keys;
128 1
            $unique_keys  = $table->unique_keys;
129
130 1
            $constraint_name = $r['constraint_name'];
131 1
            $referenced_table_name = $r['referenced_table_name'];
132 1
            $referenced_column_name = $r['referenced_column_name'];
133 1
            switch ($r['constraint_type']) {
134 1
                case 'PRIMARY KEY':
135 1
                    $table->primary_keys = array_merge($table->primary_keys->toArray(), (array) $column_name);
136 1
                    break;
137 1
                case 'UNIQUE':
138 1
                    if (!$unique_keys->offsetExists($constraint_name)) {
139 1
                        $unique_keys[$constraint_name] = [];
140 1
                    }
141 1
                    $unique_keys[$constraint_name] = array_merge($unique_keys[$constraint_name]->toArray(), (array) $column_name);
142 1
                    break;
143 1
                case 'FOREIGN KEY':
144
                    /*
145
                    if (!$foreign_keys->offsetExists($constraint_name)) {
146
                        $foreign_keys[$constraint_name] = array();
147
                    }
148
                     *
149
                     */
150
                    $fk = [
151 1
                       'referenced_table'  => $referenced_table_name,
152 1
                       'referenced_column' => $referenced_column_name,
153
                       'constraint_name' => $constraint_name
154 1
                    ];
155 1
                    $foreign_keys[$column_name] = $fk;
156
                    //$table->references[$referenced_table_name] = array($column_name => $r['referenced_column_name']);
157
158 1
                    if (!array_key_exists($referenced_table_name, $references)) {
159 1
                        $references[$referenced_table_name] = [];
160 1
                    }
161
162 1
                    $k = "$table_name:$referenced_column_name->$column_name";
163 1
                    $references[$referenced_table_name][$k] = [
164 1
                        'column' => $column_name,
165 1
                        'referencing_table' => $table_name,
166 1
                        'referencing_column' => $referenced_column_name,
167
                        'constraint_name' => $constraint_name
168 1
                    ];
169 1
                    break;
170 1
            }
171 4
        }
172
173 4
        foreach ($references as $referenced_table_name => $refs) {
174 1
            if ($tables->offsetExists($referenced_table_name)) {
175 1
                $table = $tables[$referenced_table_name];
176 1
                $table->references = $refs;
177 1
            }
178 4
        }
179
180 4
        $array = new ArrayObject($config->toArray());
181 4
        unset($config);
182 4
        return $array;
183
    }
184
185
    /**
186
     * Return information schema query
187
     *
188
     * @param string|null $table
189
     * @return string
190
     */
191 4
    protected function getQuery($table = null)
192
    {
193 4
        $qSchema = $this->adapter->quoteValue($this->schema);
194
195 4
        if ($table !== null) {
196 2
            $qTable = $this->adapter->quoteValue($table);
197 2
            $table_clause = "and (t.TABLE_NAME = $qTable or (kcu.referenced_table_name = $qTable and kcu.constraint_name = 'FOREIGN KEY'))";
198 2
            $table_join_condition = "(t.table_name = kcu.table_name or  kcu.referenced_table_name = t.table_name)";
199 2
        } else {
200 2
            $table_join_condition = "t.table_name = kcu.table_name";
201 2
            $table_clause = '';
202
        }
203
204
        $query = "
205
206
            SELECT
207
                    t.table_name,
208
                    c.column_name,
209
                    c.data_type,
210
                    c.column_type,
211
212
                    c.extra,
213
214
                    tc.constraint_type,
215
                    kcu.constraint_name,
216
                    kcu.referenced_table_name,
217
                    kcu.referenced_column_name,
218
219
                    c.column_default,
220
                    c.is_nullable,
221
                    c.numeric_precision,
222
                    c.numeric_scale,
223
                    c.character_octet_length,
224
                    c.character_maximum_length,
225
                    c.ordinal_position,
226
227
                    c.column_key, -- UNI/MUL/PRI
228
                    c.character_set_name,
229
230
231
                    c.collation_name,
232
233
                    c.column_comment,
234
235
                    t.table_type,
236
                    t.engine,
237
                    t.table_comment,
238
                    t.table_collation
239
240
            FROM `INFORMATION_SCHEMA`.`COLUMNS` c
241
            INNER JOIN `INFORMATION_SCHEMA`.`TABLES` t on c.TABLE_NAME = t.TABLE_NAME
242
            LEFT JOIN `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE` kcu
243
               on (
244
                    $table_join_condition
245
                     and kcu.table_schema = t.table_schema
246
                     and kcu.column_name = c.column_name
247
                 )
248
              LEFT JOIN
249
                `INFORMATION_SCHEMA`.`TABLE_CONSTRAINTS` tc
250
               on (
251
                     t.table_name = tc.table_name
252
                      and tc.table_schema = t.table_schema
253
                      and tc.constraint_name = kcu.constraint_name
254
                  )
255
256
257 4
            where c.TABLE_SCHEMA = $qSchema
258 4
            and t.TABLE_SCHEMA = $qSchema
259 4
            $table_clause
260 4
            and (kcu.table_schema = $qSchema  or kcu.table_schema is null)
261
262
            and (kcu.column_name = c.column_name or kcu.column_name is null)
263
            order by t.table_name, c.ordinal_position
264 4
        ";
265
266 4
        return $query;
267
    }
268
269
    /**
270
     * Execute information schema query
271
     *
272
     * @param string|null $table table name or null
273
     * @return ArrayObject
274
     * @throws Exception\ErrorException
275
     */
276 4
    protected function executeQuery($table = null)
277
    {
278 4
        $query = $this->getQuery($table);
279 4
        $this->disableInnoDbStats();
280
        try {
281 4
            $results = $this->adapter->query($query);
282 4
        } catch (\Exception $e) {
283
            $this->restoreInnoDbStats();
284
            throw new Exception\ErrorException(__METHOD__ . ": " . $e->getMessage());
285
        }
286 4
        $this->restoreInnoDbStats();
287 4
        return $results;
288
    }
289
}
290