Completed
Push — master ( 227237...06988d )
by Agel_Nash
02:25
created

DebugTrait::collectQuery()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 12
nop 4
dl 0
loc 21
ccs 14
cts 14
cp 1
crap 5
rs 8.7624
c 0
b 0
f 0
1
<?php namespace AgelxNash\Modx\Evo\Database\Traits;
2
3
use mysqli;
4
use mysqli_result;
5
use AgelxNash\Modx\Evo\Database\Exceptions;
6
7
trait DebugTrait
8
{
9
    protected $debug = false;
10
    protected $queryCollection = [];
11
    protected $queryTime = 0;
12
    protected $executedQueries = 0;
13
    protected $lastQuery = '';
14
    protected $connectionTime = 0;
15
16
    public $ignoreErrors = [
17
        1054, // SQLSTATE: 42S22 (ER_BAD_FIELD_ERROR) Unknown column '%s' in '%s'
18
        1060, // SQLSTATE: 42S21 (ER_DUP_FIELDNAME) Duplicate column name '%s'
19
        1061, // SQLSTATE: 42000 (ER_DUP_KEYNAME) Duplicate key name '%s'
20
        1062, // SQLSTATE: 23000 (ER_DUP_ENTRY) Duplicate entry '%s' for key %d
21
        1091 // SQLSTATE: 42000 (ER_CANT_DROP_FIELD_OR_KEY) Can't DROP '%s'; check that column/key exists
22
    ];
23
24
    protected $timeFormat = '%2.5f';
25
26
    /**
27
      * @return mysqli
28
      * @throws Exceptions\ConnectException
29
      * @throws Exceptions\QueryException
30
      */
31
    abstract public function getConnect() : mysqli;
32
33
    /**
34
     * @param mysqli_result $result
35
     * @return int
36
     */
37
    abstract public function getRecordCount(mysqli_result $result) : int;
38
39
    /**
40
     * @return int
41
     * @throws Exceptions\ConnectException
42
     * @throws Exceptions\QueryException
43
     */
44
    abstract public function getAffectedRows() : int;
45
46
    /**
47
     * @return string
48
     * @throws Exceptions\ConnectException
49
     * @throws Exceptions\QueryException
50
     */
51 1
    public function getLastError() : string
52
    {
53 1
        return $this->getConnect()->error;
54
    }
55
56
    /**
57
     * @return int
58
     * @throws Exceptions\ConnectException
59
     * @throws Exceptions\QueryException
60
     */
61 1
    public function getLastErrorNo() : int
62
    {
63 1
        return $this->getConnect()->errno;
64
    }
65
66
    /**
67
     * @return array
68
     */
69 2
    public function getIgnoreErrors() : array
70
    {
71 2
        return $this->ignoreErrors;
72
    }
73
74
    /**
75
     * @param int $error
76
     * @return DebugTrait
77
     */
78 1
    public function addIgnoreErrors(int $error) : self
79
    {
80 1
        $this->ignoreErrors[] = $error;
81
82 1
        return $this;
83
    }
84
85
    /**
86
     * @return DebugTrait
87
     */
88 1
    public function flushIgnoreErrors() : self
89
    {
90 1
        $this->ignoreErrors = [];
91
92 1
        return $this;
93
    }
94
95
    /**
96
     * @param array $errors
97
     * @return DebugTrait
98
     */
99 1
    public function setIgnoreErrors(array $errors = []) : self
100
    {
101 1
        $this->flushIgnoreErrors();
102
103 1
        foreach ($errors as $error) {
104 1
            $this->addIgnoreErrors($error);
105
        }
106
107 1
        return $this;
108
    }
109
110
    /**
111
     * @param null|string $query
112
     * @return bool
113
     * @throws Exceptions\ConnectException
114
     * @throws Exceptions\QueryException
115
     */
116 1
    public function checkLastError($query = null) : bool
117
    {
118 1
        if ($this->getIgnoreErrors() === [] || \in_array($this->getLastErrorNo(), $this->getIgnoreErrors(), true)) {
119
            return false;
120
        }
121
122 1
        throw (new Exceptions\QueryException($this->getLastError()))
123 1
            ->setQuery($query);
124
    }
125
126
    /**
127
     * @param mysqli_result|bool $result
128
     * @param string $sql
129
     * @param int $iteration
130
     * @param int $time
131
     * @throws Exceptions\ConnectException
132
     * @throws Exceptions\QueryException
133
     */
134 17
    protected function collectQuery($result, string $sql, int $iteration, int $time) : void
135
    {
136 17
        $debug = debug_backtrace();
137 17
        array_shift($debug);
138 17
        array_shift($debug);
139 17
        $path = [];
140 17
        foreach ($debug as $line) {
141 17
            $path[] = ($line['class'] ? ($line['class'] . '::') : null) . $line['function'];
142
            /*$path[] = [
143
                'method' => ($line['class'] ? ($line['class'] . '::') : null) . $line['function'],
144
                'file' => ($line['file'] ? ($line['file'] . ':') : null) . ($line['line'] ?? 0)
145
            ];*/
146
        }
147 17
        $path = implode(' > ', array_reverse($path));
148
149 17
        $this->queryCollection[$iteration] = [
150 17
            'sql' => $sql,
151 17
            'time' => $time,
152 17
            'rows' => (stripos($sql, 'SELECT') === 0 && $result instanceof mysqli_result) ?
153 17
                $this->getRecordCount($result) : $this->getAffectedRows(),
154 17
            'path' => $path,
155
            //'event' => $modx->event->name,
156
            //'element' => [
157
            //      'name' => $modx->event->activePlugin ?? ($modx->currentSnippet ?? null),
158
            //      'type' => $modx->event->activePlugin ? 'Plugin' : ($modx->currentSnippet ? 'Snippet' : 'Source code')
159
            // ]
160
        ];
161 17
    }
162
163
    /**
164
     * @return string
165
     */
166 18
    public function getLastQuery() : string
167
    {
168 18
        return $this->lastQuery;
169
    }
170
171
    /**
172
     * @return array
173
     */
174 7
    public function getAllExecutedQuery() : array
175
    {
176 7
        return $this->queryCollection;
177
    }
178
179
    /**
180
     * @return $this
181
     */
182 5
    public function flushExecutedQuery() : self
183
    {
184 5
        $this->queryCollection = [];
185 5
        $this->executedQueries = 0;
186 5
        $this->queryTime = 0;
187 5
        $this->lastQuery = '';
188
189 5
        return $this;
190
    }
191
192
    /**
193
     * @return string
194
     */
195 1
    public function renderExecutedQuery() : string
196
    {
197 1
        $out = '';
198
199 1
        foreach ($this->getAllExecutedQuery() as $i => $query) {
200
            $out .= '<fieldset style="text-align:left">';
201
            $out .= '<legend>Query ' . $i . ' - ' . sprintf($this->timeFormat, $query['time']) . '</legend>';
202
            $out .= $query['sql'] . '<br><br>';
203
            if (! empty($query['element'])) {
204
                $out .= $query['element']['type'] . '  => ' . $query['element']['name'] . '<br>';
205
            }
206
            if (! empty($query['event'])) {
207
                $out .= 'Current Event  => ' . $query['event'] . '<br>';
208
            }
209
            $out .= 'Affected Rows => ' . $query['rows'] . '<br>';
210
            if (! empty($query['path'])) {
211
                $out .= 'Functions Path => ' . $query['path'] . '<br>';
212
            }
213
            /*$out .= 'Functions Path => ' . $query['path']['method'] . '<br>';
214
            $out .= empty($query['path']['file']) ?: $query['path']['file'] . '<br />';*/
215
            $out .= '</fieldset><br />';
216
        }
217
218 1
        return $out;
219
    }
220
221
    /**
222
     * @param bool $format
223
     * @return string|float
224
     */
225 2
    public function getConnectionTime(bool $format = false)
226
    {
227 2
        return $format ? sprintf($this->timeFormat, $this->connectionTime) : $this->connectionTime;
228
    }
229
230
    /**
231
     * @return string
232
     */
233 1
    public function renderConnectionTime() : string
234
    {
235
        return '<fieldset style="text-align:left">' .
236
            '<legend>Database connection</legend>' .
237 1
            'Database connection was created in ' . $this->getConnectionTime(true) . ' s.' .
238 1
            '</fieldset>' .
239 1
            '<br />';
240
    }
241
242
    /**
243
     * @param bool $flag
244
     * @return $this
245
     */
246 18
    public function setDebug(bool $flag) : self
247
    {
248 18
        $this->debug = $flag;
249
250 18
        return $this;
251
    }
252
253
    /**
254
     * @return bool
255
     */
256 18
    public function isDebug() : bool
257
    {
258 18
        return $this->debug;
259
    }
260
}
261