Completed
Branch master (024767)
by Henry Stivens
02:30
created

DbPgSQL   C

Complexity

Total Complexity 75

Size/Duplication

Total Lines 516
Duplicated Lines 42.25 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 218
loc 516
rs 5.5056
c 0
b 0
f 0
wmc 75
lcom 1
cbo 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DbPgSQL 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 DbPgSQL, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * KumbiaPHP web & app Framework
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://wiki.kumbiaphp.com/Licencia
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category   Kumbia
16
 * @package    Db
17
 * @subpackage Adapters
18
 * @copyright  Copyright (c) 2005 - 2017 Kumbia Team (http://www.kumbiaphp.com)
19
 * @license    http://wiki.kumbiaphp.com/Licencia     New BSD License
20
 */
21
22
/**
23
 * PostgreSQL Database Support
24
 *
25
 * @category   Kumbia
26
 * @package    Db
27
 * @subpackage Adapters
28
 */
29
class DbPgSQL extends DbBase implements DbBaseInterface
30
{
31
32
    /**
33
     * Resource de la Conexion a PostgreSQL
34
     *
35
     * @var resource
36
     */
37
    public $id_connection;
38
    /**
39
     * Ultimo Resultado de una Query
40
     *
41
     * @var resource
42
     */
43
    public $last_result_query;
44
    /**
45
     * Ultima sentencia SQL enviada a PostgreSQL
46
     *
47
     * @var string
48
     */
49
    protected $last_query;
50
    /**
51
     * Ultimo error generado por PostgreSQL
52
     *
53
     * @var string
54
     */
55
    public $last_error;
56
57
    /**
58
     * Resultado de Array Asociativo
59
     *
60
     */
61
    const DB_ASSOC = PGSQL_ASSOC;
62
63
    /**
64
     * Resultado de Array Asociativo y Numerico
65
     *
66
     */
67
    const DB_BOTH = PGSQL_BOTH;
68
69
    /**
70
     * Resultado de Array Numerico
71
     *
72
     */
73
    const DB_NUM = PGSQL_NUM;
74
75
76
    /**
77
     * Tipo de Dato Integer
78
     *
79
     */
80
    const TYPE_INTEGER = 'INTEGER';
81
82
    /**
83
     * Tipo de Dato Date
84
     *
85
     */
86
    const TYPE_DATE = 'DATE';
87
88
    /**
89
     * Tipo de Dato Varchar
90
     *
91
     */
92
    const TYPE_VARCHAR = 'VARCHAR';
93
94
    /**
95
     * Tipo de Dato Decimal
96
     *
97
     */
98
    const TYPE_DECIMAL = 'DECIMAL';
99
100
    /**
101
     * Tipo de Dato Datetime
102
     *
103
     */
104
    const TYPE_DATETIME = 'DATETIME';
105
106
    /**
107
     * Tipo de Dato Char
108
     *
109
     */
110
    const TYPE_CHAR = 'CHAR';
111
112
    /**
113
     * Hace una conexion a la base de datos de PostgreSQL
114
     *
115
     * @param array $config
116
     * @return bool
117
     */
118
    public function connect($config)
119
    {
120
121
        if (!extension_loaded('pgsql')) {
122
            throw new KumbiaException('Debe cargar la extensión de PHP llamada php_pgsql');
123
        }
124
125
        if (!isset($config['port']) || !$config['port']) {
126
            $config['port'] = 5432;
127
        }
128
129
        if ($this->id_connection = pg_connect("host={$config['host']} user={$config['username']} password={$config['password']} dbname={$config['name']} port={$config['port']}", PGSQL_CONNECT_FORCE_NEW)) {
130
            return true;
131
        } else {
132
            throw new KumbiaException($this->error("No se puede conectar a la base de datos"));
133
        }
134
    }
135
136
    /**
137
     * Efectua operaciones SQL sobre la base de datos
138
     *
139
     * @param string $sqlQuery
140
     * @return resource or false
141
     */
142
    function query($sqlQuery)
143
    {
144
        $this->debug($sqlQuery);
145
        if ($this->logger) {
146
            Logger::debug($sqlQuery);
147
        }
148
149
        $this->last_query = $sqlQuery;
150
        if ($resultQuery = @pg_query($this->id_connection, $sqlQuery)) {
151
            $this->last_result_query = $resultQuery;
152
            return $resultQuery;
153
        } else {
154
            throw new KumbiaException($this->error(" al ejecutar <em>'$sqlQuery'</em>"));
155
        }
156
    }
157
158
    /**
159
     * Cierra la Conexión al Motor de Base de datos
160
     */
161
    function close()
162
    {
163
        if ($this->id_connection) {
164
            return pg_close($this->id_connection);
165
        } else {
166
            return false;
167
        }
168
    }
169
170
    /**
171
     * Devuelve fila por fila el contenido de un select
172
     *
173
     * @param resource $resultQuery
174
     * @param int $opt
175
     * @return array
176
     */
177
    function fetch_array($resultQuery=NULL, $opt=PGSQL_BOTH)
178
    {
179
180
        if (!$resultQuery) {
181
            $resultQuery = $this->last_result_query;
182
            if (!$resultQuery) {
183
                return false;
184
            }
185
        }
186
        return pg_fetch_array($resultQuery, NULL, $opt);
187
    }
188
189
    /**
190
     * Constructor de la Clase
191
     *
192
     * @param array $config
193
     */
194
    function __construct($config)
195
    {
196
        $this->connect($config);
197
    }
198
199
    /**
200
     * Devuelve el numero de filas de un select
201
     */
202
    function num_rows($resultQuery=NULL)
203
    {
204
205
        if (!$resultQuery) {
206
            $resultQuery = $this->last_result_query;
207
            if (!$resultQuery) {
208
                return false;
209
            }
210
        }
211
        if (($numberRows = pg_num_rows($resultQuery)) !== false) {
212
            return $numberRows;
213
        } else {
214
            throw new KumbiaException($this->error());
215
        }
216
    }
217
218
    /**
219
     * Devuelve el nombre de un campo en el resultado de un select
220
     *
221
     * @param int $number
222
     * @param resource $resultQuery
223
     * @return string
224
     */
225
    function field_name($number, $resultQuery=NULL)
226
    {
227
228
        if (!$resultQuery) {
229
            $resultQuery = $this->last_result_query;
230
            if (!$resultQuery) {
231
                return false;
232
            }
233
        }
234
        if (($fieldName = pg_field_name($resultQuery, $number)) !== false) {
235
            return $fieldName;
236
        } else {
237
            throw new KumbiaException($this->error());
238
        }
239
    }
240
241
    /**
242
     * Se Mueve al resultado indicado por $number en un select
243
     *
244
     * @param int $number
245
     * @param resource $resultQuery
246
     * @return boolean
247
     */
248
    function data_seek($number, $resultQuery=NULL)
249
    {
250
        if (!$resultQuery) {
251
            $resultQuery = $this->last_result_query;
252
            if (!$resultQuery) {
253
                return false;
254
            }
255
        }
256
        if (($success = pg_result_seek($resultQuery, $number)) !== false) {
257
            return $success;
258
        } else {
259
            throw new KumbiaException($this->error());
260
        }
261
    }
262
263
    /**
264
     * Numero de Filas afectadas en un insert, update o delete
265
     *
266
     * @param resource $resultQuery
267
     * @return int
268
     */
269
    function affected_rows($resultQuery=NULL)
270
    {
271
272
        if (!$resultQuery) {
273
            $resultQuery = $this->last_result_query;
274
            if (!$resultQuery) {
275
                return false;
276
            }
277
        }
278
        if (($numberRows = pg_affected_rows($resultQuery)) !== false) {
279
            return $numberRows;
280
        } else {
281
            throw new KumbiaException($this->error());
282
        }
283
    }
284
285
    /**
286
     * Devuelve el error de PostgreSQL
287
     *
288
     * @return string
289
     */
290
    function error($err='')
291
    {
292
        if (!$this->id_connection) {
293
            $this->last_error = @pg_last_error() ? @pg_last_error() . $err : "[Error Desconocido en PostgreSQL \"$err\"]";
294
            if ($this->logger) {
295
                Logger::error($this->last_error);
296
            }
297
            return $this->last_error;
298
        }
299
        $this->last_error = @pg_last_error() ? @pg_last_error() . $err : "[Error Desconocido en PostgreSQL: $err]";
300
        $this->last_error.= $err;
301
        if ($this->logger) {
302
            Logger::error($this->last_error);
303
        }
304
        return pg_last_error($this->id_connection) . $err;
305
    }
306
307
    /**
308
     * Devuelve el no error de PostgreSQL
309
     *
310
     * @return int ??
311
     */
312
    function no_error()
313
    {
314
315
        return 0; //Codigo de Error?
316
    }
317
318
    /**
319
     * Devuelve el ultimo id autonumerico generado en la BD
320
     *
321
     * @return int
322
     */
323
    public function last_insert_id($table='', $primary_key='')
324
    {
325
326
        $last_id = $this->fetch_one("SELECT CURRVAL('{$table}_{$primary_key}_seq')");
327
        return $last_id[0];
328
    }
329
330
    /**
331
     * Verifica si una tabla existe o no
332
     *
333
     * @param string $table
334
     * @return boolean
335
     */
336
    function table_exists($table, $schema='')
337
    {
338
        $table = addslashes(strtolower($table));
339
        if (strpos($table, ".")) {
340
            list($schema, $table) = explode(".", $table);
341
        }
342
        if ($schema == '') {
343
            $num = $this->fetch_one("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME ='$table'");
344
        } else {
345
            $schema = addslashes(strtolower($schema));
346
            $num = $this->fetch_one("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME ='$table'");
347
        }
348
        return $num[0];
349
    }
350
351
    /**
352
     * Devuelve un LIMIT valido para un SELECT del RBDM
353
     *
354
     * @param string $sql consulta sql
355
     * @return string
356
     */
357
    public function limit($sql)
358
    {
359
        $params = Util::getParams(func_get_args());
360
        $sql_new = $sql;
361
362
        if (isset($params['limit']) && is_numeric($params['limit'])) {
363
            $sql_new.=" LIMIT $params[limit]";
364
        }
365
366
        if (isset($params['offset']) && is_numeric($params['offset'])) {
367
            $sql_new.=" OFFSET $params[offset]";
368
        }
369
370
        return $sql_new;
371
    }
372
373
    /**
374
     * Borra una tabla de la base de datos
375
     *
376
     * @param string $table
377
     * @return boolean
378
     */
379
    public function drop_table($table, $if_exists=true)
380
    {
381
        if ($if_exists) {
382
            if ($this->table_exists($table)) {
383
                return $this->query("DROP TABLE $table");
384
            } else {
385
                return true;
386
            }
387
        } else {
388
            return $this->query("DROP TABLE $table");
389
        }
390
    }
391
392
    /**
393
     * Crea una tabla utilizando SQL nativo del RDBM
394
     *
395
     * TODO:
396
     * - Falta que el parametro index funcione. Este debe listar indices compuestos multipes y unicos
397
     * - Agregar el tipo de tabla que debe usarse (PostgreSQL)
398
     * - Soporte para campos autonumericos
399
     * - Soporte para llaves foraneas
400
     *
401
     * @param string $table
402
     * @param array $definition
403
     * @return resource
404
     */
405
    public function create_table($table, $definition, $index=array())
406
    {
407
        $create_sql = "CREATE TABLE $table (";
408
        if (!is_array($definition)) {
409
            throw new KumbiaException("Definición invalida para crear la tabla '$table'");
410
        }
411
        $create_lines = array();
412
        $index = array();
413
        $unique_index = array();
414
        $primary = array();
415
        //$not_null = "";
416
        //$size = "";
417
        foreach ($definition as $field => $field_def) {
418
            if (isset($field_def['not_null'])) {
419
                $not_null = $field_def['not_null'] ? 'NOT NULL' : '';
420
            } else {
421
                $not_null = "";
422
            }
423
            if (isset($field_def['size'])) {
424
                $size = $field_def['size'] ? '(' . $field_def['size'] . ')' : '';
425
            } else {
426
                $size = "";
427
            }
428
            if (isset($field_def['index'])) {
429
                if ($field_def['index']) {
430
                    $index[] = "INDEX($field)";
431
                }
432
            }
433
            if (isset($field_def['unique_index'])) {
434
                if ($field_def['unique_index']) {
435
                    $index[] = "UNIQUE($field)";
436
                }
437
            }
438
            if (isset($field_def['primary'])) {
439
                if ($field_def['primary']) {
440
                    $primary[] = "$field";
441
                }
442
            }
443
            if (isset($field_def['auto'])) {
444
                if ($field_def['auto']) {
445
                    $field_def['type'] = "SERIAL";
446
                }
447
            }
448
            if (isset($field_def['extra'])) {
449
                $extra = $field_def['extra'];
450
            } else {
451
                $extra = "";
452
            }
453
            $create_lines[] = "$field " . $field_def['type'] . $size . ' ' . $not_null . ' ' . $extra;
454
        }
455
        $create_sql.= join(',', $create_lines);
456
        $last_lines = array();
457
        if (count($primary)) {
458
            $last_lines[] = 'PRIMARY KEY(' . join(",", $primary) . ')';
459
        }
460
        if (count($index)) {
461
            $last_lines[] = join(',', $index);
462
        }
463
        if (count($unique_index)) {
464
            $last_lines[] = join(',', $unique_index);
465
        }
466
        if (count($last_lines)) {
467
            $create_sql.= ',' . join(',', $last_lines) . ')';
468
        }
469
        return $this->query($create_sql);
470
    }
471
472
    /**
473
     * Listar las tablas en la base de datos
474
     *
475
     * @return array
476
     */
477
    public function list_tables()
478
    {
479
        return $this->fetch_all("SELECT c.relname AS table FROM pg_class c, pg_user u "
480
                . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' "
481
                . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
482
                . "AND c.relname !~ '^(pg_|sql_)' UNION "
483
                . "SELECT c.relname AS table_name FROM pg_class c "
484
                . "WHERE c.relkind = 'r' "
485
                . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
486
                . "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) "
487
                . "AND c.relname !~ '^pg_'");
488
    }
489
490
    /**
491
     * Listar los campos de una tabla
492
     *
493
     * @param string $table
494
     * @return array
495
     */
496
    public function describe_table($table, $schema='')
497
    {
498
        $describe = $this->fetch_all("SELECT a.attname AS Field, t.typname AS Type,
499
                CASE WHEN attnotnull=false THEN 'YES' ELSE 'NO' END AS Null,
500
                CASE WHEN (select cc.contype FROM pg_catalog.pg_constraint cc WHERE
501
                cc.conrelid = c.oid AND cc.conkey[1] = a.attnum limit 1)='p' THEN 'PRI' ELSE ''
502
                END AS Key, CASE WHEN atthasdef=true THEN TRUE ELSE NULL END AS Default
503
                FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a,
504
                pg_catalog.pg_type t WHERE c.relname = '$table' AND c.oid = a.attrelid
505
                AND a.attnum > 0 AND t.oid = a.atttypid order by a.attnum");
506
        $final_describe = array();
507
        foreach ($describe as $key => $value) {
508
            $final_describe[] = array(
509
                "Field" => $value["field"],
510
                "Type" => $value["type"],
511
                "Null" => $value["null"],
512
                "Key" => $value["key"],
513
                "Default" => $value["default"]
514
            );
515
        }
516
        return $final_describe;
517
    }
518
519
    /**
520
     * Devuelve fila por fila el contenido de un select
521
     *
522
     * @param resource $query_result
523
     * @param string $class clase de objeto
524
     * @return object
525
     */
526
    public function fetch_object($query_result=null, $class='stdClass')
527
    {
528
        if (!$query_result) {
529
            $query_result = $this->last_result_query;
530
        }
531
        return pg_fetch_object($query_result, null, $class);
532
    }
533
534
    /**
535
     * Devuelve la ultima sentencia sql ejecutada por el Adaptador
536
     *
537
     * @return string
538
     */
539
    public function last_sql_query()
540
    {
541
        return $this->last_query;
542
    }
543
544
}
545