Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
60 / 60
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractGateway
100.00% covered (success)
100.00%
60 / 60
100.00% covered (success)
100.00%
4 / 4
19
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 checkOptions
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getTableInfo
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
14
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Db\Gateway;
16
17use Pop\Db\Db;
18use Pop\Db\Sql;
19use Pop\Db\Adapter\AbstractAdapter;
20
21/**
22 * Db abstract gateway class
23 *
24 * @category   Pop
25 * @package    Pop\Db
26 * @author     Nick Sagona, III <nick@popphp.org>
27 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
28 * @license    https://www.popphp.org/license     New BSD License
29 * @version    7.0.0
30 */
31abstract class AbstractGateway implements GatewayInterface
32{
33
34    /**
35     * Recognized $options keys. This is the union of the keys consumed by the table gateway,
36     * the row gateway and the relationship classes - a key outside of it is a typo.
37     * @var array
38     */
39    public const OPTIONS = ['select', 'limit', 'offset', 'order', 'group', 'join', 'columns'];
40
41    /**
42     * Table
43     * @var ?string
44     */
45    protected ?string $table = null;
46
47    /**
48     * Constructor
49     *
50     * Instantiate the AbstractGateway object.
51     *
52     * @param  string $table
53     */
54    public function __construct(string $table)
55    {
56        $this->table = $table;
57    }
58
59    /**
60     * Get the table name
61     *
62     * @return string
63     */
64    public function getTable(): string
65    {
66        return $this->table;
67    }
68
69    /**
70     * Check the keys of an $options array, firing a notice naming any that isn't recognized
71     *
72     * An unrecognized key is silently ignored by the query builders, so a misspelled or
73     * wrong-cased one ('limitt', 'Limit', 'orderBy') would otherwise return unfiltered results
74     * with no signal at all. This is deliberately a notice and not an exception, so that
75     * applications passing extra keys today keep working.
76     *
77     * @param  ?array $options
78     * @return void
79     */
80    protected function checkOptions(?array $options = null): void
81    {
82        if (empty($options)) {
83            return;
84        }
85
86        $unrecognized = array_diff(array_map('strval', array_keys($options)), self::OPTIONS);
87
88        if (!empty($unrecognized)) {
89            trigger_error(
90                "Notice: The option key(s) [" . implode(', ', $unrecognized) . "] are not recognized and were " .
91                "ignored. Option keys are case-sensitive; the recognized keys are: " .
92                implode(', ', self::OPTIONS) . ".",
93                E_USER_NOTICE
94            );
95        }
96    }
97
98    /**
99     * Get table info
100     *
101     * @param  ?AbstractAdapter $db
102     * @return array
103     */
104    public function getTableInfo(?AbstractAdapter $db = null): array
105    {
106        if ($db === null) {
107            $db = Db::getDb($this->table);
108        }
109
110        $tables = $db->getTables();
111        $sql    = $db->createSql();
112        $info   = [
113            'tableName' => $this->table,
114            'columns'   => []
115        ];
116
117        if (in_array($this->table, $tables)) {
118            $sqlString = null;
119            $field     = 'column_name';
120            $type      = 'data_type';
121            $nullField = 'is_nullable';
122            $keyField  = 'constraint_type';
123
124            switch ($sql->getDbType()) {
125                case Sql::PGSQL:
126                case Sql::SQLSRV:
127                    $sqlString = 'SELECT * FROM information_schema.columns ' .
128                        'LEFT JOIN information_schema.table_constraints ' .
129                        'ON information_schema.table_constraints.table_name = information_schema.columns.table_name ' .
130                        'WHERE information_schema.columns.table_name = \'' . $this->table . '\'';
131                    break;
132                case Sql::SQLITE:
133                    $sqlString = 'PRAGMA table_info(\'' . $this->table . '\')';
134                    $field     = 'name';
135                    $type      = 'type';
136                    $nullField = 'notnull';
137                    $keyField  = 'pk';
138                    break;
139                default:
140                    $sqlString = 'SHOW COLUMNS FROM `' . $this->table . '`';
141                    $field     = 'Field';
142                    $type      = 'Type';
143                    $nullField = 'Null';
144                    $keyField  = 'Key';
145            }
146
147            $db->query($sqlString);
148
149            while (($row = $db->fetch()) != false) {
150                switch ($sql->getDbType()) {
151                    case Sql::SQLITE:
152                        $nullResult    = !($row[$nullField]);
153                        $primaryResult = ($row[$keyField] == 1);
154                        break;
155                    case Sql::MYSQL:
156                        $nullResult    = (!empty($row[$nullField]) && (strtoupper($row[$nullField]) != 'NO'));
157                        $primaryResult = (!empty($row[$keyField]) && (strtoupper($row[$keyField]) == 'PRI'));
158                        break;
159                    default:
160                        $nullResult    = $row[$nullField];
161                        $primaryResult = (!empty($row[$keyField]) && (strtoupper($row[$keyField]) == 'PRIMARY KEY'));
162
163                }
164
165                $info['columns'][$row[$field]] = [
166                    'type'    => $row[$type],
167                    'primary' => $primaryResult,
168                    'null'    => $nullResult
169                ];
170            }
171        }
172
173        return $info;
174    }
175
176}