1
|
|
|
<?php |
2
|
|
|
namespace Divergence\Controllers; |
3
|
|
|
|
4
|
|
|
use Exception; |
5
|
|
|
|
6
|
|
|
use Divergence\Helpers\JSON; |
7
|
|
|
use Divergence\Helpers\JSONP; |
8
|
|
|
use Divergence\Helpers\Util as Util; |
9
|
|
|
use Divergence\IO\Database\MySQL as DB; |
10
|
|
|
use Divergence\Models\ActiveRecord as ActiveRecord; |
11
|
|
|
|
12
|
|
|
abstract class RecordsRequestHandler extends RequestHandler |
13
|
|
|
{ |
14
|
|
|
public static $config; |
15
|
|
|
|
16
|
|
|
// configurables |
17
|
|
|
public static $recordClass; |
18
|
|
|
public static $accountLevelRead = false; |
19
|
|
|
public static $accountLevelBrowse = 'Staff'; |
20
|
|
|
public static $accountLevelWrite = 'Staff'; |
21
|
|
|
public static $accountLevelAPI = false; |
22
|
|
|
public static $browseOrder = false; |
23
|
|
|
public static $browseConditions = false; |
24
|
|
|
public static $browseLimitDefault = false; |
25
|
|
|
public static $editableFields = false; |
26
|
|
|
public static $searchConditions = false; |
27
|
|
|
|
28
|
|
|
public static $calledClass = __CLASS__; |
29
|
|
|
public static $responseMode = 'dwoo'; |
30
|
|
|
|
31
|
|
|
public static function handleRequest() |
32
|
|
|
{ |
33
|
|
|
// save static class |
34
|
|
|
static::$calledClass = get_called_class(); |
35
|
|
|
|
36
|
|
|
// handle JSON requests |
37
|
|
|
if (static::peekPath() == 'json') { |
38
|
|
|
// check access for API response modes |
39
|
|
|
static::$responseMode = static::shiftPath(); |
40
|
|
|
if (in_array(static::$responseMode, ['json','jsonp'])) { |
41
|
|
|
if (!static::checkAPIAccess()) { |
42
|
|
|
return static::throwAPIUnAuthorizedError(); |
43
|
|
|
} |
44
|
|
|
} |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
return static::handleRecordsRequest(); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
|
51
|
|
|
public static function handleRecordsRequest($action = false) |
52
|
|
|
{ |
53
|
|
|
switch ($action ? $action : $action = static::shiftPath()) { |
54
|
|
|
case 'save': |
55
|
|
|
{ |
56
|
|
|
return static::handleMultiSaveRequest(); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
case 'destroy': |
60
|
|
|
{ |
61
|
|
|
return static::handleMultiDestroyRequest(); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
case 'create': |
65
|
|
|
{ |
66
|
|
|
return static::handleCreateRequest(); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
case '': |
70
|
|
|
case false: |
71
|
|
|
{ |
72
|
|
|
return static::handleBrowseRequest(); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
default: |
76
|
|
|
{ |
77
|
|
|
if ($Record = static::getRecordByHandle($action)) { |
78
|
|
|
return static::handleRecordRequest($Record); |
79
|
|
|
} else { |
80
|
|
|
return static::throwRecordNotFoundError(); |
81
|
|
|
} |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
public static function getRecordByHandle($handle) |
87
|
|
|
{ |
88
|
|
|
$className = static::$recordClass; |
89
|
|
|
|
90
|
|
|
if (method_exists($className, 'getByHandle')) { |
91
|
|
|
return $className::getByHandle($handle); |
92
|
|
|
} |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
public static function prepareBrowseConditions($conditions = []) |
96
|
|
|
{ |
97
|
|
|
if (static::$browseConditions) { |
98
|
|
|
if (!is_array(static::$browseConditions)) { |
99
|
|
|
static::$browseConditions = [static::$browseConditions]; |
100
|
|
|
} |
101
|
|
|
$conditions = array_merge(static::$browseConditions, $conditions); |
102
|
|
|
} |
103
|
|
|
return $conditions; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public static function prepareDefaultBrowseOptions() |
107
|
|
|
{ |
108
|
|
|
if (empty($_REQUEST['offset']) && is_numeric($_REQUEST['start'])) { |
109
|
|
|
$_REQUEST['offset'] = $_REQUEST['start']; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
$limit = !empty($_REQUEST['limit']) && is_numeric($_REQUEST['limit']) ? $_REQUEST['limit'] : static::$browseLimitDefault; |
113
|
|
|
$offset = !empty($_REQUEST['offset']) && is_numeric($_REQUEST['offset']) ? $_REQUEST['offset'] : false; |
114
|
|
|
|
115
|
|
|
$options = [ |
116
|
|
|
'limit' => $limit, |
117
|
|
|
'offset' => $offset, |
118
|
|
|
'order' => static::$browseOrder, |
119
|
|
|
]; |
120
|
|
|
|
121
|
|
|
return $options; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
public static function handleBrowseRequest($options = [], $conditions = [], $responseID = null, $responseData = []) |
125
|
|
|
{ |
126
|
|
|
if (!static::checkBrowseAccess(func_get_args())) { |
127
|
|
|
return static::throwUnauthorizedError(); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
$conditions = static::prepareBrowseConditions($conditions); |
131
|
|
|
|
132
|
|
|
$options = static::prepareDefaultBrowseOptions(); |
133
|
|
|
|
134
|
|
|
// process sorter |
135
|
|
|
if (!empty($_REQUEST['sort'])) { |
136
|
|
|
$sort = json_decode($_REQUEST['sort'], true); |
137
|
|
|
if (!$sort || !is_array($sort)) { |
138
|
|
|
return static::respond('error', [ |
139
|
|
|
'success' => false, |
140
|
|
|
'failed' => [ |
141
|
|
|
'errors' => 'Invalid sorter.', |
142
|
|
|
], |
143
|
|
|
]); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
if (is_array($sort)) { |
147
|
|
|
foreach ($sort as $field) { |
148
|
|
|
$options['order'][$field['property']] = $field['direction']; |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// process filter |
154
|
|
|
if (!empty($_REQUEST['filter'])) { |
155
|
|
|
$filter = json_decode($_REQUEST['filter'], true); |
156
|
|
|
if (!$filter || !is_array($filter)) { |
157
|
|
|
return static::respond('error', [ |
158
|
|
|
'success' => false, |
159
|
|
|
'failed' => [ |
160
|
|
|
'errors' => 'Invalid filter.', |
161
|
|
|
], |
162
|
|
|
]); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
foreach ($filter as $field) { |
166
|
|
|
$conditions[$field['property']] = $field['value']; |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
$className = static::$recordClass; |
171
|
|
|
|
172
|
|
|
return static::respond( |
173
|
|
|
isset($responseID) ? $responseID : static::getTemplateName($className::$pluralNoun), |
174
|
|
|
array_merge($responseData, [ |
175
|
|
|
'success' => true, |
176
|
|
|
'data' => $className::getAllByWhere($conditions, $options), |
177
|
|
|
'conditions' => $conditions, |
178
|
|
|
'total' => DB::foundRows(), |
179
|
|
|
'limit' => $options['limit'], |
180
|
|
|
'offset' => $options['offset'], |
181
|
|
|
]) |
182
|
|
|
); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
|
186
|
|
|
public static function handleRecordRequest(ActiveRecord $Record, $action = false) |
187
|
|
|
{ |
188
|
|
|
if (!static::checkReadAccess($Record)) { |
189
|
|
|
return static::throwUnauthorizedError(); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
switch ($action ? $action : $action = static::shiftPath()) { |
193
|
|
|
case '': |
194
|
|
|
case false: |
195
|
|
|
{ |
196
|
|
|
$className = static::$recordClass; |
197
|
|
|
|
198
|
|
|
return static::respond(static::getTemplateName($className::$singularNoun), [ |
199
|
|
|
'success' => true, |
200
|
|
|
'data' => $Record, |
201
|
|
|
]); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
case 'edit': |
205
|
|
|
{ |
206
|
|
|
return static::handleEditRequest($Record); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
case 'delete': |
210
|
|
|
{ |
211
|
|
|
return static::handleDeleteRequest($Record); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
default: |
215
|
|
|
{ |
216
|
|
|
return static::onRecordRequestNotHandled($Record, $action); |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
|
222
|
|
|
public static function prepareResponseModeJSON($methods = []) |
223
|
|
|
{ |
224
|
|
|
if (static::$responseMode == 'json' && in_array($_SERVER['REQUEST_METHOD'], $methods)) { |
225
|
|
|
$JSONData = JSON::getRequestData(); |
226
|
|
|
if (is_array($JSONData)) { |
227
|
|
|
$_REQUEST = $JSONData; |
228
|
|
|
} |
229
|
|
|
} |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
public static function processDatumSave($datum) |
233
|
|
|
{ |
234
|
|
|
$className = static::$recordClass; |
235
|
|
|
$PrimaryKey = $className::getPrimaryKey(); |
236
|
|
|
|
237
|
|
|
// get record |
238
|
|
|
if (empty($datum[$PrimaryKey])) { |
239
|
|
|
$Record = new $className::$defaultClass(); |
240
|
|
|
static::onRecordCreated($Record, $datum); |
241
|
|
|
} else { |
242
|
|
|
if (!$Record = $className::getByID($datum[$PrimaryKey])) { |
243
|
|
|
throw new Exception('Record not found'); |
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
// check write access |
248
|
|
|
if (!static::checkWriteAccess($Record)) { |
249
|
|
|
throw new Exception('Write access denied'); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
// apply delta |
253
|
|
|
static::applyRecordDelta($Record, $datum); |
254
|
|
|
|
255
|
|
|
// call template function |
256
|
|
|
static::onBeforeRecordValidated($Record, $datum); |
257
|
|
|
|
258
|
|
|
// try to save record |
259
|
|
|
try { |
260
|
|
|
// call template function |
261
|
|
|
static::onBeforeRecordSaved($Record, $datum); |
262
|
|
|
|
263
|
|
|
$Record->save(); |
264
|
|
|
return (!$Record::fieldExists('Class') || get_class($Record) == $Record->Class) ? $Record : $Record->changeClass(); |
265
|
|
|
|
266
|
|
|
// call template function |
267
|
|
|
static::onRecordSaved($Record, $datum); |
|
|
|
|
268
|
|
|
} catch (Exception $e) { |
269
|
|
|
$failed[] = [ |
|
|
|
|
270
|
|
|
'record' => $Record->data, |
271
|
|
|
'validationErrors' => $Record->validationErrors, |
272
|
|
|
]; |
273
|
|
|
} |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
public static function handleMultiSaveRequest() |
277
|
|
|
{ |
278
|
|
|
$className = static::$recordClass; |
279
|
|
|
|
280
|
|
|
$PrimaryKey = $className::getPrimaryKey(); |
|
|
|
|
281
|
|
|
|
282
|
|
|
static::prepareResponseModeJSON(['POST','PUT']); |
283
|
|
|
|
284
|
|
|
if ($className::fieldExists(key($_REQUEST['data']))) { |
285
|
|
|
$_REQUEST['data'] = [$_REQUEST['data']]; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
if (empty($_REQUEST['data']) || !is_array($_REQUEST['data'])) { |
289
|
|
|
return static::respond('error', [ |
290
|
|
|
'success' => false, |
291
|
|
|
'failed' => [ |
292
|
|
|
'errors' => 'Save expects "data" field as array of records.', |
293
|
|
|
], |
294
|
|
|
]); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
$results = []; |
298
|
|
|
$failed = []; |
299
|
|
|
|
300
|
|
|
foreach ($_REQUEST['data'] as $datum) { |
301
|
|
|
try { |
302
|
|
|
$results[] = static::processDatumSave($datum); |
303
|
|
|
} catch (Exception $e) { |
304
|
|
|
$failed[] = [ |
305
|
|
|
'record' => $datum, |
306
|
|
|
'errors' => $e->getMessage(), |
307
|
|
|
]; |
308
|
|
|
continue; |
309
|
|
|
} |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
|
313
|
|
|
return static::respond(static::getTemplateName($className::$pluralNoun).'Saved', [ |
314
|
|
|
'success' => count($results) || !count($failed), |
315
|
|
|
'data' => $results, |
316
|
|
|
'failed' => $failed, |
317
|
|
|
]); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
|
321
|
|
|
public static function handleMultiDestroyRequest() |
322
|
|
|
{ |
323
|
|
|
$className = static::$recordClass; |
324
|
|
|
|
325
|
|
|
$PrimaryKey = $className::getPrimaryKey(); |
326
|
|
|
|
327
|
|
|
static::prepareResponseModeJSON(['POST','PUT','DELETE']); |
328
|
|
|
|
329
|
|
|
if ($className::fieldExists(key($_REQUEST['data']))) { |
330
|
|
|
$_REQUEST['data'] = [$_REQUEST['data']]; |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
if (empty($_REQUEST['data']) || !is_array($_REQUEST['data'])) { |
334
|
|
|
return static::respond('error', [ |
335
|
|
|
'success' => false, |
336
|
|
|
'failed' => [ |
337
|
|
|
'errors' => 'Save expects "data" field as array of records.', |
338
|
|
|
], |
339
|
|
|
]); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
|
343
|
|
|
$results = []; |
344
|
|
|
$failed = []; |
345
|
|
|
|
346
|
|
|
foreach ($_REQUEST['data'] as $datum) { |
347
|
|
|
// get record |
348
|
|
|
if (is_numeric($datum)) { |
349
|
|
|
$recordID = $datum; |
350
|
|
|
} elseif (!empty($datum[$PrimaryKey]) && is_numeric($datum[$PrimaryKey])) { |
351
|
|
|
$recordID = $datum[$PrimaryKey]; |
352
|
|
|
} else { |
353
|
|
|
$failed[] = [ |
354
|
|
|
'record' => $datum, |
355
|
|
|
'errors' => $PrimaryKey.' missing', |
356
|
|
|
]; |
357
|
|
|
continue; |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
if (!$Record = $className::getByField($PrimaryKey, $recordID)) { |
361
|
|
|
$failed[] = [ |
362
|
|
|
'record' => $datum, |
363
|
|
|
'errors' => $PrimaryKey.' not found', |
364
|
|
|
]; |
365
|
|
|
continue; |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
// check write access |
369
|
|
|
if (!static::checkWriteAccess($Record)) { |
370
|
|
|
$failed[] = [ |
371
|
|
|
'record' => $datum, |
372
|
|
|
'errors' => 'Write access denied', |
373
|
|
|
]; |
374
|
|
|
continue; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
// destroy record |
378
|
|
|
if ($Record->destroy()) { |
379
|
|
|
$results[] = $Record; |
380
|
|
|
} |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
return static::respond(static::getTemplateName($className::$pluralNoun).'Destroyed', [ |
384
|
|
|
'success' => count($results) || !count($failed), |
385
|
|
|
'data' => $results, |
386
|
|
|
'failed' => $failed, |
387
|
|
|
]); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
|
391
|
|
|
public static function handleCreateRequest(ActiveRecord $Record = null) |
392
|
|
|
{ |
393
|
|
|
// save static class |
394
|
|
|
static::$calledClass = get_called_class(); |
395
|
|
|
|
396
|
|
|
if (!$Record) { |
397
|
|
|
$className = static::$recordClass; |
398
|
|
|
$Record = new $className::$defaultClass(); |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
// call template function |
402
|
|
|
static::onRecordCreated($Record, $_REQUEST); |
403
|
|
|
|
404
|
|
|
return static::handleEditRequest($Record); |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
public static function handleEditRequest(ActiveRecord $Record) |
408
|
|
|
{ |
409
|
|
|
$className = static::$recordClass; |
410
|
|
|
|
411
|
|
|
if (!static::checkWriteAccess($Record)) { |
412
|
|
|
return static::throwUnauthorizedError(); |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
if (in_array($_SERVER['REQUEST_METHOD'], ['POST','PUT'])) { |
416
|
|
|
if (static::$responseMode == 'json') { |
417
|
|
|
$_REQUEST = JSON::getRequestData(); |
418
|
|
|
if (is_array($_REQUEST['data'])) { |
419
|
|
|
$_REQUEST = $_REQUEST['data']; |
420
|
|
|
} |
421
|
|
|
} |
422
|
|
|
$_REQUEST = $_REQUEST ? $_REQUEST : $_POST; |
423
|
|
|
|
424
|
|
|
// apply delta |
425
|
|
|
static::applyRecordDelta($Record, $_REQUEST); |
426
|
|
|
|
427
|
|
|
// call template function |
428
|
|
|
static::onBeforeRecordValidated($Record, $_REQUEST); |
429
|
|
|
|
430
|
|
|
// validate |
431
|
|
|
if ($Record->validate()) { |
432
|
|
|
// call template function |
433
|
|
|
static::onBeforeRecordSaved($Record, $_REQUEST); |
434
|
|
|
|
435
|
|
|
try { |
436
|
|
|
// save session |
437
|
|
|
$Record->save(); |
438
|
|
|
} catch (Exception $e) { |
439
|
|
|
return static::respond('Error', [ |
440
|
|
|
'success' => false, |
441
|
|
|
'failed' => [ |
442
|
|
|
'errors' => $e->getMessage(), |
443
|
|
|
], |
444
|
|
|
]); |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
// call template function |
448
|
|
|
static::onRecordSaved($Record, $_REQUEST); |
449
|
|
|
|
450
|
|
|
// fire created response |
451
|
|
|
$responseID = static::getTemplateName($className::$singularNoun).'Saved'; |
452
|
|
|
$responseData = [ |
453
|
|
|
'success' => true, |
454
|
|
|
'data' => $Record, |
455
|
|
|
]; |
456
|
|
|
return static::respond($responseID, $responseData); |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
// fall through back to form if validation failed |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
$responseID = static::getTemplateName($className::$singularNoun).'Edit'; |
463
|
|
|
$responseData = [ |
464
|
|
|
'success' => false, |
465
|
|
|
'data' => $Record, |
466
|
|
|
]; |
467
|
|
|
|
468
|
|
|
return static::respond($responseID, $responseData); |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
|
472
|
|
|
public static function handleDeleteRequest(ActiveRecord $Record) |
473
|
|
|
{ |
474
|
|
|
$className = static::$recordClass; |
475
|
|
|
|
476
|
|
|
if (!static::checkWriteAccess($Record)) { |
477
|
|
|
return static::throwUnauthorizedError(); |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') { |
481
|
|
|
$data = $Record->data; |
482
|
|
|
$Record->destroy(); |
483
|
|
|
|
484
|
|
|
// call cleanup function after delete |
485
|
|
|
static::onRecordDeleted($Record, $data); |
486
|
|
|
|
487
|
|
|
// fire created response |
488
|
|
|
return static::respond(static::getTemplateName($className::$singularNoun).'Deleted', [ |
489
|
|
|
'success' => true, |
490
|
|
|
'data' => $Record, |
491
|
|
|
]); |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
return static::respond('confirm', [ |
495
|
|
|
'question' => 'Are you sure you want to delete this '.$className::$singularNoun.'?', |
496
|
|
|
'data' => $Record, |
497
|
|
|
]); |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
|
501
|
|
|
public static function respond($responseID, $responseData = [], $responseMode = false) |
502
|
|
|
{ |
503
|
|
|
// default to static property |
504
|
|
|
if (!$responseMode) { |
505
|
|
|
$responseMode = static::$responseMode; |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
return parent::respond($responseID, $responseData, $responseMode); |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
// access control template functions |
512
|
|
|
public static function checkBrowseAccess($arguments) |
513
|
|
|
{ |
514
|
|
|
return true; |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
public static function checkReadAccess(ActiveRecord $Record) |
518
|
|
|
{ |
519
|
|
|
return true; |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
public static function checkWriteAccess(ActiveRecord $Record) |
523
|
|
|
{ |
524
|
|
|
return true; |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
public static function checkAPIAccess() |
528
|
|
|
{ |
529
|
|
|
return true; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
public static function throwUnauthorizedError() |
533
|
|
|
{ |
534
|
|
|
return static::respond('Unauthorized', [ |
535
|
|
|
'success' => false, |
536
|
|
|
'failed' => [ |
537
|
|
|
'errors' => 'Login required.', |
538
|
|
|
], |
539
|
|
|
]); |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
public static function throwAPIUnAuthorizedError() |
543
|
|
|
{ |
544
|
|
|
return static::respond('Unauthorized', [ |
545
|
|
|
'success' => false, |
546
|
|
|
'failed' => [ |
547
|
|
|
'errors' => 'API access required.', |
548
|
|
|
], |
549
|
|
|
]); |
550
|
|
|
} |
551
|
|
|
|
552
|
|
|
public static function throwNotFoundError() |
553
|
|
|
{ |
554
|
|
|
return static::respond('error', [ |
555
|
|
|
'success' => false, |
556
|
|
|
'failed' => [ |
557
|
|
|
'errors' => 'Record not found.', |
558
|
|
|
], |
559
|
|
|
]); |
560
|
|
|
} |
561
|
|
|
|
562
|
|
|
public static function onRecordRequestNotHandled(ActiveRecord $Record, $action) |
563
|
|
|
{ |
564
|
|
|
return static::respond('error', [ |
565
|
|
|
'success' => false, |
566
|
|
|
'failed' => [ |
567
|
|
|
'errors' => 'Malformed request.', |
568
|
|
|
], |
569
|
|
|
]); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
|
573
|
|
|
|
574
|
|
|
public static function getTemplateName($noun) |
575
|
|
|
{ |
576
|
|
|
return preg_replace_callback('/\s+([a-zA-Z])/', function ($matches) { |
577
|
|
|
return strtoupper($matches[1]); |
578
|
|
|
}, $noun); |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
public static function applyRecordDelta(ActiveRecord $Record, $data) |
582
|
|
|
{ |
583
|
|
|
if (is_array(static::$editableFields)) { |
584
|
|
|
$Record->setFields(array_intersect_key($data, array_flip(static::$editableFields))); |
585
|
|
|
} else { |
586
|
|
|
$Record->setFields($data); |
587
|
|
|
} |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
// event template functions |
591
|
|
|
protected static function onRecordCreated(ActiveRecord $Record, $data) |
592
|
|
|
{ |
593
|
|
|
} |
594
|
|
|
protected static function onBeforeRecordValidated(ActiveRecord $Record, $data) |
595
|
|
|
{ |
596
|
|
|
} |
597
|
|
|
protected static function onBeforeRecordSaved(ActiveRecord $Record, $data) |
598
|
|
|
{ |
599
|
|
|
} |
600
|
|
|
protected static function onRecordDeleted(ActiveRecord $Record, $data) |
601
|
|
|
{ |
602
|
|
|
} |
603
|
|
|
protected static function onRecordSaved(ActiveRecord $Record, $data) |
604
|
|
|
{ |
605
|
|
|
} |
606
|
|
|
|
607
|
|
|
protected static function throwRecordNotFoundError() |
608
|
|
|
{ |
609
|
|
|
return static::throwNotFoundError(); |
610
|
|
|
} |
611
|
|
|
} |
612
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.