Completed
Push — master ( 5c9c14...d8f82a )
by James Ekow Abaka
05:37
created

Descriptor::throwTableExceptions()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

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