|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace BfwSql; |
|
4
|
|
|
|
|
5
|
|
|
use \Exception; |
|
6
|
|
|
|
|
7
|
|
|
/** |
|
8
|
|
|
* Abstract class used for all query writer class. |
|
9
|
|
|
* |
|
10
|
|
|
* @package bfw-sql |
|
11
|
|
|
* @author Vermeulen Maxime <[email protected]> |
|
12
|
|
|
* @version 2.0 |
|
13
|
|
|
*/ |
|
14
|
|
|
abstract class SqlActions |
|
15
|
|
|
{ |
|
16
|
|
|
/** |
|
17
|
|
|
* @var \BfwSql\SqlConnect $sqlConnect SqlConnect object |
|
18
|
|
|
*/ |
|
19
|
|
|
protected $sqlConnect; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* @var string $assembledRequest The request will be executed |
|
23
|
|
|
*/ |
|
24
|
|
|
protected $assembledRequest = ''; |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* @var boolean $isPreparedRequest If is a prepared request |
|
28
|
|
|
*/ |
|
29
|
|
|
protected $isPreparedRequest = true; |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* @var string $tableName The main table name for request |
|
33
|
|
|
*/ |
|
34
|
|
|
protected $tableName = ''; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* @var array $columns List of impacted columns by the request |
|
38
|
|
|
*/ |
|
39
|
|
|
protected $columns = array(); |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* @var string[] $where All filter use in where part of the request |
|
43
|
|
|
*/ |
|
44
|
|
|
protected $where = array(); |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* @var string[] $preparedRequestArgs Arguments used by prepared request |
|
48
|
|
|
*/ |
|
49
|
|
|
protected $preparedRequestArgs = array(); |
|
50
|
|
|
|
|
51
|
|
|
/** |
|
52
|
|
|
* @var array $prepareDriversOptions SGBD driver option used for |
|
53
|
|
|
* prepared request |
|
54
|
|
|
* |
|
55
|
|
|
* @link http://php.net/manual/en/pdo.prepare.php |
|
56
|
|
|
*/ |
|
57
|
|
|
protected $prepareDriversOptions = array(); |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* @var boolean $noResult If request has sent no result. |
|
61
|
|
|
*/ |
|
62
|
|
|
protected $noResult = false; |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* @var \PDOStatement $lastRequestStatement The PDOStatement pour the |
|
66
|
|
|
* last request executed. |
|
67
|
|
|
*/ |
|
68
|
|
|
protected $lastRequestStatement; |
|
69
|
|
|
|
|
70
|
|
|
/** |
|
71
|
|
|
* Constructor |
|
72
|
|
|
* |
|
73
|
|
|
* @param \BfwSql\SqlConnect $sqlConnect Instance of SGBD connexion |
|
74
|
|
|
*/ |
|
75
|
|
|
public function __construct(SqlConnect $sqlConnect) |
|
76
|
|
|
{ |
|
77
|
|
|
$this->sqlConnect = $sqlConnect; |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* Getter to access at sqlConnect property |
|
82
|
|
|
* |
|
83
|
|
|
* @return \BfwSql\SqlConnect |
|
84
|
|
|
*/ |
|
85
|
|
|
public function getSqlConnect() |
|
86
|
|
|
{ |
|
87
|
|
|
return $this->sqlConnect; |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Setter to enable or disable prepared request |
|
92
|
|
|
* |
|
93
|
|
|
* @param boolean $preparedRequestStatus The new status for prepared request |
|
94
|
|
|
* |
|
95
|
|
|
* @return void |
|
96
|
|
|
*/ |
|
97
|
|
|
public function setIsPreparedRequest($preparedRequestStatus) |
|
98
|
|
|
{ |
|
99
|
|
|
$this->isPreparedRequest = (bool) $preparedRequestStatus; |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
/** |
|
103
|
|
|
* Define driver options to prepared request |
|
104
|
|
|
* |
|
105
|
|
|
* @link http://php.net/manual/fr/pdo.prepare.php |
|
106
|
|
|
* |
|
107
|
|
|
* @param array $driverOptions Drivers options |
|
108
|
|
|
* |
|
109
|
|
|
* @return void |
|
110
|
|
|
*/ |
|
111
|
|
|
public function setPrepareDriversOptions($driverOptions) |
|
112
|
|
|
{ |
|
113
|
|
|
$this->prepareDriversOptions = $driverOptions; |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
/** |
|
117
|
|
|
* Check if a request is assemble or not. |
|
118
|
|
|
* If not, run the method assembleRequest. |
|
119
|
|
|
* |
|
120
|
|
|
* @return void |
|
121
|
|
|
*/ |
|
122
|
|
|
public function requestIsAssembled() |
|
123
|
|
|
{ |
|
124
|
|
|
if($this->assembledRequest == '') |
|
125
|
|
|
{ |
|
126
|
|
|
$this->assembleRequest(); |
|
127
|
|
|
} |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
/** |
|
131
|
|
|
* Write the query |
|
132
|
|
|
* |
|
133
|
|
|
* @return void |
|
134
|
|
|
*/ |
|
135
|
|
|
protected abstract function assembleRequest(); |
|
136
|
|
|
|
|
137
|
|
|
/** |
|
138
|
|
|
* Return the assembled request |
|
139
|
|
|
* |
|
140
|
|
|
* @return string |
|
141
|
|
|
*/ |
|
142
|
|
|
public function assemble() |
|
143
|
|
|
{ |
|
144
|
|
|
$this->requestIsAssembled(); |
|
145
|
|
|
return $this->assembledRequest; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* Execute the assembled request |
|
150
|
|
|
* |
|
151
|
|
|
* @return array The pdo errorInfo array |
|
152
|
|
|
*/ |
|
153
|
|
|
protected function executeQuery() |
|
154
|
|
|
{ |
|
155
|
|
|
$pdo = $this->sqlConnect->getPDO(); |
|
156
|
|
|
$this->sqlConnect->upNbQuery(); |
|
157
|
|
|
$this->requestIsAssembled(); |
|
158
|
|
|
|
|
159
|
|
|
if ($this->isPreparedRequest) { |
|
160
|
|
|
|
|
161
|
|
|
$req = $pdo->prepare( |
|
162
|
|
|
$this->assembledRequest, |
|
163
|
|
|
$this->prepareDriversOptions |
|
164
|
|
|
); |
|
165
|
|
|
|
|
166
|
|
|
$req->execute($this->preparedRequestArgs); |
|
167
|
|
|
$error = $req->errorInfo(); |
|
168
|
|
|
} else { |
|
169
|
|
|
$pdoMethodToCall = 'exec'; |
|
170
|
|
|
if (get_class($this) === '\BfwSql\SqlSelect') { |
|
171
|
|
|
$pdoMethodToCall = 'query'; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
$req = $pdo->{$pdoMethodToCall}($this->assembledRequest); |
|
175
|
|
|
$error = $pdo->errorInfo(); |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
|
|
$this->lastRequestStatement = $req; |
|
179
|
|
|
|
|
180
|
|
|
return $error; |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* Execute the assembled request and check if there are errors |
|
185
|
|
|
* Update property noResult |
|
186
|
|
|
* |
|
187
|
|
|
* @throws \Exception If the request fail |
|
188
|
|
|
* |
|
189
|
|
|
* @return \PDOStatement|integer |
|
190
|
|
|
*/ |
|
191
|
|
|
public function execute() |
|
192
|
|
|
{ |
|
193
|
|
|
$error = $this->executeQuery(); |
|
194
|
|
|
|
|
195
|
|
|
//Throw an exception if they are an error with the request |
|
196
|
|
|
if ($error[0] != null && $error[0] != '00000') { |
|
197
|
|
|
throw new Exception($error[2]); |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
if ($this->lastRequestStatement === false) { |
|
201
|
|
|
throw new Exception( |
|
202
|
|
|
'An error occurred during the execution of the request' |
|
203
|
|
|
); |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
$this->noResult = false; |
|
207
|
|
|
if ($this->obtainImpactedRows() === 0) { |
|
208
|
|
|
$this->noResult = true; |
|
209
|
|
|
} |
|
210
|
|
|
|
|
211
|
|
|
return $this->lastRequestStatement; |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
|
|
/** |
|
215
|
|
|
* Closes the cursor, enabling the statement to be executed again. |
|
216
|
|
|
* |
|
217
|
|
|
* @link http://php.net/manual/fr/pdostatement.closecursor.php |
|
218
|
|
|
* |
|
219
|
|
|
* @return void |
|
220
|
|
|
*/ |
|
221
|
|
|
public function closeCursor() |
|
222
|
|
|
{ |
|
223
|
|
|
return $this->lastRequestStatement->closeCursor(); |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
/** |
|
227
|
|
|
* Return the number of impacted rows by the last request |
|
228
|
|
|
* |
|
229
|
|
|
* @return int|bool |
|
230
|
|
|
*/ |
|
231
|
|
|
public function obtainImpactedRows() |
|
232
|
|
|
{ |
|
233
|
|
|
if ($this->lastRequestStatement === false) { |
|
234
|
|
|
return false; |
|
235
|
|
|
} |
|
236
|
|
|
|
|
237
|
|
|
if (is_object($this->lastRequestStatement)) { |
|
238
|
|
|
//If pdo::query or pdo::prepare |
|
|
|
|
|
|
239
|
|
|
return $this->lastRequestStatement->rowCount(); |
|
240
|
|
|
} elseif (is_integer($this->lastRequestStatement)) { |
|
241
|
|
|
//If pdo::exec |
|
242
|
|
|
return $this->lastRequestStatement; |
|
243
|
|
|
} |
|
244
|
|
|
|
|
245
|
|
|
//Security if call without executed a request |
|
246
|
|
|
return false; |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
/** |
|
250
|
|
|
* To call this own request without use query writer |
|
251
|
|
|
* |
|
252
|
|
|
* @param string $request The user request |
|
253
|
|
|
* |
|
254
|
|
|
* @return void |
|
255
|
|
|
*/ |
|
256
|
|
|
public function query($request) |
|
257
|
|
|
{ |
|
258
|
|
|
$this->assembledRequest = $request; |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
/** |
|
262
|
|
|
* Add a filter to where part of the request |
|
263
|
|
|
* |
|
264
|
|
|
* @param string $filter The filter to add |
|
265
|
|
|
* @param array|null $preparedFilters (default: null) Filters to add |
|
266
|
|
|
* in prepared request |
|
267
|
|
|
* |
|
268
|
|
|
* @throws \Exception If key on prepared request is already used |
|
269
|
|
|
* |
|
270
|
|
|
* @return \BfwSql\SqlActions |
|
271
|
|
|
*/ |
|
272
|
|
|
public function where($filter, $preparedFilters=null) |
|
273
|
|
|
{ |
|
274
|
|
|
$this->where[] = $filter; |
|
275
|
|
|
|
|
276
|
|
|
if(is_array($preparedFilters)) |
|
277
|
|
|
{ |
|
278
|
|
|
$this->addPreparedFilters($preparedFilters); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
return $this; |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
/** |
|
285
|
|
|
* Add filters to prepared requests |
|
286
|
|
|
* |
|
287
|
|
|
* @param array $preparedFilters Filters to add in prepared request |
|
288
|
|
|
* |
|
289
|
|
|
* @return void |
|
290
|
|
|
*/ |
|
291
|
|
|
protected function addPreparedFilters($preparedFilters) |
|
292
|
|
|
{ |
|
293
|
|
|
foreach($preparedFilters as $prepareKey => $prepareValue) |
|
294
|
|
|
{ |
|
295
|
|
|
$this->preparedRequestArgs[$prepareKey] = $prepareValue; |
|
296
|
|
|
} |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
/** |
|
300
|
|
|
* Write the where part of a sql query and return it |
|
301
|
|
|
* |
|
302
|
|
|
* @return string |
|
303
|
|
|
*/ |
|
304
|
|
|
protected function generateWhere() |
|
305
|
|
|
{ |
|
306
|
|
|
$where = ''; |
|
307
|
|
|
|
|
308
|
|
|
//check if there are filters to write |
|
309
|
|
|
if (count($this->where) > 0) { |
|
310
|
|
|
$where = ' WHERE '; |
|
311
|
|
|
|
|
312
|
|
|
foreach ($this->where as $filter) { |
|
313
|
|
|
|
|
314
|
|
|
if ($where != ' WHERE ') { |
|
315
|
|
|
$where .= ' AND '; |
|
316
|
|
|
} |
|
317
|
|
|
|
|
318
|
|
|
$where .= $filter; |
|
319
|
|
|
} |
|
320
|
|
|
} |
|
321
|
|
|
|
|
322
|
|
|
return $where; |
|
323
|
|
|
} |
|
324
|
|
|
|
|
325
|
|
|
/** |
|
326
|
|
|
* Add datas to insert or update for a column. |
|
327
|
|
|
* Used by UPDATE and INSERT requests |
|
328
|
|
|
* |
|
329
|
|
|
* @param array $columns Datas to add or update |
|
330
|
|
|
* Format : array('sqlColumnName' => 'valueForThisColumn', ...); |
|
331
|
|
|
* |
|
332
|
|
|
* @return \BfwSql\SqlActions |
|
333
|
|
|
*/ |
|
334
|
|
|
public function addDatasForColumns($columns) |
|
335
|
|
|
{ |
|
336
|
|
|
foreach ($columns as $columnName => $data) { |
|
337
|
|
|
if ( |
|
338
|
|
|
isset($this->columns[$columnName]) |
|
339
|
|
|
&& $this->columns[$columnName] != $data |
|
340
|
|
|
) { |
|
341
|
|
|
throw new \Exception( |
|
342
|
|
|
'A different data is already declared for the column ' |
|
343
|
|
|
.$columnName |
|
344
|
|
|
); |
|
345
|
|
|
} |
|
346
|
|
|
|
|
347
|
|
|
$this->columns[$columnName] = $data; |
|
348
|
|
|
} |
|
349
|
|
|
|
|
350
|
|
|
return $this; |
|
351
|
|
|
} |
|
352
|
|
|
|
|
353
|
|
|
/** |
|
354
|
|
|
* Send a notify to application observers |
|
355
|
|
|
* |
|
356
|
|
|
* @return void |
|
357
|
|
|
*/ |
|
358
|
|
|
protected function callObserver() |
|
359
|
|
|
{ |
|
360
|
|
|
$app = \BFW\Application::getInstance(); |
|
361
|
|
|
$app->setContext($this); |
|
362
|
|
|
$app->notifyAction('BfwSqlRequest'); |
|
363
|
|
|
} |
|
364
|
|
|
} |
|
365
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.