Passed
Push — hypernext ( b2802c...e207e0 )
by Nico
11:21
created

src/classes/Db.php (5 issues)

Labels
Severity
1
<?php
2
/**
3
 * @author Nicolas CARPi <[email protected]>
4
 * @copyright 2012 Nicolas CARPi
5
 * @see https://www.elabftw.net Official website
6
 * @license AGPL-3.0
7
 * @package elabftw
8
 */
9
declare(strict_types=1);
10
11
namespace Elabftw\Elabftw;
12
13
use const DB_CERT_PATH;
14
use const DB_HOST;
15
use const DB_NAME;
16
use const DB_PASSWORD;
17
use const DB_PORT;
18
use const DB_USER;
19
use Elabftw\Exceptions\DatabaseErrorException;
20
use PDO;
21
use PDOException;
22
use PDOStatement;
23
24
/**
25
 * Connect to the database with a singleton class
26
 */
27
final class Db
28
{
29
    private PDO $connection;
30
31
    // store the single instance of the class
32
    private static ?Db $instance = null;
33
34
    // total number of queries
35
    private int $nq = 0;
36 1
37
    /**
38 1
     * Construct of a singleton is private
39
     *
40 1
     * @throws PDOException If it cannot connect to the database
41
     */
42 1
    private function __construct()
43
    {
44 1
        $pdo_options = array();
45
        // throw exception if error
46
        $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
47 1
        // use persistent mode for connection to MySQL
48 1
        $pdo_options[PDO::ATTR_PERSISTENT] = true;
49
        // only return a named array
50
        $pdo_options[PDO::ATTR_DEFAULT_FETCH_MODE] = PDO::FETCH_ASSOC;
51 1
        if (defined('DB_CERT_PATH') && !empty(DB_CERT_PATH)) {
1 ignored issue
show
The constant DB_CERT_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
52 1
            $pdo_options[PDO::MYSQL_ATTR_SSL_CA] = DB_CERT_PATH;
53 1
        }
54 1
55 1
        // be backward compatible
56
        if (!defined('DB_PORT')) {
57
            define('DB_PORT', '3306');
58 1
        }
59
60
        $this->connection = new PDO(
61
            'mysql:host=' . DB_HOST . ';port=' . DB_PORT . ';dbname=' .
0 ignored issues
show
The constant DB_HOST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
62
            DB_NAME,
0 ignored issues
show
The constant DB_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
63
            DB_USER,
0 ignored issues
show
The constant DB_USER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
64
            DB_PASSWORD,
0 ignored issues
show
The constant DB_PASSWORD was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
65
            $pdo_options
66
        );
67
    }
68
69
    /**
70
     * Disallow cloning the class
71
     * @norector \Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector
72
     */
73
    private function __clone()
74
    {
75
    }
76
77
    /**
78
     * Disallow wakeup also
79
     * @norector \Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector
80 100
     */
81
    public function __wakeup()
82 100
    {
83 1
    }
84
85
    /**
86 100
     * Return the instance of the class
87
     *
88
     * @throws PDOException If connection to database failed
89
     * @return Db The instance of the class
90
     */
91
    public static function getConnection(): self
92
    {
93
        if (self::$instance === null) {
94
            self::$instance = new self();
95 100
        }
96
97 100
        return self::$instance;
98 100
    }
99
100
    /**
101
     * Prepare a query
102
     *
103
     * @param string $sql The SQL query
104
     */
105
    public function prepare(string $sql): PDOStatement
106
    {
107
        $this->nq++;
108
        return $this->connection->prepare($sql);
109
    }
110
111
    /**
112
     * Execute a prepared statement and throw exception if it doesn't return true
113
     *
114
     * @param array<mixed>|null $arr optional array to execute
115
     */
116
    public function execute(PDOStatement $req, ?array $arr = null): bool
117
    {
118
        try {
119
            $res = $req->execute($arr);
120
        } catch (PDOException $e) {
121
            throw new DatabaseErrorException($e);
122 21
        }
123
        if (!$res) {
124 21
            throw new DatabaseErrorException();
125
        }
126
        return $res;
127
    }
128
129
    /**
130
     * Force fetchAll to return an array or throw exception if result is false
131
     * because this is hard to test
132
     */
133
    public function fetchAll(PDOStatement $req): array
134
    {
135
        $res = $req->fetchAll();
136
        if ($res === false) {
137
            throw new DatabaseErrorException();
138
        }
139
        return $res;
140
    }
141
142
    /**
143
     * Make a simple query
144
     *
145
     * @param string $sql The SQL query
146
     */
147
    public function q(string $sql): PDOStatement
148
    {
149
        $res = $this->connection->query($sql);
150
        if ($res === false) {
151
            throw new DatabaseErrorException();
152
        }
153
154
        return $res;
155
    }
156
157
    /**
158
     * Return the last id inserted
159
     */
160
    public function lastInsertId(): int
161
    {
162
        return (int) $this->connection->lastInsertId();
163
    }
164
165
    /**
166
     * Get number of SQL queries for the page
167
     */
168
    public function getNumberOfQueries(): int
169
    {
170
        return $this->nq;
171
    }
172
}
173