Passed
Pull Request — develop (#186)
by Felipe
07:21 queued 01:59
created

TriggerTrait   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 25
dl 0
loc 204
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getTriggerFunctions() 0 3 1
A getTrigger() 0 15 1
B _defineTriggersConstants() 0 11 6
B _getTriggerDeferrability() 0 27 6
C _getTriggerConstraint() 0 44 8
B getTriggerDef() 0 36 3
1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.43
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
/**
10
 * Common trait for triggers manipulation.
11
 */
12
trait TriggerTrait
13
{
14
    /**
15
     * Grabs a single trigger.
16
     *
17
     * @param string $table   The name of a table whose triggers to retrieve
18
     * @param string $trigger The name of the trigger to retrieve
19
     *
20
     * @return \PHPPgAdmin\ADORecordSet A recordset
21
     */
22
    public function getTrigger($table, $trigger)
23
    {
24
        $c_schema = $this->_schema;
25
        $this->clean($c_schema);
26
        $this->clean($table);
27
        $this->clean($trigger);
28
29
        $sql = "
30
            SELECT * FROM pg_catalog.pg_trigger t, pg_catalog.pg_class c
31
            WHERE t.tgrelid=c.oid AND c.relname='{$table}' AND t.tgname='{$trigger}'
32
                AND c.relnamespace=(
33
                    SELECT oid FROM pg_catalog.pg_namespace
34
                    WHERE nspname='{$c_schema}')";
35
36
        return $this->selectSet($sql);
37
    }
38
39
    /**
40
     * Gets the trigger constraint.
41
     *
42
     * @param array $trigger An array containing fields from the trigger table
43
     *
44
     * @return array  The trigger constraint sentence, and the $findx
45
     */
46
    private function _getTriggerConstraint($trigger)
47
    {
48
        // Constraint trigger or normal trigger
49
        if ($trigger['tgisconstraint']) {
50
            $tgdef = 'CREATE CONSTRAINT TRIGGER ';
51
        } else {
52
            $tgdef = 'CREATE TRIGGER ';
53
        }
54
55
        $tgdef .= "\"{$trigger['tgname']}\" ";
56
57
        // Trigger type
58
        $findx = 0;
59
        if (($trigger['tgtype'] & TRIGGER_TYPE_BEFORE) == TRIGGER_TYPE_BEFORE) {
60
            $tgdef .= 'BEFORE';
61
        } else {
62
            $tgdef .= 'AFTER';
63
        }
64
65
        if (($trigger['tgtype'] & TRIGGER_TYPE_INSERT) == TRIGGER_TYPE_INSERT) {
66
            $tgdef .= ' INSERT';
67
            ++$findx;
68
        }
69
        if (($trigger['tgtype'] & TRIGGER_TYPE_DELETE) == TRIGGER_TYPE_DELETE) {
70
            if ($findx > 0) {
71
                $tgdef .= ' OR DELETE';
72
            } else {
73
                $tgdef .= ' DELETE';
74
                ++$findx;
75
            }
76
        }
77
        if (($trigger['tgtype'] & TRIGGER_TYPE_UPDATE) == TRIGGER_TYPE_UPDATE) {
78
            if ($findx > 0) {
79
                $tgdef .= ' OR UPDATE';
80
            } else {
81
                $tgdef .= ' UPDATE';
82
            }
83
        }
84
85
        $f_schema = $this->_schema;
86
        $this->fieldClean($f_schema);
87
        // Table name
88
        $tgdef .= " ON \"{$f_schema}\".\"{$trigger['relname']}\" ";
89
        return [$tgdef, $findx];
90
    }
91
92
    /**
93
     * Figure out if trigger is deferrable
94
     *
95
     * @param array $trigger An array containing fields from the trigger table
96
     *
97
     * @return string  The trigger deferrability sentence part.
98
     */
99
    private function _getTriggerDeferrability($trigger)
100
    {
101
        $tgdef = '';
102
        if ($trigger['tgisconstraint']) {
103
            if ($trigger['tgconstrrelid'] != 0) {
104
                // Assume constrelname is not null
105
                $tgdef .= " FROM \"{$trigger['tgconstrrelname']}\" ";
106
            }
107
            if (!$trigger['tgdeferrable']) {
108
                $tgdef .= 'NOT ';
109
            }
110
111
            $tgdef .= 'DEFERRABLE INITIALLY ';
112
            if ($trigger['tginitdeferred']) {
113
                $tgdef .= 'DEFERRED ';
114
            } else {
115
                $tgdef .= 'IMMEDIATE ';
116
            }
117
        }
118
119
        // Row or statement
120
        if ($trigger['tgtype'] & TRIGGER_TYPE_ROW == TRIGGER_TYPE_ROW) {
121
            $tgdef .= 'FOR EACH ROW ';
122
        } else {
123
            $tgdef .= 'FOR EACH STATEMENT ';
124
        }
125
        return $tgdef;
126
    }
127
128
    /**
129
     * Defines trigger related constants
130
     */
131
    private function _defineTriggersConstants()
132
    {
133
        defined('TRIGGER_TYPE_ROW') || define('TRIGGER_TYPE_ROW', 1 << 0);
134
135
        defined('TRIGGER_TYPE_BEFORE') || define('TRIGGER_TYPE_BEFORE', 1 << 1);
136
137
        defined('TRIGGER_TYPE_INSERT') || define('TRIGGER_TYPE_INSERT', 1 << 2);
138
139
        defined('TRIGGER_TYPE_DELETE') || define('TRIGGER_TYPE_DELETE', 1 << 3);
140
141
        defined('TRIGGER_TYPE_UPDATE') || define('TRIGGER_TYPE_UPDATE', 1 << 4);
142
    }
143
144
    /**
145
     * A helper function for getTriggers that translates
146
     * an array of attribute numbers to an array of field names.
147
     * Note: Only needed for pre-7.4 servers, this function is deprecated.
148
     *
149
     * @param array $trigger An array containing fields from the trigger table
150
     *
151
     * @return string The trigger definition string
152
     */
153
    public function getTriggerDef($trigger)
154
    {
155
        $this->fieldArrayClean($trigger);
0 ignored issues
show
Bug introduced by
It seems like fieldArrayClean() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

155
        $this->/** @scrutinizer ignore-call */ 
156
               fieldArrayClean($trigger);
Loading history...
156
        // Constants to figure out tgtype
157
158
        $this->_defineTriggersConstants();
159
160
        $trigger['tgisconstraint'] = $this->phpBool($trigger['tgisconstraint']);
0 ignored issues
show
Bug introduced by
It seems like phpBool() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

160
        /** @scrutinizer ignore-call */ 
161
        $trigger['tgisconstraint'] = $this->phpBool($trigger['tgisconstraint']);
Loading history...
161
        $trigger['tgdeferrable']   = $this->phpBool($trigger['tgdeferrable']);
162
        $trigger['tginitdeferred'] = $this->phpBool($trigger['tginitdeferred']);
163
164
        list($tgdef, $findx) = $this->_getTriggerConstraint($trigger);
165
        // Deferrability
166
167
        $tgdef .= $this->_getTriggerDeferrability($trigger);
168
169
        // Execute procedure
170
        $tgdef .= "EXECUTE PROCEDURE \"{$trigger['tgfname']}\"(";
171
172
        // Parameters
173
        // Escape null characters
174
        $v = addcslashes($trigger['tgargs'], "\0");
175
        // Split on escaped null characters
176
        $params = explode('\\000', $v);
177
        for ($findx = 0; $findx < $trigger['tgnargs']; ++$findx) {
178
            $param = "'" . str_replace('\'', '\\\'', $params[$findx]) . "'";
179
            $tgdef .= $param;
180
            if ($findx < ($trigger['tgnargs'] - 1)) {
181
                $tgdef .= ', ';
182
            }
183
        }
184
185
        // Finish it off
186
        $tgdef .= ')';
187
188
        return $tgdef;
189
    }
190
191
    /**
192
     * Returns a list of all functions that can be used in triggers.
193
     *
194
     * @return \PHPPgAdmin\ADORecordSet all functions that can be used in triggers
195
     */
196
    public function getTriggerFunctions()
197
    {
198
        return $this->getFunctions(true, 'trigger');
0 ignored issues
show
Bug introduced by
It seems like getFunctions() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

198
        return $this->/** @scrutinizer ignore-call */ getFunctions(true, 'trigger');
Loading history...
199
    }
200
201
    abstract public function fieldClean(&$str);
202
203
    abstract public function beginTransaction();
204
205
    abstract public function rollbackTransaction();
206
207
    abstract public function endTransaction();
208
209
    abstract public function execute($sql);
210
211
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
212
213
    abstract public function selectSet($sql);
214
215
    abstract public function clean(&$str);
216
}
217