1
|
|
|
<?php |
2
|
|
|
namespace Flipside\Data; |
3
|
|
|
|
4
|
|
|
class SQLDataSet extends DataSet |
5
|
|
|
{ |
6
|
|
|
protected $pdo; |
7
|
|
|
protected $params; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Create a new SQLDataSet |
11
|
|
|
* |
12
|
|
|
* @param array $params An array containing atleast 'dsn' and possibly 'user' and 'pass' |
13
|
|
|
*/ |
14
|
|
|
public function __construct($params) |
15
|
|
|
{ |
16
|
|
|
$this->params = $params; |
17
|
|
View Code Duplication |
if(isset($params['user'])) |
|
|
|
|
18
|
|
|
{ |
19
|
|
|
$this->pdo = new \PDO($params['dsn'], $params['user'], $params['pass']); |
20
|
|
|
} |
21
|
|
|
else |
22
|
|
|
{ |
23
|
|
|
$this->pdo = new \PDO($params['dsn']); |
24
|
|
|
} |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
public function __sleep() |
28
|
|
|
{ |
29
|
|
|
$this->pdo = null; |
30
|
|
|
return array('params'); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
public function __wakeup() |
34
|
|
|
{ |
35
|
|
|
$this->connect(); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
protected function connect() |
39
|
|
|
{ |
40
|
|
|
if(isset($this->params['user'])) |
41
|
|
|
{ |
42
|
|
|
$this->pdo = new \PDO($this->params['dsn'], $this->params['user'], $this->params['pass'], array(PDO::MYSQL_ATTR_FOUND_ROWS => true)); |
43
|
|
|
} |
44
|
|
|
else |
45
|
|
|
{ |
46
|
|
|
$this->pdo = new \PDO($this->params['dsn']); |
47
|
|
|
} |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Get the number of rows affected by the query |
52
|
|
|
* |
53
|
|
|
* @param string $sql The SQL string |
54
|
|
|
* |
55
|
|
|
* @return integer The number of rows affected by the query |
56
|
|
|
*/ |
57
|
|
|
private function _get_row_count_for_query($sql) |
58
|
|
|
{ |
59
|
|
|
$stmt = $this->pdo->query($sql); |
60
|
|
|
if($stmt === false) |
61
|
|
|
{ |
62
|
|
|
return 0; |
63
|
|
|
} |
64
|
|
|
$count = $stmt->rowCount(); |
65
|
|
|
if($count === 0) |
66
|
|
|
{ |
67
|
|
|
$array = $stmt->fetchAll(); |
68
|
|
|
$count = count($array); |
69
|
|
|
} |
70
|
|
|
return $count; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
private function _tableExistsNoPrefix($name) |
74
|
|
|
{ |
75
|
|
|
if($this->_get_row_count_for_query('SHOW TABLES LIKE '.$this->pdo->quote($name)) > 0) |
76
|
|
|
{ |
77
|
|
|
return true; |
78
|
|
|
} |
79
|
|
|
else if($this->_get_row_count_for_query('SELECT * FROM sqlite_master WHERE name LIKE '.$this->pdo->quote($name)) > 0) |
80
|
|
|
{ |
81
|
|
|
return true; |
82
|
|
|
} |
83
|
|
|
return false; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
private function _tableExists($name) |
87
|
|
|
{ |
88
|
|
|
return $this->_tableExistsNoPrefix('tbl'.$name); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
private function _viewExists($name) |
92
|
|
|
{ |
93
|
|
|
return $this->_tableExistsNoPrefix('v'.$name); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function tableExists($name) |
97
|
|
|
{ |
98
|
|
|
if($this->_tableExists($name)) |
99
|
|
|
{ |
100
|
|
|
return true; |
101
|
|
|
} |
102
|
|
|
if($this->_tableExistsNoPrefix($name)) |
103
|
|
|
{ |
104
|
|
|
return true; |
105
|
|
|
} |
106
|
|
|
if($this->_viewExists($name)) |
107
|
|
|
{ |
108
|
|
|
return true; |
109
|
|
|
} |
110
|
|
|
return false; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
public function getTable($name) |
114
|
|
|
{ |
115
|
|
|
if($this->_tableExists($name)) |
116
|
|
|
{ |
117
|
|
|
return new SQLDataTable($this, 'tbl'.$name); |
118
|
|
|
} |
119
|
|
|
if($this->_viewExists($name)) |
120
|
|
|
{ |
121
|
|
|
return new SQLDataTable($this, 'v'.$name); |
122
|
|
|
} |
123
|
|
|
if($this->_tableExistsNoPrefix($name)) |
124
|
|
|
{ |
125
|
|
|
return new SQLDataTable($this, $name); |
126
|
|
|
} |
127
|
|
|
throw new \Exception('No such table '.$name); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* @param boolean|array $sort The array to sort by or false to not sort |
132
|
|
|
*/ |
133
|
|
|
private function getOrderByClause($sort) |
134
|
|
|
{ |
135
|
|
|
if(empty($sort)) |
136
|
|
|
{ |
137
|
|
|
return false; |
138
|
|
|
} |
139
|
|
|
$sql = ' ORDER BY '; |
140
|
|
|
$tmp = array(); |
141
|
|
|
foreach($sort as $sort_col=>$dir) |
|
|
|
|
142
|
|
|
{ |
143
|
|
|
array_push($tmp, $sort_col.' '.($dir === 1 ? 'ASC' : 'DESC')); |
144
|
|
|
} |
145
|
|
|
$sql .= implode($tmp, ','); |
146
|
|
|
return $sql; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Convert OData style $count and $skip into SQL LIMIT |
151
|
|
|
* |
152
|
|
|
* @param boolean|string $count The number of items to return |
153
|
|
|
* @param boolean|string $skip The number of items to skip |
154
|
|
|
*/ |
155
|
|
|
private function getLimitClause($count, $skip) |
156
|
|
|
{ |
157
|
|
|
if($count === false) |
158
|
|
|
{ |
159
|
|
|
return false; |
160
|
|
|
} |
161
|
|
|
$count = intval($count); |
162
|
|
|
if($skip !== false) |
163
|
|
|
{ |
164
|
|
|
$skip = intval($count); |
165
|
|
|
return " LIMIT $skip, $count"; |
166
|
|
|
} |
167
|
|
|
return ' LIMIT '.$count; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Read data from the specified SQL table |
172
|
|
|
* |
173
|
|
|
* @param string $tablename The name of the table to read from |
174
|
|
|
* @param boolean|string $where The where caluse of the SQL statement |
175
|
|
|
* @param string $select The colums to read |
176
|
|
|
* @param boolean|string $count The number of rows to read |
177
|
|
|
* @param boolean|string $skip The number of rows to skip over |
178
|
|
|
* @param boolean|array $sort The array to sort by or false to not sort |
179
|
|
|
* |
180
|
|
|
* @return false|array An array of all the returned records |
181
|
|
|
*/ |
182
|
|
|
public function read($tablename, $where = false, $select = '*', $count = false, $skip = false, $sort = false) |
183
|
|
|
{ |
184
|
|
|
if($select === false) |
185
|
|
|
{ |
186
|
|
|
$select = '*'; |
187
|
|
|
} |
188
|
|
|
$sql = "SELECT $select FROM `$tablename`"; |
189
|
|
|
if($where !== false) |
190
|
|
|
{ |
191
|
|
|
$sql .= ' WHERE '.$where; |
192
|
|
|
} |
193
|
|
|
$tmp = $this->getLimitClause($count, $skip); |
194
|
|
|
if($tmp !== false) |
195
|
|
|
{ |
196
|
|
|
$sql .= $tmp; |
197
|
|
|
} |
198
|
|
|
$tmp = $this->getOrderByClause($sort); |
199
|
|
|
if($tmp !== false) |
200
|
|
|
{ |
201
|
|
|
$sql .= $tmp; |
202
|
|
|
} |
203
|
|
|
$stmt = $this->pdo->query($sql, \PDO::FETCH_ASSOC); |
204
|
|
|
if($stmt === false) |
205
|
|
|
{ |
206
|
|
|
return false; |
207
|
|
|
} |
208
|
|
|
$ret = $stmt->fetchAll(); |
209
|
|
|
if(empty($ret)) |
210
|
|
|
{ |
211
|
|
|
return false; |
212
|
|
|
} |
213
|
|
|
return $ret; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Perform an SQL update on the specified table |
218
|
|
|
* |
219
|
|
|
* @param string $tablename The name of the table to insert to |
220
|
|
|
* @param string $where The where clause in SQL format |
221
|
|
|
* @param mixed $data The data to write to the table |
222
|
|
|
* |
223
|
|
|
* @return boolean true if successful, false otherwise |
224
|
|
|
*/ |
225
|
|
|
public function update($tablename, $where, $data) |
226
|
|
|
{ |
227
|
|
|
$set = array(); |
228
|
|
|
if(is_object($data)) |
229
|
|
|
{ |
230
|
|
|
$data = (array)$data; |
231
|
|
|
} |
232
|
|
|
$cols = array_keys($data); |
233
|
|
|
$count = count($cols); |
234
|
|
|
for($i = 0; $i < $count; $i++) |
235
|
|
|
{ |
236
|
|
|
if($data[$cols[$i]] === null) |
237
|
|
|
{ |
238
|
|
|
array_push($set, $cols[$i].'=NULL'); |
239
|
|
|
} |
240
|
|
|
else |
241
|
|
|
{ |
242
|
|
|
array_push($set, $cols[$i].'='.$this->pdo->quote($data[$cols[$i]])); |
243
|
|
|
} |
244
|
|
|
} |
245
|
|
|
$set = implode(',', $set); |
246
|
|
|
$sql = "UPDATE $tablename SET $set WHERE $where"; |
247
|
|
|
$stmt = $this->pdo->query($sql); |
248
|
|
|
if($stmt === false) |
249
|
|
|
{ |
250
|
|
View Code Duplication |
if (php_sapi_name() !== "cli") { |
|
|
|
|
251
|
|
|
error_log('DB query failed. '.print_r($this->pdo->errorInfo(), true)); |
252
|
|
|
} |
253
|
|
|
return false; |
254
|
|
|
} |
255
|
|
|
else if($stmt->rowCount() === 0) |
256
|
|
|
{ |
257
|
|
|
$data = $this->read($tablename, $where); |
258
|
|
|
if(empty($data)) |
259
|
|
|
{ |
260
|
|
|
return false; |
261
|
|
|
} |
262
|
|
|
} |
263
|
|
|
return true; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Perform an SQL insert on the specified table |
268
|
|
|
* |
269
|
|
|
* @param string $tablename The name of the table to insert to |
270
|
|
|
* @param mixed $data The data to write to the table |
271
|
|
|
* |
272
|
|
|
* @return boolean true if successful, false otherwise |
273
|
|
|
*/ |
274
|
|
|
public function create($tablename, $data) |
275
|
|
|
{ |
276
|
|
|
$set = array(); |
277
|
|
|
if(is_object($data)) |
278
|
|
|
{ |
279
|
|
|
$data = (array)$data; |
280
|
|
|
} |
281
|
|
|
$cols = array_keys($data); |
282
|
|
|
$count = count($cols); |
283
|
|
|
for($i = 0; $i < $count; $i++) |
284
|
|
|
{ |
285
|
|
|
if($data[$cols[$i]] === null) |
286
|
|
|
{ |
287
|
|
|
array_push($set, 'NULL'); |
288
|
|
|
} |
289
|
|
|
else |
290
|
|
|
{ |
291
|
|
|
array_push($set, $this->pdo->quote($data[$cols[$i]])); |
292
|
|
|
} |
293
|
|
|
} |
294
|
|
|
$cols = implode(',', $cols); |
295
|
|
|
$set = implode(',', $set); |
296
|
|
|
$sql = "INSERT INTO $tablename ($cols) VALUES ($set);"; |
297
|
|
|
if($this->pdo->exec($sql) === false) |
298
|
|
|
{ |
299
|
|
View Code Duplication |
if (php_sapi_name() !== "cli") { |
|
|
|
|
300
|
|
|
error_log('DB query failed. '.print_r($this->pdo->errorInfo(), true)); |
301
|
|
|
} |
302
|
|
|
return false; |
303
|
|
|
} |
304
|
|
|
return true; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* Perform an SQL delete on the specified table |
309
|
|
|
* |
310
|
|
|
* @param string $tablename The name of the table to insert to |
311
|
|
|
* @param string $where The where clause in SQL format |
312
|
|
|
* |
313
|
|
|
* @return boolean true if successful, false otherwise |
314
|
|
|
*/ |
315
|
|
|
public function delete($tablename, $where) |
316
|
|
|
{ |
317
|
|
|
$sql = "DELETE FROM $tablename WHERE $where"; |
318
|
|
|
if($this->pdo->exec($sql) === false) |
319
|
|
|
{ |
320
|
|
|
return false; |
321
|
|
|
} |
322
|
|
|
return true; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* Perform an SQL query |
327
|
|
|
* |
328
|
|
|
* @param string $sql The raw SQL |
329
|
|
|
* |
330
|
|
|
* @return mixed false on a failure, an array of data otherwise |
331
|
|
|
*/ |
332
|
|
|
public function raw_query($sql) |
333
|
|
|
{ |
334
|
|
|
$stmt = $this->pdo->query($sql, \PDO::FETCH_ASSOC); |
335
|
|
|
if($stmt === false) |
336
|
|
|
{ |
337
|
|
|
return false; |
338
|
|
|
} |
339
|
|
|
$ret = $stmt->fetchAll(); |
340
|
|
|
return $ret; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
public function getLastError() |
344
|
|
|
{ |
345
|
|
|
return $this->pdo->errorInfo(); |
346
|
|
|
} |
347
|
|
|
} |
348
|
|
|
/* vim: set tabstop=4 shiftwidth=4 expandtab: */ |
349
|
|
|
|
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.