Completed
Pull Request — master (#4)
by James Ekow Abaka
02:32 queued 01:18
created

Descriptor::describeViews()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 9
cts 9
cp 1
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/*
4
 * The MIT License
5
 *
6
 * Copyright 2014-2018 James Ekow Abaka Ainooson
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
namespace ntentan\atiaa;
28
29
/**
30
 * Does the job of describing the schema of the underlying database. This
31
 * abstract class is usually extended by database platform specific descriptor
32
 * classes which provide the details of the actual database items. The main work
33
 * of this class is to format the description into a common format.
34
 */
35
abstract class Descriptor
36
{
37
    /**
38
     * An instance of the database driver used for accessing the database
39
     * system.
40
     *
41
     * @var \ntentan\atiaa\Driver;
42
     */
43
    protected $driver;
44
    private $cleanDefaults = false;
45
46 15
    public function __construct($driver)
47
    {
48 15
        $this->driver = $driver;
49 15
    }
50
51
    /**
52
     * Returns a list of schemata available on the database.
53
     *
54
     * @return array
55
     */
56
    abstract protected function getSchemata();
57
58
    /**
59
     * Retrieve the names of all the tables in a given schema.
60
     * The array returned must be a list of structured arrays which have `name`
61
     * and `schema` as keys. The `name` key should represent the name of the table and
62
     * the `schema` key should represent the name of the schema (which is the same
63
     * as the schema which was passed to the function).
64
     *
65
     * @param string $schema The name of the schema whose tables should be
66
     *                       describled.
67
     * @param array<string> An array contianing names of specific tables
68
     *     who's descriptions should be retrieved.
69
     *
70
     * @return array<array>
71
     */
72
    abstract protected function getTables($schema, $requestedTables, $includeViews);
73
74
    /**
75
     * Retrieve descriptions of all the columns available in a given table as an array.
76
     * The array returned must contain structured arrays with the following keys.
77
     *
78
     * name
79
     * : The name of the column.
80
     *
81
     * type
82
     * : The system specific datatype of the column.
83
     *
84
     * nulls
85
     * : A boolean which is true for columsn which can contain null values
86
     *   and false for columns which can't.
87
     *
88
     * default
89
     * : The default value of the column. In cases where there is no default
90
     *   this column is set to null.
91
     *
92
     * length
93
     * : The maximum character lenght of the column.
94
     *
95
     * @param array $table An array which contains the name of the table as it's
96
     *                     `name` key and the schema of the table as it's `schema` key.
97
     *
98
     * @return array<array<string>>
99
     */
100
    abstract protected function getColumns(&$table);
101
102
    /**
103
     * Retrieve the descriptions of all the views of a given schema in a array.
104
     * The array returned must contain structured arrays with the following keys.
105
     *
106
     * name
107
     * : The name of the view.
108
     *
109
     * schema
110
     * : The schema to which the view belongs.
111
     *
112
     * definition
113
     * : The SQL query which represents the definition of the view.
114
     *
115
     * @param string $schema The name of the database schema
116
     *
117
     * @return array<array<string>>
118
     */
119
    abstract protected function getViews(&$schema);
120
121
    /**
122
     * Retrieve the description of a primary key on a given table.
123
     * The description returned must be an array which contains structured
124
     * arrays with the following keys.
125
     *
126
     * column
127
     * : The name of a column which is part of the primary key
128
     *
129
     * name
130
     * : The name of the primary key constraint (must be the same throughout
131
     *   all the items returned).
132
     *
133
     * For primary keys with multiple columns, the array returned would contain
134
     * one entry for each column.
135
     *
136
     * @param array $table An array which contains the name of the table as it's
137
     *                     `name` key and the schema of the table as it's `schema` key.
138
     *
139
     * @return array<array<string>>
140
     */
141
    abstract protected function getPrimaryKey(&$table);
142
143
    /**
144
     * Retrieve the description of unique keys on a given table.
145
     * The description returned must be an array which contains structured
146
     * arrays with the following keys.
147
     *
148
     * column
149
     * : The name of a column which is part of a unique key
150
     *
151
     * name
152
     * : The name of the unique key constraint.
153
     *
154
     * For unique keys with multiple columns, the value of the `name` key must
155
     * be the same for only the columns in the key.
156
     *
157
     * @param array $table An array which contains the name of the table as it's
158
     *                     `name` key and the schema of the table as it's `schema` key.
159
     *
160
     * @return array<array<string>>
161
     */
162
    abstract protected function getUniqueKeys(&$table);
163
164
    /**
165
     * Retrieve the description of foreign keys on a given table.
166
     * The description returned must be an array which contains structured
167
     * arrays with the following keys.
168
     *
169
     * name
170
     * : The name of the foreign key constraint.
171
     *
172
     * table
173
     * : The name of the database table (should be same as passed to the function)
174
     *
175
     * schema
176
     * : The schema of the database table (should be same as passed to the
177
     *   function)
178
     *
179
     * column
180
     * : The foreign key column on the table.
181
     *
182
     * foreign_table
183
     * : The name of the database table to be referenced.
184
     *
185
     * foreign_schema
186
     * : The schema which contains the database table to be referenced.
187
     *
188
     * foreign_column:
189
     * : The column to be refereced on the foreign table.
190
     *
191
     * For foreign keys with multiple columns, the value of the `name` key must
192
     * be the same for only the columns in the key.
193
     *
194
     * @param array $table An array which contains the name of the table as it's
195
     *                     `name` key and the schema of the table as it's `schema` key.
196
     *
197
     * @return array<array<string>>
198
     */
199
    abstract protected function getForeignKeys(&$table);
200
201
    /**
202
     * Retrieve the description of indices on a given table.
203
     * The description returned must be an array which contains structured
204
     * arrays with the following keys.
205
     *
206
     * column
207
     * : The name of a column which is part of an index
208
     *
209
     * name
210
     * : The name of the index.
211
     *
212
     * For unique keys with multiple columns, the value of the `name` key must
213
     * be the same for only the columns in the key.
214
     *
215
     * @param array $table An array which contains the name of the table as it's
216
     *                     `name` key and the schema of the table as it's `schema` key.
217
     *
218
     * @return array<array<string>>
219
     */
220
    abstract protected function getIndices(&$table);
221
222
    /**
223
     * Returns a boolean value which tells whether a table has an auto incrementing
224
     * key or not.
225
     *
226
     * @return bool
227
     */
228
    abstract protected function hasAutoIncrementingKey(&$table);
229
230
    /**
231
     * Returns the description of the database as an array.
232
     *
233
     * @return array
234
     */
235 6
    public function describe()
236
    {
237 6
        $defaultSchema = $this->driver->getDefaultSchema();
238
        $description = [
239 6
            'schemata' => [],
240
        ];
241
242 6
        $schemata = $this->getSchemata();
243
244 6
        foreach ($schemata as $schema) {
245 6
            if ($schema['name'] == $defaultSchema) {
246 6
                $description['tables'] = $this->describeTables($defaultSchema);
247 6
                $description['views'] = $this->describeViews($defaultSchema);
248
            } else {
249
                $description['schemata'][$schema['name']]['name'] = $schema['name'];
250
                $description['schemata'][$schema['name']]['tables'] = $this->describeTables($schema['name']);
251 6
                $description['schemata'][$schema['name']]['views'] = $this->describeViews($schema['name']);
252
            }
253
        }
254
255 6
        return $description;
256
    }
257
258 3
    public function setCleanDefaults($cleanDefaults)
259
    {
260 3
        $this->cleanDefaults = $cleanDefaults;
261 3
    }
262
263
    /**
264
     * Throws exceptions for which are found in the list of requested tables
265
     * but not found in the list of found tables.
266
     *
267
     * @param array $tables
268
     * @param array $requestedTables
269
     *
270
     * @throws exceptions\TableNotFoundException
271
     */
272 6
    private function throwTableExceptions($tables, $requestedTables)
273
    {
274 6
        $foundTables = [];
275 6
        foreach ($tables as $table) {
276 3
            $foundTables[] = $table['name'];
277
        }
278
279 6
        foreach ($requestedTables as $requestedTable) {
280 6
            if (array_search($requestedTable, $foundTables) === false) {
281 6
                throw new exceptions\TableNotFoundException($requestedTable
282 6
                    ? "$requestedTable not found on target database."
283 6
                    : 'Please specify a table name.'
284
                );
285
            }
286
        }
287
    }
288
289 15
    public function describeTables($schema, $requestedTables = [], $includeViews = false)
290
    {
291 15
        $description = [];
292 15
        $tables = $this->getTables($schema, $requestedTables, $includeViews);
293
294 15
        if (count($requestedTables) > 0 && count($tables) < count($requestedTables)) {
295 6
            $this->throwTableExceptions($tables, $requestedTables);
296
        }
297
298 9
        foreach ($tables as $table) {
299 9
            $table['columns'] = $this->describeColumns($table);
300 9
            $table['primary_key'] = $this->describePrimaryKey($table);
301 9
            $table['unique_keys'] = $this->describeUniqueKeys($table);
302 9
            $table['foreign_keys'] = $this->describeForeignKeys($table);
303 9
            $table['indices'] = $this->describeIndices($table);
304 9
            $table['auto_increment'] = $this->hasAutoIncrementingKey($table);
305 9
            $table['schema'] = $this->fixSchema($table['schema']);
306
307 9
            $description[$table['name']] = $table;
308
        }
309
310 9
        return $description;
311
    }
312
313 9
    private function describeColumns($table)
314
    {
315 9
        $columns = [];
316 9
        $columnDetails = $this->getColumns($table);
317 9
        foreach ($columnDetails as $column) {
318 9
            $columns[$column['name']] = $column;
319 9
            $columns[$column['name']]['nulls'] = $columns[$column['name']]['nulls'] == 'YES' ? true : false;
320
321 9
            if ($this->cleanDefaults) {
322 9
                $columns[$column['name']]['default'] = $this->cleanDefaultValue($column['default']);
323
            }
324
        }
325
326 9
        return $columns;
327
    }
328
329 6
    private function describeViews($schema)
330
    {
331 6
        $description = [];
332 6
        $views = $this->getViews($schema);
333 6
        foreach ($views as $view) {
334 6
            $description[$view['name']] = [
335 6
                'name'       => $view['name'],
336 6
                'schema'     => $view['schema'],
337 6
                'definition' => $view['definition'],
338
            ];
339
        }
340
341 6
        return $description;
342
    }
343
344 9
    private function describePrimaryKey($table)
345
    {
346 9
        return $this->describeKey($this->getPrimaryKey($table));
347
    }
348
349 9
    private function describeUniqueKeys($table)
350
    {
351 9
        return $this->describeKey($this->getUniqueKeys($table));
352
    }
353
354 9
    private function describeForeignKeys($table)
355
    {
356 9
        return $this->describeKey($this->getForeignKeys($table));
357
    }
358
359 9
    private function describeIndices($table)
360
    {
361 9
        return $this->describeKey($this->getIndices($table));
362
    }
363
364 9
    private function describeKey($constraintColumns)
365
    {
366 9
        $constraints = [];
367 9
        foreach ($constraintColumns as $column) {
368 6
            $name = $column['name'];
369 6
            unset($column['name']);
370 6
            foreach ($column as $key => $value) {
371 6
                if ($key == 'column' || $key == 'foreign_column') {
372 6
                    $constraints[$name]["{$key}s"][] = $value;
373
                } else {
374 6
                    if ($key === 'schema' || $key === 'foreign_schema') {
375 6
                        $value = $this->fixSchema($value);
376
                    }
377 6
                    $constraints[$name][$key] = $value;
378
                }
379
            }
380
        }
381
382 9
        return $constraints;
383
    }
384
385 9
    private function fixSchema($schema)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
386
    {
387 9
        $defaultSchema = $this->driver->getDefaultSchema();
388 9
        if ($schema == false || $schema == $defaultSchema) {
389 9
            return '';
390
        } else {
391
            return $schema;
392
        }
393
    }
394
395 1
    protected function cleanDefaultValue($defaultValue)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
396
    {
397 1
        return $defaultValue;
398
    }
399
}
400