Component::close()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
ccs 11
cts 11
cp 1
rs 9.2
cc 4
eloc 7
nc 3
nop 1
crap 4
1
<?php
2
3
namespace BootPress\Database;
4
5
class Component extends Driver
6
{
7
    protected $prepared = array();
8
9 24
    public function exec($query, $values = array())
10
    {
11 24
        if ($stmt = $this->prepare($query)) {
12 24
            $result = $this->execute($stmt, $values);
13 24
            $this->close($stmt);
14 24
        }
15
16 24
        return (isset($result)) ? $result : false;
17
    }
18
19 72
    public function query($select, $values = array(), $fetch = 'row')
20
    {
21 72
        if ($stmt = $this->prepare($select, $fetch)) {
22 71
            if ($this->prepared[$stmt]['type'] == 'SELECT' && $this->execute($stmt, $values)) {
23 71
                return $stmt;
24
            }
25 1
            $this->close($stmt);
26 1
        }
27
28 3
        return false;
29
    }
30
31 32
    public function all($select, $values = array(), $fetch = 'row')
32
    {
33 32
        $rows = array();
34 32
        if ($stmt = $this->query($select, $values, $fetch)) {
35 32
            while ($row = $this->fetch($stmt)) {
36 31
                $rows[] = $row;
37 31
            }
38 32
            $this->close($stmt);
39 32
        }
40
41 32
        return $rows;
42
    }
43
44 14
    public function ids($select, $values = array())
45
    {
46 14
        $ids = array();
47 14
        if ($stmt = $this->query($select, $values, 'row')) {
48 14
            while ($row = $this->fetch($stmt)) {
49 12
                $ids[] = (int) array_shift($row);
50 12
            }
51 14
            $this->close($stmt);
52 14
        }
53
54 14
        return (!empty($ids)) ? $ids : false;
55
    }
56
57 48
    public function row($select, $values = array(), $fetch = 'row')
58
    {
59 48
        if ($stmt = $this->query($select, $values, $fetch)) {
60 48
            $row = $this->fetch($stmt);
61 48
            $this->close($stmt);
62 48
        }
63
64 48
        return (isset($row) && !empty($row)) ? $row : false;
65
    }
66
67 30
    public function value($select, $values = array())
68
    {
69 30
        return ($row = $this->row($select, $values, 'row')) ? array_shift($row) : false;
70
    }
71
72 19
    public function insert($table, array $data, $and = '')
73
    {
74 19
        if (isset($this->prepared[$table])) {
75 13
            return $this->execute($table, $data);
76
        }
77 19
        $single = (count(array_filter(array_keys($data), 'is_string')) > 0) ? $data : false;
78 19
        if ($single) {
79 8
            $data = array_keys($data);
80 8
        }
81 19
        if (stripos($table, ' INTO ') !== false) { // eg. 'OR IGNORE INTO table'
82 2
            $query = "INSERT {$table} ";
83 2
        } else {
84 19
            $query = "INSERT INTO {$table} ";
85
        }
86 19
        $query .= '('.implode(', ', $data).') VALUES ('.implode(', ', array_fill(0, count($data), '?')).') '.$and;
87 19
        $stmt = $this->prepare($query);
88 19
        if ($single && $stmt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stmt of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
89 8
            $id = $this->insert($stmt, array_values($single));
90 8
            $this->close($stmt);
91
92 8
            return $id;
93
        }
94
95 15
        return $stmt;
96
    }
97
98 18
    public function update($table, $id, array $data, $and = '')
99
    {
100 18
        if (isset($this->prepared[$table])) {
101 16
            $data[] = $id;
102
103 16
            return $this->execute($table, $data);
104
        }
105 18
        $first = each($data);
106 18
        $single = (is_array($first['value'])) ? $first['value'] : false;
107 18
        if ($single) {
108 8
            $data = array_keys($single);
109 8
        }
110 18
        if (stripos($table, ' SET ') !== false) { // eg. 'table SET date = NOW(),'
111 1
            $query = "UPDATE {$table} ";
112 1
        } else {
113 18
            $query = "UPDATE {$table} SET ";
114
        }
115 18
        $query .= implode(' = ?, ', $data).' = ? WHERE '.$id.' = ? '.$and;
116 18
        $stmt = $this->prepare($query);
117 18
        if ($single && $stmt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stmt of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
118 8
            $affected = $this->update($stmt, $first['key'], array_values($single));
119 8
            $this->close($stmt);
120
121 8
            return $affected;
122
        }
123
124 12
        return $stmt;
125
    }
126
127 2
    public function upsert($table, $id, array $data)
128
    {
129 2
        if (isset($this->prepared[$table]['ref']) && $this->execute($table, $id)) {
130 2
            $data[] = $id;
131 2
            if ($row = $this->fetch($table)) {
132 1
                return ($this->execute($this->prepared[$table]['ref']['update'], $data)) ? array_shift($row) : false;
133
            } else {
134 2
                return $this->execute($this->prepared[$table]['ref']['insert'], $data);
135
            }
136
        }
137 2
        $first = each($data);
138 2
        $single = (is_array($first['value'])) ? $first['value'] : false;
139 2
        if ($single) {
140 1
            $data = array_keys($single);
141 1
        }
142 2
        if ($stmt = $this->prepare("SELECT {$id} FROM {$table} WHERE {$id} = ?", 'row')) {
143 2
            $this->prepared[$stmt]['ref']['update'] = $this->update($table, $id, $data);
144 2
            $this->prepared[$stmt]['ref']['insert'] = $this->insert($table, array_merge($data, array($id)));
145 2
        }
146 2
        if ($single && $stmt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stmt of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
147 1
            $id = $this->upsert($stmt, $first['key'], array_values($single));
148 1
            $this->close($stmt);
149
150 1
            return $id;
151
        }
152
153 2
        return $stmt;
154
    }
155
156 76
    public function prepare($query, $fetch = null)
157
    {
158 76
        $query = (is_array($query)) ? trim(implode("\n", $query)) : trim($query);
159 76
        $stmt = count(static::$logs[$this->id]) + 1;
160 76
        $start = microtime(true);
161 76
        $this->connection();
162 76
        $this->prepared[$stmt]['obj'] = $this->dbPrepare($query);
163 76
        static::$logs[$this->id][$stmt] = array(
164 76
            'sql' => $query,
165 76
            'count' => 0,
166 76
            'prepared' => microtime(true) - $start,
167 76
            'executed' => 0,
168
        );
169 76
        $this->prepared[$stmt]['params'] = substr_count($query, '?');
170 76
        $this->prepared[$stmt]['type'] = strtoupper(strtok($query, " \r\n\t"));
171 76
        if ($this->prepared[$stmt]['type'] == 'SELECT') {
172 73
            $this->prepared[$stmt]['style'] = $this->dbStyle(strtolower((string) $fetch));
173 73
        }
174 76
        if ($this->prepared[$stmt]['obj'] === false) {
175 8
            unset($this->prepared[$stmt]);
176 8
            if ($error = $this->dbPrepareError()) {
177 8
                static::$logs[$this->id][$stmt]['errors'][] = $error;
178 8
            }
179
180 8
            return false;
181
        }
182
183 75
        return $stmt;
184
    }
185
186 75
    public function execute($stmt, $values = null)
187
    {
188 75
        if (isset($this->prepared[$stmt])) {
189 75
            if (!is_array($values)) {
190 65
                $values = ($this->prepared[$stmt]['params'] == 1) ? array($values) : array();
191 65
            }
192 75
            $start = microtime(true);
193 75
            if ($this->dbExecute($this->prepared[$stmt]['obj'], array_values($values), $stmt)) {
194 75
                static::$logs[$this->id][$stmt]['executed'] += microtime(true) - $start;
195 75
                static::$logs[$this->id][$stmt]['count']++;
196 75
                switch ($this->prepared[$stmt]['type']) {
197 75
                    case 'SELECT':
198 72
                        return true;
199
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
200 30
                    case 'INSERT':
201 20
                        return $this->dbInserted();
202 28
                    default:
203 28
                        return $this->dbAffected($this->prepared[$stmt]['obj']);
204 28
                }
205 2
            } elseif ($error = $this->dbExecuteError($this->prepared[$stmt]['obj'])) {
206 2
                static::$logs[$this->id][$stmt]['errors'][] = $error;
207 2
            }
208 2
        }
209
210 3
        return false;
211
    }
212
213 72
    public function fetch($stmt)
214
    {
215 72
        if (isset($this->prepared[$stmt]) && $this->prepared[$stmt]['type'] == 'SELECT') {
216 72
            return $this->dbFetch($this->prepared[$stmt]['obj'], $this->prepared[$stmt]['style'], $stmt);
217
        }
218
219 1
        return false;
220
    }
221
222 75
    public function close($stmt)
223
    {
224 75
        if (isset($this->prepared[$stmt])) {
225 75
            if (isset($this->prepared[$stmt]['ref'])) {
226 2
                foreach ($this->prepared[$stmt]['ref'] as $value) {
227 2
                    $this->close($value);
228 2
                }
229 2
            }
230 75
            $this->dbClose($this->prepared[$stmt]['obj'], $stmt);
231 75
            unset($this->prepared[$stmt]);
232 75
        }
233 75
    }
234
235 2
    public function debug($query, $values = array())
236
    {
237 2
        $query = (is_array($query)) ? trim(implode("\n", $query)) : trim($query);
238 2
        if (!is_array($values)) {
239 2
            $values = (!empty($values)) ? array($values) : array();
240 2
        }
241 2
        foreach ($values as $string) {
242 2
            if (false !== $replace = strpos($query, '?')) {
243 2
                $query = substr_replace($query, $this->dbEscape($string), $replace, 1);
244 2
            }
245 2
        }
246
247 2
        return $query;
248
    }
249
250 10
    public function log($value = null) // 'sql', 'count', 'prepared', 'executed', 'errors'?, 'average', 'total', 'time'
251
    {
252 10
        $log = (is_numeric($value)) ? static::$logs[$this->id][$value] : end(static::$logs[$this->id]);
253 10
        if (isset($log['errors'])) {
254 7
            $log['errors'] = array_count_values($log['errors']);
255 7
        }
256 10
        $log['average'] = ($log['count'] > 0) ? $log['executed'] / $log['count'] : 0;
257 10
        $log['total'] = $log['prepared'] + $log['executed'];
258 10
        $log['time'] = round($log['total'] * 1000).' ms';
259 10
        if ($log['count'] > 1) {
260 4
            $log['time'] .= ' (~'.round($log['average'] * 1000).' ea)';
261 4
        }
262 10
        if (is_null($value) || is_numeric($value)) {
263 2
            return $log;
264
        }
265
266 9
        return (isset($log[$value])) ? $log[$value] : null;
267
    }
268
}
269