Passed
Push — develop ( 2d5edd...a33225 )
by Felipe
05:40
created

TypeTrait   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 514
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 55
dl 0
loc 514
rs 6
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
F createCompositeType() 0 108 21
D formatType() 0 42 9
A getConversions() 0 18 1
A getType() 0 8 1
B getTypes() 0 39 4
B getCasts() 0 38 2
A getEnumValues() 0 9 1
C createEnumType() 0 44 7
A dropType() 0 12 2
C createType() 0 50 7

How to fix   Complexity   

Complex Class

Complex classes like TypeTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TypeTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.47
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
/**
10
 * Common trait for types manipulation.
11
 */
12
trait TypeTrait
13
{
14
    /**
15
     * Formats a type correctly for display.  Postgres 7.0 had no 'format_type'
16
     * built-in function, and hence we need to do it manually.
17
     *
18
     * @param string $typname The name of the type
19
     * @param string $typmod  The contents of the typmod field
20
     *
21
     * @return bool|string
22
     */
23
    public function formatType($typname, $typmod)
24
    {
25
        // This is a specific constant in the 7.0 source
26
        $varhdrsz = 4;
27
28
        // If the first character is an underscore, it's an array type
29
        $is_array = false;
30
        if (substr($typname, 0, 1) == '_') {
31
            $is_array = true;
32
            $typname  = substr($typname, 1);
33
        }
34
35
        // Show lengths on bpchar and varchar
36
        if ($typname == 'bpchar') {
37
            $len  = $typmod - $varhdrsz;
38
            $temp = 'character';
39
            if ($len > 1) {
40
                $temp .= "({$len})";
41
            }
42
        } elseif ($typname == 'varchar') {
43
            $temp = 'character varying';
44
            if ($typmod != -1) {
45
                $temp .= '('.($typmod - $varhdrsz).')';
46
            }
47
        } elseif ($typname == 'numeric') {
48
            $temp = 'numeric';
49
            if ($typmod != -1) {
50
                $tmp_typmod = $typmod - $varhdrsz;
51
                $precision  = ($tmp_typmod >> 16) & 0xffff;
52
                $scale      = $tmp_typmod & 0xffff;
53
                $temp .= "({$precision}, {$scale})";
54
            }
55
        } else {
56
            $temp = $typname;
57
        }
58
59
        // Add array qualifier if it's an array
60
        if ($is_array) {
61
            $temp .= '[]';
62
        }
63
64
        return $temp;
65
    }
66
67
    /**
68
     * Returns all details for a particular type.
69
     *
70
     * @param string $typname The name of the view to retrieve
71
     *
72
     * @return \PHPPgAdmin\ADORecordSet type info
73
     */
74
    public function getType($typname)
75
    {
76
        $this->clean($typname);
77
78
        $sql = "SELECT typtype, typbyval, typname, typinput AS typin, typoutput AS typout, typlen, typalign
79
            FROM pg_type WHERE typname='{$typname}'";
80
81
        return $this->selectSet($sql);
82
    }
83
84
    /**
85
     * Returns a list of all types in the database.
86
     *
87
     * @param bool $all        If true, will find all available types, if false just those in search path
88
     * @param bool $tabletypes If true, will include table types
89
     * @param bool $domains    If true, will include domains
90
     *
91
     * @return \PHPPgAdmin\ADORecordSet A recordset
92
     */
93
    public function getTypes($all = false, $tabletypes = false, $domains = false)
94
    {
95
        if ($all) {
96
            $where = '1 = 1';
97
        } else {
98
            $c_schema = $this->_schema;
99
            $this->clean($c_schema);
100
            $where = "n.nspname = '{$c_schema}'";
101
        }
102
        // Never show system table types
103
        $where2 = "AND c.relnamespace NOT IN (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname LIKE 'pg@_%' ESCAPE '@')";
104
105
        // Create type filter
106
        $tqry = "'c'";
107
        if ($tabletypes) {
108
            $tqry .= ", 'r', 'v'";
109
        }
110
111
        // Create domain filter
112
        if (!$domains) {
113
            $where .= " AND t.typtype != 'd'";
114
        }
115
116
        $sql = "SELECT
117
                t.typname AS basename,
118
                pg_catalog.format_type(t.oid, NULL) AS typname,
119
                pu.usename AS typowner,
120
                t.typtype,
121
                pg_catalog.obj_description(t.oid, 'pg_type') AS typcomment
122
            FROM (pg_catalog.pg_type t
123
                LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace)
124
                LEFT JOIN pg_catalog.pg_user pu ON t.typowner = pu.usesysid
125
            WHERE (t.typrelid = 0 OR (SELECT c.relkind IN ({$tqry}) FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid {$where2}))
126
            AND t.typname !~ '^_'
127
            AND {$where}
128
            ORDER BY typname
129
        ";
130
131
        return $this->selectSet($sql);
132
    }
133
134
    /**
135
     * Creates a new type.
136
     *
137
     * @param string $typname
138
     * @param string $typin
139
     * @param string $typout
140
     * @param string $typlen
141
     * @param string $typdef
142
     * @param string $typelem
143
     * @param string $typdelim
144
     * @param string $typbyval
145
     * @param string $typalign
146
     * @param string $typstorage
147
     *
148
     * @return int 0 if operation was successful
149
     *
150
     * @internal param $ ...
151
     */
152
    public function createType(
153
        $typname,
154
        $typin,
155
        $typout,
156
        $typlen,
157
        $typdef,
158
        $typelem,
159
        $typdelim,
160
        $typbyval,
161
        $typalign,
162
        $typstorage
163
    ) {
164
        $f_schema = $this->_schema;
165
        $this->fieldClean($f_schema);
166
        $this->fieldClean($typname);
167
        $this->fieldClean($typin);
168
        $this->fieldClean($typout);
169
170
        $sql = "
171
            CREATE TYPE \"{$f_schema}\".\"{$typname}\" (
172
                INPUT = \"{$typin}\",
173
                OUTPUT = \"{$typout}\",
174
                INTERNALLENGTH = {$typlen}";
175
        if ($typdef != '') {
176
            $sql .= ", DEFAULT = {$typdef}";
177
        }
178
179
        if ($typelem != '') {
180
            $sql .= ", ELEMENT = {$typelem}";
181
        }
182
183
        if ($typdelim != '') {
184
            $sql .= ", DELIMITER = {$typdelim}";
185
        }
186
187
        if ($typbyval) {
188
            $sql .= ', PASSEDBYVALUE, ';
189
        }
190
191
        if ($typalign != '') {
192
            $sql .= ", ALIGNMENT = {$typalign}";
193
        }
194
195
        if ($typstorage != '') {
196
            $sql .= ", STORAGE = {$typstorage}";
197
        }
198
199
        $sql .= ')';
200
201
        return $this->execute($sql);
202
    }
203
204
    /**
205
     * Drops a type.
206
     *
207
     * @param string $typname The name of the type to drop
208
     * @param bool   $cascade True to cascade drop, false to restrict
209
     *
210
     * @return int 0 if operation was successful
211
     */
212
    public function dropType($typname, $cascade)
213
    {
214
        $f_schema = $this->_schema;
215
        $this->fieldClean($f_schema);
216
        $this->fieldClean($typname);
217
218
        $sql = "DROP TYPE \"{$f_schema}\".\"{$typname}\"";
219
        if ($cascade) {
220
            $sql .= ' CASCADE';
221
        }
222
223
        return $this->execute($sql);
224
    }
225
226
    /**
227
     * Creates a new enum type in the database.
228
     *
229
     * @param string $name       The name of the type
230
     * @param array  $values     An array of values
231
     * @param string $typcomment Type comment
232
     *
233
     * @return bool|int 0 success
234
     */
235
    public function createEnumType($name, $values, $typcomment)
236
    {
237
        $f_schema = $this->_schema;
238
        $this->fieldClean($f_schema);
239
        $this->fieldClean($name);
240
241
        if (empty($values)) {
242
            return -2;
243
        }
244
245
        $status = $this->beginTransaction();
246
        if ($status != 0) {
247
            return -1;
248
        }
249
250
        $values = array_unique($values);
251
252
        $nbval = count($values);
253
254
        for ($i = 0; $i < $nbval; ++$i) {
255
            $this->clean($values[$i]);
256
        }
257
258
        $sql = "CREATE TYPE \"{$f_schema}\".\"{$name}\" AS ENUM ('";
259
        $sql .= implode("','", $values);
260
        $sql .= "')";
261
262
        $status = $this->execute($sql);
263
        if ($status) {
264
            $this->rollbackTransaction();
265
266
            return -1;
267
        }
268
269
        if ($typcomment != '') {
270
            $status = $this->setComment('TYPE', $name, '', $typcomment, true);
271
            if ($status) {
272
                $this->rollbackTransaction();
273
274
                return -1;
275
            }
276
        }
277
278
        return $this->endTransaction();
279
    }
280
281
    /**
282
     * Get defined values for a given enum.
283
     *
284
     * @param string $name
285
     *
286
     * @return \PHPPgAdmin\ADORecordSet A recordset
287
     */
288
    public function getEnumValues($name)
289
    {
290
        $this->clean($name);
291
292
        $sql = "SELECT enumlabel AS enumval
293
        FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON (t.oid=e.enumtypid)
294
        WHERE t.typname = '{$name}' ORDER BY e.oid";
295
296
        return $this->selectSet($sql);
297
    }
298
299
    // Operator functions
300
301
    /**
302
     * Creates a new composite type in the database.
303
     *
304
     * @param string $name       The name of the type
305
     * @param int    $fields     The number of fields
306
     * @param array  $field      An array of field names
307
     * @param array  $type       An array of field types
308
     * @param array  $array      An array of '' or '[]' for each type if it's an array or not
309
     * @param array  $length     An array of field lengths
310
     * @param array  $colcomment An array of comments
311
     * @param string $typcomment Type comment
312
     *
313
     * @return bool|int 0 success
314
     */
315
    public function createCompositeType($name, $fields, $field, $type, $array, $length, $colcomment, $typcomment)
316
    {
317
        $f_schema = $this->_schema;
318
        $this->fieldClean($f_schema);
319
        $this->fieldClean($name);
320
321
        $status = $this->beginTransaction();
322
        if ($status != 0) {
323
            return -1;
324
        }
325
326
        $found       = false;
327
        $first       = true;
328
        $comment_sql = ''; // Accumulate comments for the columns
329
        $sql         = "CREATE TYPE \"{$f_schema}\".\"{$name}\" AS (";
330
        for ($i = 0; $i < $fields; ++$i) {
331
            $this->fieldClean($field[$i]);
332
            $this->clean($type[$i]);
333
            $this->clean($length[$i]);
334
            $this->clean($colcomment[$i]);
335
336
            // Skip blank columns - for user convenience
337
            if ($field[$i] == '' || $type[$i] == '') {
338
                continue;
339
            }
340
341
            // If not the first column, add a comma
342
            if (!$first) {
343
                $sql .= ', ';
344
            } else {
345
                $first = false;
346
            }
347
348
            switch ($type[$i]) {
349
                // Have to account for weird placing of length for with/without
350
                // time zone types
351
                case 'timestamp with time zone':
352
                case 'timestamp without time zone':
353
                    $qual = substr($type[$i], 9);
354
                    $sql .= "\"{$field[$i]}\" timestamp";
355
                    if ($length[$i] != '') {
356
                        $sql .= "({$length[$i]})";
357
                    }
358
359
                    $sql .= $qual;
360
361
                    break;
362
                case 'time with time zone':
363
                case 'time without time zone':
364
                    $qual = substr($type[$i], 4);
365
                    $sql .= "\"{$field[$i]}\" time";
366
                    if ($length[$i] != '') {
367
                        $sql .= "({$length[$i]})";
368
                    }
369
370
                    $sql .= $qual;
371
372
                    break;
373
                default:
374
                    $sql .= "\"{$field[$i]}\" {$type[$i]}";
375
                    if ($length[$i] != '') {
376
                        $sql .= "({$length[$i]})";
377
                    }
378
            }
379
            // Add array qualifier if necessary
380
            if ($array[$i] == '[]') {
381
                $sql .= '[]';
382
            }
383
384
            if ($colcomment[$i] != '') {
385
                $comment_sql .= "COMMENT ON COLUMN \"{$f_schema}\".\"{$name}\".\"{$field[$i]}\" IS '{$colcomment[$i]}';\n";
386
            }
387
388
            $found = true;
389
        }
390
391
        if (!$found) {
0 ignored issues
show
introduced by
The condition $found is always false.
Loading history...
392
            return -1;
393
        }
394
395
        $sql .= ')';
396
397
        $status = $this->execute($sql);
398
        if ($status) {
399
            $this->rollbackTransaction();
400
401
            return -1;
402
        }
403
404
        if ($typcomment != '') {
405
            $status = $this->setComment('TYPE', $name, '', $typcomment, true);
406
            if ($status) {
407
                $this->rollbackTransaction();
408
409
                return -1;
410
            }
411
        }
412
413
        if ($comment_sql != '') {
414
            $status = $this->execute($comment_sql);
415
            if ($status) {
416
                $this->rollbackTransaction();
417
418
                return -1;
419
            }
420
        }
421
422
        return $this->endTransaction();
423
    }
424
425
    /**
426
     * Returns a list of all casts in the database.
427
     *
428
     * @return \PHPPgAdmin\ADORecordSet All casts
429
     */
430
    public function getCasts()
431
    {
432
        $conf = $this->conf;
433
434
        if ($conf['show_system']) {
435
            $where = '';
436
        } else {
437
            $where = '
438
                AND n1.nspname NOT LIKE $$pg\_%$$
439
                AND n2.nspname NOT LIKE $$pg\_%$$
440
                AND n3.nspname NOT LIKE $$pg\_%$$
441
            ';
442
        }
443
444
        $sql = "
445
            SELECT
446
                c.castsource::pg_catalog.regtype AS castsource,
447
                c.casttarget::pg_catalog.regtype AS casttarget,
448
                CASE WHEN c.castfunc=0 THEN NULL
449
                ELSE c.castfunc::pg_catalog.regprocedure END AS castfunc,
450
                c.castcontext,
451
                obj_description(c.oid, 'pg_cast') as castcomment
452
            FROM
453
                (pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p ON c.castfunc=p.oid JOIN pg_catalog.pg_namespace n3 ON p.pronamespace=n3.oid),
454
                pg_catalog.pg_type t1,
455
                pg_catalog.pg_type t2,
456
                pg_catalog.pg_namespace n1,
457
                pg_catalog.pg_namespace n2
458
            WHERE
459
                c.castsource=t1.oid
460
                AND c.casttarget=t2.oid
461
                AND t1.typnamespace=n1.oid
462
                AND t2.typnamespace=n2.oid
463
                {$where}
464
            ORDER BY 1, 2
465
        ";
466
467
        return $this->selectSet($sql);
468
    }
469
470
    /**
471
     * Returns a list of all conversions in the database.
472
     *
473
     * @return \PHPPgAdmin\ADORecordSet All conversions
474
     */
475
    public function getConversions()
476
    {
477
        $c_schema = $this->_schema;
478
        $this->clean($c_schema);
479
        $sql = "
480
            SELECT
481
                   c.conname,
482
                   pg_catalog.pg_encoding_to_char(c.conforencoding) AS conforencoding,
483
                   pg_catalog.pg_encoding_to_char(c.contoencoding) AS contoencoding,
484
                   c.condefault,
485
                   pg_catalog.obj_description(c.oid, 'pg_conversion') AS concomment
486
            FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n
487
            WHERE n.oid = c.connamespace
488
                  AND n.nspname='{$c_schema}'
489
            ORDER BY 1;
490
        ";
491
492
        return $this->selectSet($sql);
493
    }
494
495
    abstract public function fieldClean(&$str);
496
497
    abstract public function beginTransaction();
498
499
    abstract public function rollbackTransaction();
500
501
    abstract public function endTransaction();
502
503
    abstract public function execute($sql);
504
505
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
506
507
    abstract public function selectSet($sql);
508
509
    abstract public function clean(&$str);
510
511
    abstract public function phpBool($parameter);
512
513
    abstract public function hasCreateTableLikeWithConstraints();
514
515
    abstract public function hasCreateTableLikeWithIndexes();
516
517
    abstract public function hasTablespaces();
518
519
    abstract public function delete($table, $conditions, $schema = '');
520
521
    abstract public function fieldArrayClean(&$arr);
522
523
    abstract public function hasCreateFieldWithConstraints();
524
525
    abstract public function getAttributeNames($table, $atts);
526
}
527