1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* |
4
|
|
|
* @filesource PDODriverAbstract.php |
5
|
|
|
* @created 04.11.2015 |
6
|
|
|
* @package chillerlan\Database\Drivers\PDO |
7
|
|
|
* @author Smiley <[email protected]> |
8
|
|
|
* @copyright 2015 Smiley |
9
|
|
|
* @license MIT |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace chillerlan\Database\Drivers\PDO; |
13
|
|
|
|
14
|
|
|
use chillerlan\Database\DBException; |
15
|
|
|
use chillerlan\Database\Drivers\DBDriverAbstract; |
16
|
|
|
use chillerlan\Database\Drivers\DBDriverInterface; |
17
|
|
|
use PDO; |
18
|
|
|
use PDOException; |
19
|
|
|
use PDOStatement; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Class PDODriverAbstract |
23
|
|
|
* |
24
|
|
|
* @see http://php.net/manual/pdo.constants.php |
25
|
|
|
*/ |
26
|
|
|
abstract class PDODriverAbstract extends DBDriverAbstract{ |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Holds the database resource object |
30
|
|
|
* |
31
|
|
|
* @var PDO |
32
|
|
|
*/ |
33
|
|
|
protected $db; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Some basic PDO options |
37
|
|
|
* |
38
|
|
|
* @see http://php.net/manual/pdo.getattribute.php PDO::getAttribute |
39
|
|
|
* |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
protected $pdo_options |
43
|
|
|
= [ |
44
|
|
|
PDO::ATTR_CASE => PDO::CASE_NATURAL, |
45
|
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, |
46
|
|
|
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, |
47
|
|
|
PDO::ATTR_STRINGIFY_FETCHES => false, |
48
|
|
|
PDO::ATTR_EMULATE_PREPARES => false, |
49
|
|
|
]; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* The PDO drivername which is being used in the DSN |
53
|
|
|
* |
54
|
|
|
* @var string |
55
|
|
|
*/ |
56
|
|
|
protected $drivername; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* This array holds one or more key=>value pairs to set attribute values for the PDOStatement object that this |
60
|
|
|
* method returns. You would most commonly use this to set the PDO::ATTR_CURSOR value to PDO::CURSOR_SCROLL to |
61
|
|
|
* request a scrollable cursor. |
62
|
|
|
* |
63
|
|
|
* @var array |
64
|
|
|
*/ |
65
|
|
|
protected $pdo_stmt_options = []; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Returns a DSN string using the given options |
69
|
|
|
* |
70
|
|
|
* @link http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html#4.4 |
71
|
|
|
* |
72
|
|
|
* @return string DSN |
73
|
|
|
*/ |
74
|
|
View Code Duplication |
protected function getDSN():string{ |
|
|
|
|
75
|
|
|
$dsn = $this->drivername; |
76
|
|
|
|
77
|
|
|
if($this->options->socket){ |
78
|
|
|
$dsn .= ':unix_socket='.$this->options->socket; |
79
|
|
|
} |
80
|
|
|
else{ |
81
|
|
|
$dsn .= ':host='.$this->options->host; |
82
|
|
|
$dsn .= (bool)$this->options->port ? ';port='.$this->options->port : ''; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
$dsn .= ';dbname='.$this->options->database; |
86
|
|
|
|
87
|
|
|
return $dsn; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Establishes a database connection and returns the connection object |
92
|
|
|
* |
93
|
|
|
* @return \chillerlan\Database\Drivers\DBDriverInterface |
94
|
|
|
* @throws \chillerlan\Database\DBException |
95
|
|
|
*/ |
96
|
|
View Code Duplication |
public function connect():DBDriverInterface{ |
|
|
|
|
97
|
|
|
|
98
|
|
|
if($this->db instanceof PDO){ |
99
|
|
|
return $this; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
if($this->options->use_ssl){ |
103
|
|
|
$this->pdo_options += [ |
104
|
|
|
PDO::MYSQL_ATTR_SSL_KEY => $this->options->ssl_key, |
105
|
|
|
PDO::MYSQL_ATTR_SSL_CERT => $this->options->ssl_cert, |
106
|
|
|
PDO::MYSQL_ATTR_SSL_CA => $this->options->ssl_ca, |
107
|
|
|
PDO::MYSQL_ATTR_SSL_CAPATH => $this->options->ssl_capath, |
108
|
|
|
PDO::MYSQL_ATTR_SSL_CIPHER => $this->options->ssl_cipher, |
109
|
|
|
]; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
try{ |
113
|
|
|
$this->db = new PDO($this->getDSN(), $this->options->username, $this->options->password, $this->pdo_options); |
114
|
|
|
} |
115
|
|
|
catch(PDOException $PDOException){ |
116
|
|
|
throw new DBException($PDOException->getMessage()); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
return $this; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Closes a database connection |
124
|
|
|
* |
125
|
|
|
* @return bool |
126
|
|
|
*/ |
127
|
|
|
public function disconnect():bool{ |
128
|
|
|
$this->db = null; |
129
|
|
|
|
130
|
|
|
return true; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Returns info about the used php client |
135
|
|
|
* |
136
|
|
|
* @return string php's database client string |
137
|
|
|
*/ |
138
|
|
|
public function getClientInfo():string{ |
139
|
|
|
return $this->db->getAttribute(PDO::ATTR_CLIENT_VERSION); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Returns info about the database server |
144
|
|
|
* |
145
|
|
|
* @return string database's serverinfo string |
146
|
|
|
*/ |
147
|
|
|
public function getServerInfo():string{ |
148
|
|
|
return $this->db->getAttribute(PDO::ATTR_SERVER_INFO); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @param $data |
153
|
|
|
* |
154
|
|
|
* @return string |
155
|
|
|
*/ |
156
|
|
|
protected function __escape($data){ |
157
|
|
|
return $this->db->quote($data); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @param \PDOStatement $stmt |
162
|
|
|
* @param array $values |
163
|
|
|
* |
164
|
|
|
* @return void |
165
|
|
|
*/ |
166
|
|
View Code Duplication |
protected function bindParams(PDOStatement &$stmt, array $values){ |
|
|
|
|
167
|
|
|
$param_no = 1; |
168
|
|
|
|
169
|
|
|
foreach($values as $v){ |
170
|
|
|
|
171
|
|
|
switch(gettype($v)){ |
172
|
|
|
case 'boolean': |
173
|
|
|
$type = PDO::PARAM_BOOL; |
174
|
|
|
break; |
175
|
|
|
case 'integer': |
176
|
|
|
$type = PDO::PARAM_INT; |
177
|
|
|
break; |
178
|
|
|
case 'NULL': |
179
|
|
|
$type = PDO::PARAM_NULL; |
180
|
|
|
break; |
181
|
|
|
default: |
182
|
|
|
$type = PDO::PARAM_STR; |
183
|
|
|
break; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
$stmt->bindValue($param_no, $v, $type); |
187
|
|
|
$param_no++; |
188
|
|
|
} |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Returns the last insert id (if present) |
193
|
|
|
* |
194
|
|
|
* @link http://php.net/manual/pdo.lastinsertid.php |
195
|
|
|
* @return string |
196
|
|
|
*/ |
197
|
|
|
protected function insertID():string{ |
198
|
|
|
return $this->db->lastInsertId(); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @param $stmt |
203
|
|
|
* @param string|null $index |
204
|
|
|
* @param bool $assoc |
205
|
|
|
* |
206
|
|
|
* @return bool|\chillerlan\Database\DBResult |
207
|
|
|
*/ |
208
|
|
|
protected function __getResult($stmt, string $index = null, bool $assoc = true){ |
209
|
|
|
|
210
|
|
|
if(is_bool($stmt)){ |
211
|
|
|
return $stmt; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
return $this->getResult([$stmt, 'fetch'], [$assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM], $index, $assoc); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* @param string $sql |
219
|
|
|
* @param string|null $index |
220
|
|
|
* @param bool $assoc |
221
|
|
|
* |
222
|
|
|
* @return bool|\chillerlan\Database\DBResult |
223
|
|
|
*/ |
224
|
|
|
protected function __raw(string $sql, string $index = null, bool $assoc = true){ |
225
|
|
|
return $this->__getResult($this->db->query($sql), $index, $assoc); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* @param string $sql |
230
|
|
|
* @param array $values |
231
|
|
|
* @param string|null $index |
232
|
|
|
* @param bool $assoc |
233
|
|
|
* |
234
|
|
|
* @return bool|\chillerlan\Database\DBResult |
235
|
|
|
*/ |
236
|
|
|
protected function __prepared(string $sql, array $values = [], string $index = null, bool $assoc = true){ |
237
|
|
|
$stmt = $this->db->prepare($sql, $this->pdo_stmt_options); |
238
|
|
|
|
239
|
|
|
if(!empty($values)){ |
240
|
|
|
$this->bindParams($stmt, $values); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$stmt->execute(); |
244
|
|
|
|
245
|
|
|
return $this->__getResult($stmt, $index, $assoc); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* @param string $sql |
250
|
|
|
* @param array $values |
251
|
|
|
* |
252
|
|
|
* @return bool |
253
|
|
|
*/ |
254
|
|
View Code Duplication |
protected function __multi(string $sql, array $values){ |
|
|
|
|
255
|
|
|
$stmt = $this->db->prepare($sql, $this->pdo_stmt_options); |
256
|
|
|
|
257
|
|
|
foreach($values as $row){ |
258
|
|
|
$this->bindParams($stmt, $row); |
259
|
|
|
$stmt->execute(); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
$stmt = null; |
|
|
|
|
263
|
|
|
|
264
|
|
|
return true; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* @param string $sql |
269
|
|
|
* @param array $data |
270
|
|
|
* @param $callback |
271
|
|
|
* |
272
|
|
|
* @return bool |
273
|
|
|
*/ |
274
|
|
View Code Duplication |
protected function __multi_callback(string $sql, array $data, $callback){ |
|
|
|
|
275
|
|
|
$stmt = $this->db->prepare($sql, $this->pdo_stmt_options); |
276
|
|
|
|
277
|
|
|
foreach($data as $row){ |
278
|
|
|
$this->bindParams($stmt, call_user_func_array($callback, [$row])); |
279
|
|
|
$stmt->execute(); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
$stmt = null; |
|
|
|
|
283
|
|
|
|
284
|
|
|
return true; |
285
|
|
|
} |
286
|
|
|
} |
287
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.