TypeTrait   C
last analyzed

Complexity

Total Complexity 55

Size/Duplication

Total Lines 533
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 185
c 0
b 0
f 0
dl 0
loc 533
rs 6
wmc 55

10 Methods

Rating   Name   Duplication   Size   Complexity  
A dropType() 0 13 2
A getType() 0 8 1
B createEnumType() 0 47 7
B createType() 0 51 7
A getTypes() 0 40 4
A getConversions() 0 18 1
A getCasts() 0 38 2
A getEnumValues() 0 9 1
F createCompositeType() 0 117 21
B formatType() 0 46 9

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