GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 1f2713...a43f99 )
by Andreas
15:48
created

Db::commit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * Starlit Db.
4
 *
5
 * @copyright Copyright (c) 2016 Starweb / Ehandelslogik i Lund AB
6
 * @license   BSD 3-Clause
7
 */
8
9
namespace Starlit\Db;
10
11
use Starlit\Db\Exception\ConnectionException;
12
use Starlit\Db\Exception\QueryException;
13
use \PDO;
14
use \PDOException;
15
use \PDOStatement;
16
17
/**
18
 * Extended PDO database wrapper.
19
 *
20
 * @author Andreas Nilsson <http://github.com/jandreasn>
21
 */
22
class Db
23
{
24
    /**
25
     * Database handle/connection.
26
     *
27
     * @var PDO
28
     */
29
    protected $pdo;
30
31
    /**
32
     * @var string
33
     */
34
    protected $dsn;
35
36
    /**
37
     * @var string
38
     */
39
    protected $username;
40
41
    /**
42
     * @var string
43
     */
44
    protected $password;
45
46
    /**
47
     * @var array
48
     */
49
    protected $options;
50
51
    /**
52
     * @var bool
53
     */
54
    protected $hasActiveTransaction = false;
55
56
    /**
57
     * Constructor.
58
     *
59
     * @param string|PDO  $hostDsnOrPdo A MySQL host, a dsn or an existing PDO instance.
60
     * @param string|null $username
61
     * @param string|null $password
62
     * @param string|null $database
63
     * @param array       $options
64
     */
65 19
    public function __construct(
66
        $hostDsnOrPdo,
67
        $username = null,
68
        $password = null,
69
        $database = null,
70
        array $options = []
71
    ) {
72 19
        if ($hostDsnOrPdo instanceof PDO) {
73 19
            $this->pdo = $hostDsnOrPdo;
74 19
        } elseif (strpos($hostDsnOrPdo, ':') !== false) {
75
            $this->dsn = $hostDsnOrPdo;
76
        } else {
77
            $this->dsn = "mysql:host={$hostDsnOrPdo}" . ($database ? ";dbname={$database}" : '');
78
        }
79
80 19
        $this->username = $username;
81 19
        $this->password = $password;
82 19
        $this->options = $options;
83 19
    }
84
85
    /**
86
     */
87 13
    public function connect()
88
    {
89 13
        if ($this->isConnected()) {
90 13
            return;
91
        }
92
93
        $retries = isset($this->options['connectRetries'])? $this->options['connectRetries'] : 0;
94
        do {
95
            try {
96
                $defaultPdoOptions = [
97
                    PDO::ATTR_TIMEOUT            => 5,
98
                    // We want emulation by default (faster for single queries). Disable if you want to
99
                    // use proper native prepared statements
100
                    PDO::ATTR_EMULATE_PREPARES   => true,
101
                    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
102
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
103
                ];
104
                $pdoOptions = $defaultPdoOptions + (isset($this->options['pdo']) ? $this->options['pdo'] : []);
105
106
                $this->pdo = new PDO(
107
                    $this->dsn,
108
                    $this->username,
109
                    $this->password,
110
                    $pdoOptions
111
                );
112
113
                return;
114
            } catch (PDOException $e) {
115
                if ($this->isConnectionExceptionCausedByConnection($e) && $retries > 0) {
116
                    // Sleep for 100 - 500 ms until next retry
117
                    usleep(rand(100000, 500000));
118
                } else {
119
                    throw new ConnectionException($e);
120
                }
121
            }
122
123
        } while ($retries-- > 0);
124
    }
125
126
    /**
127
     * @param PDOException $exception
128
     * @return bool
129
     */
130
    private function isConnectionExceptionCausedByConnection(PDOException $exception)
131
    {
132
        return in_array($exception->getCode(), [
133
            2002, // Can't connect to MySQL server (Socket)
134
            2003, // Can't connect to MySQL server (TCP)
135
            2006, // MySQL server has gone away
136
            2013, // Lost connection to MySQL server during query
137
        ]);
138
    }
139
140
    /**
141
     * Close the database connection.
142
     */
143 1
    public function disconnect()
144
    {
145 1
        $this->pdo = null;
146 1
    }
147
148
    /**
149
     */
150 1
    public function reconnect()
151
    {
152 1
        $this->disconnect();
153 1
        $this->connect();
154 1
    }
155
156
    /**
157
     * Check if database connection is open.
158
     *
159
     * @return bool
160
     */
161 14
    public function isConnected()
162
    {
163 14
        return ($this->pdo instanceof PDO);
164
    }
165
166
    /**
167
     * Returns the PDO handle.
168
     *
169
     * Can be used to gain access to any special PDO methods.
170
     *
171
     * @return PDO
172
     */
173 2
    public function getPdo()
174
    {
175 2
        return $this->pdo;
176
    }
177
178
    /**
179
     * Creates and executes a PDO statement.
180
     *
181
     * @param string $sql
182
     * @param array  $parameters
183
     * @return PDOStatement
184
     */
185 5
    protected function executeQuery($sql, array $parameters = [])
186
    {
187 5
        $this->connect();
188
189
        try {
190 5
            $pdoStatement = $this->pdo->prepare($sql);
191 4
            $pdoStatement->execute($this->prepareParameters($parameters));
192
193 4
            return $pdoStatement;
194 1
        } catch (PDOException $e) {
195 1
            throw new QueryException($e, $sql, $parameters);
196
        }
197
    }
198
199
    /**
200
     * Execute an SQL statement and return the number of affected rows.
201
     *
202
     * @param string $sql
203
     * @param array  $parameters
204
     * @return int The number of rows affected
205
     */
206 2
    public function exec($sql, array $parameters = [])
207
    {
208 2
        $statement = $this->executeQuery($sql, $parameters);
209
210 1
        return $statement->rowCount();
211
    }
212
213
    /**
214
     * Execute an SQL statement and return the first row.
215
     *
216
     * @param string $sql
217
     * @param array  $parameters
218
     * @param bool   $indexedKeys
219
     * @return array|false
220
     */
221 1
    public function fetchRow($sql, array $parameters = [], $indexedKeys = false)
222
    {
223 1
        $statement = $this->executeQuery($sql, $parameters);
224
225 1
        return $statement->fetch($indexedKeys ? PDO::FETCH_NUM : PDO::FETCH_ASSOC);
226
    }
227
228
    /**
229
     * Execute an SQL statement and return all rows as an array.
230
     *
231
     * @param string $sql
232
     * @param array  $parameters
233
     * @param bool   $indexedKeys
234
     * @return array
235
     */
236 1
    public function fetchRows($sql, array $parameters = [], $indexedKeys = false)
237
    {
238 1
        $statement = $this->executeQuery($sql, $parameters);
239
240 1
        return $statement->fetchAll($indexedKeys ? PDO::FETCH_NUM : PDO::FETCH_ASSOC);
241
    }
242
243
    /**
244
     * Execute an SQL statement and return the first column of the first row.
245
     *
246
     * @param string $sql
247
     * @param array  $parameters
248
     * @return string|false
249
     */
250 1
    public function fetchValue($sql, array $parameters = [])
251
    {
252 1
        $statement = $this->executeQuery($sql, $parameters);
253
254 1
        return $statement->fetchColumn(0);
255
    }
256
257
    /**
258
     * Quote a value for a safe use in query (eg. bla'bla -> 'bla''bla').
259
     *
260
     * @param mixed $value
261
     * @return string
262
     */
263 1
    public function quote($value)
264
    {
265 1
        $this->connect();
266
267 1
        return $this->pdo->quote($value);
268
    }
269
270
    /**
271
     * Get id of the last inserted row.
272
     *
273
     * @return int
274
     */
275 1
    public function getLastInsertId()
276
    {
277 1
        $this->connect();
278
279 1
        return (int) $this->pdo->lastInsertId();
280
    }
281
282
    /**
283
     * Prepare parameters for database use.
284
     *
285
     * @param array $parameters
286
     * @return array
287
     */
288 4
    protected function prepareParameters(array $parameters = [])
289
    {
290 4
        foreach ($parameters as &$parameterValue) {
291 4
            if (is_bool($parameterValue)) {
292 1
                $parameterValue = (int) $parameterValue;
293 1
            } elseif (!is_scalar($parameterValue) && $parameterValue !== null) {
294 4
                throw new \InvalidArgumentException(
295 4
                    sprintf('Invalid db parameter type "%s"', gettype($parameterValue))
296
                );
297 4
            }
298
        }
299
        unset($parameterValue);
300
301
        return $parameters;
302
    }
303
304
    /**
305
     * Begin transaction (turns off autocommit mode).
306 4
     *
307
     * @param bool $onlyIfNoActiveTransaction
308 4
     * @return bool
309
     */
310 4
    public function beginTransaction($onlyIfNoActiveTransaction = false)
311 1
    {
312
        $this->connect();
313
314 4
        if ($onlyIfNoActiveTransaction && $this->hasActiveTransaction()) {
315 4
            return false;
316
        }
317 4
318
        $this->pdo->beginTransaction();
319
        $this->hasActiveTransaction = true;
320
321
        return true;
322
    }
323 2
324
    /**
325 2
     * Commits current active transaction (restores autocommit mode).
326
     */
327 2
    public function commit()
328 2
    {
329 2
        $this->connect();
330
331
        $this->pdo->commit();
332
        $this->hasActiveTransaction = false;
333
    }
334 2
335
    /**
336 2
     * Rolls back current active transaction (restores autocommit mode).
337
     */
338 2
    public function rollBack()
339 2
    {
340 2
        $this->connect();
341
342
        $this->pdo->rollBack();
343
        $this->hasActiveTransaction = false;
344
    }
345 3
346
    /**
347 3
     * @return bool
348
     */
349
    public function hasActiveTransaction()
350
    {
351
        return $this->hasActiveTransaction;
352
    }
353
354
    /**
355 1
     * @param string $table
356
     * @param array $data
357 1
     * @return int The number of rows affected
358 1
     */
359
    public function insert($table, array $data)
360 1
    {
361 1
        $fields = array_keys($data);
362 1
        $valuePlaceholders = implode(', ', array_fill(0, count($fields), '?'));
363 1
364
        $sql = 'INSERT INTO `' . $table . '` '
365 1
            . ($fields ? '(`' . implode('`, `', $fields) . '`)' : '') . "\n"
366
            . ($fields ? 'VALUES (' . $valuePlaceholders . ')' : 'VALUES ()')
367
        ;
368
369
        return $this->exec($sql, array_values($data));
370
    }
371
372
    /**
373
     * @param string $table
374
     * @param array  $data
375 1
     * @param string $whereSql
376
     * @param array  $whereParameters
377 1
     * @return int The number of rows affected
378 1
     */
379 1
    public function update($table, array $data, $whereSql = '', array $whereParameters = [])
380 1
    {
381
        $setStrings = [];
382 1
        foreach (array_keys($data) as $field) {
383 1
            $setStrings[] = '`' . $field . '` = ?';
384 1
        }
385 1
386
        $sql = 'UPDATE `' . $table . "`\n"
387 1
            . 'SET ' . implode(', ', $setStrings)
388
            . ($whereSql ? "\nWHERE " . $whereSql : '')
389 1
        ;
390
391
        $parameters = array_merge(array_values($data), $whereParameters);
392
393
        return $this->exec($sql, $parameters);
394
    }
395
}
396