Passed
Push — main ( b2ddc1...a529c9 )
by Thierry
01:51
created

Table::triggerOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
namespace Lagdo\DbAdmin\Driver\PgSql\Db;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableEntity;
6
use Lagdo\DbAdmin\Driver\Entity\IndexEntity;
7
use Lagdo\DbAdmin\Driver\Entity\ForeignKeyEntity;
8
use Lagdo\DbAdmin\Driver\Entity\TriggerEntity;
9
10
use Lagdo\DbAdmin\Driver\Db\ConnectionInterface;
11
12
use Lagdo\DbAdmin\Driver\Db\Table as AbstractTable;
13
14
class Table extends AbstractTable
15
{
16
    use TableTrait;
17
18
    /**
19
     * @inheritDoc
20
     */
21
    public function tableStatus(string $table, bool $fast = false)
22
    {
23
        $rows = $this->queryStatus($table);
24
        if (!($row = reset($rows))) {
25
            return null;
26
        }
27
        return $this->makeStatus($row);
28
    }
29
30
    /**
31
     * @inheritDoc
32
     */
33
    public function tableStatuses(bool $fast = false)
34
    {
35
        $tables = [];
36
        $rows = $this->queryStatus();
37
        foreach ($rows as $row) {
38
            $tables[$row["Name"]] = $this->makeStatus($row);
39
        }
40
        return $tables;
41
    }
42
43
    /**
44
     * @inheritDoc
45
     */
46
    public function tableNames()
47
    {
48
        $tables = [];
49
        $rows = $this->queryStatus();
50
        foreach ($rows as $row) {
51
            $tables[] = $row["Name"];
52
        }
53
        return $tables;
54
    }
55
56
    /**
57
     * @inheritDoc
58
     */
59
    public function isView(TableEntity $tableStatus)
60
    {
61
        return in_array($tableStatus->engine, ["view", "materialized view"]);
62
    }
63
64
    /**
65
     * @inheritDoc
66
     */
67
    public function supportForeignKeys(TableEntity $tableStatus)
68
    {
69
        return true;
70
    }
71
72
    /**
73
     * @inheritDoc
74
     */
75
    public function referencableTables(string $table)
76
    {
77
        $fields = []; // table_name => [field]
78
        foreach ($this->tableNames() as $tableName) {
79
            if ($tableName === $table) {
80
                continue;
81
            }
82
            foreach ($this->fields($tableName) as $field) {
83
                if ($field->primary) {
84
                    if (!isset($fields[$tableName])) {
85
                        $fields[$tableName] = $field;
86
                    } else {
87
                        // No multi column primary key
88
                        $fields[$tableName] = null;
89
                    }
90
                }
91
            }
92
        }
93
        return array_filter($fields, function($field) {
94
            return $field !== null;
95
        });
96
    }
97
98
    /**
99
     * @inheritDoc
100
     */
101
    public function fields(string $table)
102
    {
103
        $fields = [];
104
105
        // Primary keys
106
        $primaryKeyColumns = $this->primaryKeyColumns($table);
107
108
        $identity_column = $this->driver->minVersion(10) ? 'a.attidentity' : '0';
109
        $query = "SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, " .
110
            "pg_get_expr(d.adbin, d.adrelid) AS default, a.attnotnull::int, " .
111
            "col_description(c.oid, a.attnum) AS comment, $identity_column AS identity FROM pg_class c " .
112
            "JOIN pg_namespace n ON c.relnamespace = n.oid JOIN pg_attribute a ON c.oid = a.attrelid " .
113
            "LEFT JOIN pg_attrdef d ON c.oid = d.adrelid AND a.attnum = d.adnum WHERE c.relname = " .
114
            $this->driver->quote($table) .
0 ignored issues
show
Bug introduced by
The method quote() does not exist on Lagdo\DbAdmin\Driver\DriverInterface. Did you maybe mean quoteBinary()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

114
            $this->driver->/** @scrutinizer ignore-call */ 
115
                           quote($table) .

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
115
            " AND n.nspname = current_schema() AND NOT a.attisdropped AND a.attnum > 0 ORDER BY a.attnum";
116
        foreach ($this->driver->rows($query) as $row)
117
        {
118
            $fields[$row["field"]] = $this->makeFieldEntity($row, $primaryKeyColumns);
119
        }
120
        return $fields;
121
    }
122
123
    /**
124
     * @inheritDoc
125
     */
126
    public function indexes(string $table, ConnectionInterface $connection = null)
127
    {
128
        if (!$connection) {
129
            $connection = $this->connection;
130
        }
131
        $indexes = [];
132
        $table_oid = $connection->result("SELECT oid FROM pg_class WHERE " .
133
            "relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema()) " .
134
            "AND relname = " . $this->driver->quote($table));
135
        $columns = $this->driver->keyValues("SELECT attnum, attname FROM pg_attribute WHERE " .
136
            "attrelid = $table_oid AND attnum > 0", $connection);
137
        $query = "SELECT relname, indisunique::int, indisprimary::int, indkey, indoption, " .
138
            "(indpred IS NOT NULL)::int as indispartial FROM pg_index i, pg_class ci " .
139
            "WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid";
140
        foreach ($this->driver->rows($query, $connection) as $row)
141
        {
142
            $indexes[$row["relname"]] = $this->makeIndexEntity($row, $columns);
143
        }
144
        return $indexes;
145
    }
146
147
    /**
148
     * @inheritDoc
149
     */
150
    public function foreignKeys(string $table)
151
    {
152
        $foreignKeys = [];
153
        $query = "SELECT conname, condeferrable::int AS deferrable, pg_get_constraintdef(oid) " .
154
            "AS definition FROM pg_constraint WHERE conrelid = (SELECT pc.oid FROM pg_class AS pc " .
155
            "INNER JOIN pg_namespace AS pn ON (pn.oid = pc.relnamespace) WHERE pc.relname = " .
156
            $this->driver->quote($table) .
157
            " AND pn.nspname = current_schema()) AND contype = 'f'::char ORDER BY conkey, conname";
158
        foreach ($this->driver->rows($query) as $row) {
159
            $foreignKey = $this->makeForeignKeyEntity($row);
160
            if ($foreignKey !== null) {
161
                $foreignKeys[$row['conname']] = $foreignKey;
162
            }
163
        }
164
        return $foreignKeys;
165
    }
166
167
    /**
168
     * @inheritDoc
169
     */
170
    public function trigger(string $name, string $table = '')
171
    {
172
        if ($name == '') {
173
            return new TriggerEntity('', '', 'EXECUTE PROCEDURE ()');
174
        }
175
        if ($table === '') {
176
            $table = $this->util->input()->getTable();
177
        }
178
        $query = 'SELECT t.trigger_name AS "Trigger", t.action_timing AS "Timing", ' .
179
            '(SELECT STRING_AGG(event_manipulation, \' OR \') FROM information_schema.triggers ' .
180
            'WHERE event_object_table = t.event_object_table AND trigger_name = t.trigger_name ) AS "Events", ' .
181
            't.event_manipulation AS "Event", \'FOR EACH \' || t.action_orientation AS "Type", ' .
182
            't.action_statement AS "Statement" FROM information_schema.triggers t WHERE t.event_object_table = ' .
183
            $this->driver->quote($table) . ' AND t.trigger_name = ' . $this->driver->quote($name);
184
        $rows = $this->driver->rows($query);
185
        if (!($row = reset($rows))) {
186
            return null;
187
        }
188
        return new TriggerEntity($row['Timing'], $row['Event'], $row['Statement'], '', $row['Trigger']);
189
    }
190
191
    /**
192
     * @inheritDoc
193
     */
194
    public function triggers(string $table)
195
    {
196
        $triggers = [];
197
        $query = "SELECT * FROM information_schema.triggers WHERE trigger_schema = current_schema() " .
198
            "AND event_object_table = " . $this->driver->quote($table);
199
        foreach ($this->driver->rows($query) as $row) {
200
            $triggers[$row["trigger_name"]] = new TriggerEntity($row["action_timing"],
201
                $row["event_manipulation"], '', '', $row["trigger_name"]);
202
        }
203
        return $triggers;
204
    }
205
206
    /**
207
     * @inheritDoc
208
     */
209
    public function triggerOptions()
210
    {
211
        return [
212
            "Timing" => ["BEFORE", "AFTER"],
213
            "Event" => ["INSERT", "UPDATE", "DELETE"],
214
            "Type" => ["FOR EACH ROW", "FOR EACH STATEMENT"],
215
        ];
216
    }
217
218
    /**
219
     * @inheritDoc
220
     */
221
    public function tableHelp(string $name)
222
    {
223
        $links = [
224
            "information_schema" => "infoschema",
225
            "pg_catalog" => "catalog",
226
        ];
227
        $link = $links[$this->driver->schema()];
228
        if ($link) {
229
            return "$link-" . str_replace("_", "-", $name) . ".html";
230
        }
231
    }
232
}
233