Completed
Push — master ( 5379df...f3c734 )
by Rougin
01:28
created

MySQLDriver::foreign()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
ccs 11
cts 11
cp 1
rs 9.2
cc 3
eloc 11
nc 3
nop 3
crap 3
1
<?php
2
3
namespace Rougin\Describe\Driver;
4
5
use Rougin\Describe\Column;
6
use Rougin\Describe\Exceptions\TableNotFoundException;
7
use Rougin\Describe\Table;
8
9
/**
10
 * MySQL Driver
11
 *
12
 * A database driver extension for MySQL.
13
 * NOTE: Should be renamed to "MySqlDriver" in v2.0.0.
14
 *
15
 * @package Describe
16
 * @author  Rougin Royce Gutib <[email protected]>
17
 */
18
class MySQLDriver implements DriverInterface
19
{
20
    const FOREIGN_QUERY = 'SELECT COLUMN_NAME as "column", REFERENCED_COLUMN_NAME as "referenced_column",' .
21
        'CONCAT(REFERENCED_TABLE_SCHEMA, ".", REFERENCED_TABLE_NAME) as "referenced_table"' .
22
        'FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE ' .
23
        'WHERE CONSTRAINT_SCHEMA = "%s" AND TABLE_NAME = "%s";';
24
25
    /**
26
     * @var string
27
     */
28
    protected $database;
29
30
    /**
31
     * @var \PDO
32
     */
33
    protected $pdo;
34
35 105
    /**
36
     * Initializes the driver instance.
37 105
     *
38
     * @param \PDO   $pdo
39 105
     * @param string $database
40
     */
41 105
    public function __construct(\PDO $pdo, $database)
42 105
    {
43
        $this->database = $database;
44
45
        $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
46
47
        $this->pdo = $pdo;
48
    }
49
50 84
    /**
51
     * Returns an array of Column instances from a table.
52 84
     *
53
     * @param  string $table
54
     * @return \Rougin\Describe\Column[]
55
     */
56
    public function columns($table)
57
    {
58
        return $this->query($table, 'DESCRIBE ' . $table);
59
    }
60
61
    /**
62 48
     * Returns an array of Column instances from a table.
63
     * NOTE: To be removed in v2.0.0. Use columns() instead.
64 48
     *
65
     * @param  string $table
66
     * @return \Rougin\Describe\Column[]
67
     */
68
    public function getColumns($table)
69
    {
70
        return $this->columns($table);
71
    }
72
73
    /**
74 42
     * Returns an array of Column instances from a table.
75
     * NOTE: To be removed in v2.0.0. Use getColumns() instead.
76 42
     *
77
     * @param  string $table
78
     * @return \Rougin\Describe\Column[]
79
     */
80
    public function getTable($table)
81
    {
82
        return $this->getColumns($table);
83
    }
84
85 6
    /**
86
     * Returns an array of table names.
87 6
     * NOTE: To be removed in v2.0.0. Use tables() instead.
88
     *
89
     * @return array
90
     */
91
    public function getTableNames()
92
    {
93
        return $this->items(false);
94
    }
95
96 3
    /**
97
     * Returns an array of table names.
98 3
     * NOTE: To be removed in v2.0.0. Use getTableNames() instead.
99
     *
100
     * @return array
101
     */
102
    public function showTables()
103
    {
104
        return $this->getTableNames();
105
    }
106 12
107
    /**
108 12
     * Returns an array of Table instances.
109
     *
110
     * @return \Rougin\Describe\Table[]
111
     */
112
    public function tables()
113
    {
114
        return $this->items(true);
115
    }
116
117
    /**
118
     * Prepares the defined columns.
119 78
     *
120
     * @param  \Rougin\Describe\Column $column
121 78
     * @param  string                  $table
122
     * @param  mixed                   $row
123 78
     * @return \Rougin\Describe\Column
124
     */
125 78
    protected function column(Column $column, $table, $row)
126
    {
127 78
        preg_match('/(.*?)\((.*?)\)/', $row->Type, $match);
128
129 78
        $column->setDataType($row->Type);
130 78
131
        $column->setDefaultValue($row->Default);
132 78
133 78
        $column->setField($row->Field);
134
135 78
        if (isset($match[1]) === true) {
136
            $column->setDataType($match[1]);
137 78
138
            $column->setLength($match[2]);
139 78
        }
140
141
        $column = $this->properties($row, $column);
142
143
        $column = $this->keys($row, $column);
144
145
        return $this->foreign($table, $row, $column);
146
    }
147
148
    /**
149
     * Sets the properties of a column if it does exists.
150 78
     *
151
     * @param  string                  $name
152
     * @param  mixed                   $row
153 78
     * @param  \Rougin\Describe\Column $column
154 78
     * @return \Rougin\Describe\Column
155 78
     */
156
    protected function foreign($name, $row, Column $column)
157 78
    {
158
        $query = sprintf(self::FOREIGN_QUERY, $this->database, $name);
159 78
160
        $table = $this->pdo->prepare($query);
161 78
162
        $table->execute();
163 78
164 78
        $table->setFetchMode(\PDO::FETCH_OBJ);
165 78
166
        while ($item = $table->fetch()) {
167 78
            if ($item->column === $row->Field) {
168
                $referenced = $this->strip($item->referenced_table);
169 78
170 78
                $column->setReferencedField($item->referenced_column);
171 78
172
                $column->setReferencedTable($referenced);
173 78
            }
174
        }
175
176
        return $column;
177
    }
178
179
    /**
180
     * Returns an array of table names or Table instances.
181
     * NOTE: To be removed in v2.0.0. Move to tables() instead.
182
     *
183
     * @param  boolean $instance
184 18
     * @param  array   $tables
185
     * @return array|\Rougin\Describe\Table[]
186 18
     */
187
    protected function items($instance = false, $tables = array())
188 18
    {
189
        $information = $this->pdo->prepare('SHOW TABLES');
190 18
191
        $information->execute();
192 18
193
        while ($row = $information->fetch()) {
194 18
            // NOTE: To be removed in v2.0.0. Always return Table instance.
195 18
            $instance && $row[0] = new Table($row[0], $this);
196
197 18
            array_push($tables, $row[0]);
198
        }
199
200
        return $tables;
201
    }
202
203
    /**
204
     * Sets the key of a column.
205
     *
206
     * @param  mixed                   $row
207 78
     * @param  \Rougin\Describe\Column $column
208
     * @return \Rougin\Describe\Column
209 78
     */
210 78
    protected function keys($row, Column $column)
211 78
    {
212
        switch ($row->Key) {
213 78
            case 'PRI':
214
                $column->setPrimary(true);
215 78
216 78
                break;
217
            
218 78
            case 'MUL':
219
                $column->setForeign(true);
220 78
221 78
                break;
222
223 78
            case 'UNI':
224 78
                $column->setUnique(true);
225
226 78
                break;
227
        }
228
229
        return $column;
230
    }
231
232
    /**
233
     * Returns the list of columns based on a query.
234
     *
235
     * @param  string $table
236 78
     * @param  string $query
237
     * @param  array  $columns
238 78
     * @return \Rougin\Describe\Column[]
239
     */
240 78
    protected function query($table, $query, $columns = array())
241
    {
242 78
        $result = $this->pdo->prepare($query);
243
244 78
        $result->execute();
245
246
        $result->setFetchMode(\PDO::FETCH_OBJ);
247
248
        while ($row = $result->fetch()) {
249
            $column = $this->column(new Column, $table, $row);
250
251
            array_push($columns, $column);
252
        }
253 78
254
        if (empty($columns) === true) {
255 78
            $message = 'Table "' . $table . '" does not exists!';
256
257 78
            throw new TableNotFoundException($message);
258
        }
259 78
260
        return $columns;
261
    }
262
263
    /**
264
     * Sets the properties of a column.
265
     *
266
     * @param  mixed                   $row
267
     * @param  \Rougin\Describe\Column $column
268
     * @return \Rougin\Describe\Column
269
     */
270
    protected function properties($row, Column $column)
271
    {
272
        $increment = $row->Extra === 'auto_increment';
273
274
        $column->setAutoIncrement($increment);
275
276
        $column->setNull($row->Null === 'YES');
277
278
        return $column;
279
    }
280
281
    /**
282
     * Strips the table schema from the table name.
283
     *
284
     * @param  string $table
285
     * @return string
286
     */
287
    protected function strip($table)
288
    {
289
        $exists = strpos($table, '.') !== false;
290
291
        $updated = substr($table, strpos($table, '.') + 1);
292
293
        return $exists ? $updated : $table;
294
    }
295
}
296