1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Yajra\DataTables; |
4
|
|
|
|
5
|
|
|
use Illuminate\Http\Request; |
6
|
|
|
use Illuminate\Http\JsonResponse; |
7
|
|
|
use Illuminate\Database\Eloquent\Model; |
8
|
|
|
use Illuminate\Database\QueryException; |
9
|
|
|
use Illuminate\Contracts\Validation\Validator; |
10
|
|
|
use Illuminate\Foundation\Validation\ValidatesRequests; |
11
|
|
|
|
12
|
|
|
abstract class DataTablesEditor |
13
|
|
|
{ |
14
|
|
|
use ValidatesRequests; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Allowed dataTables editor actions. |
18
|
|
|
* |
19
|
|
|
* @var array |
20
|
|
|
*/ |
21
|
|
|
protected $actions = ['create', 'edit', 'remove']; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var \Illuminate\Database\Eloquent\Model |
25
|
|
|
*/ |
26
|
|
|
protected $model = null; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Process dataTables editor action request. |
30
|
|
|
* |
31
|
|
|
* @param Request $request |
32
|
|
|
* @return JsonResponse|mixed |
33
|
|
|
* @throws DataTablesEditorException |
34
|
|
|
*/ |
35
|
|
|
public function process(Request $request) |
36
|
|
|
{ |
37
|
|
|
$action = $request->get('action'); |
38
|
|
|
|
39
|
|
|
if (! in_array($action, $this->actions)) { |
40
|
|
|
throw new DataTablesEditorException('Requested action not supported!'); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
return $this->{$action}($request); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Process create action request. |
48
|
|
|
* |
49
|
|
|
* @param Request $request |
50
|
|
|
* @return JsonResponse |
51
|
|
|
*/ |
52
|
|
|
public function create(Request $request) |
53
|
|
|
{ |
54
|
|
|
$instance = $this->resolveModel(); |
55
|
|
|
$connection = $instance->getConnection(); |
56
|
|
|
$affected = []; |
57
|
|
|
$errors = []; |
58
|
|
|
|
59
|
|
|
$connection->beginTransaction(); |
60
|
|
|
foreach ($request->get('data') as $data) { |
61
|
|
|
$validator = $this->getValidationFactory()->make($data, $this->createRules(), $this->createMessages(), $this->attributes()); |
62
|
|
|
if ($validator->fails()) { |
63
|
|
|
foreach ($this->formatErrors($validator) as $error) { |
64
|
|
|
$errors[] = $error; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
continue; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
if (method_exists($this, 'creating')) { |
71
|
|
|
$data = $this->creating($instance, $data); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
if (method_exists($this, 'saving')) { |
75
|
|
|
$data = $this->saving($instance, $data); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
$model = $instance->newQuery()->create($data); |
79
|
|
|
$model->setAttribute('DT_RowId', $model->getKey()); |
80
|
|
|
|
81
|
|
|
if (method_exists($this, 'created')) { |
82
|
|
|
$this->created($model, $data); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
if (method_exists($this, 'saved')) { |
86
|
|
|
$this->saved($model, $data); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
$affected[] = $model; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
if (! $errors) { |
|
|
|
|
93
|
|
|
$connection->commit(); |
94
|
|
|
} else { |
95
|
|
|
$connection->rollBack(); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
return $this->toJson($affected, $errors); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Resolve model to used. |
103
|
|
|
* |
104
|
|
|
* @return Model |
105
|
|
|
*/ |
106
|
|
|
protected function resolveModel() |
107
|
|
|
{ |
108
|
|
|
if ($this->model instanceof Model) { |
|
|
|
|
109
|
|
|
return $this->model; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
return new $this->model; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Get create action validation rules. |
117
|
|
|
* |
118
|
|
|
* @return array |
119
|
|
|
*/ |
120
|
|
|
abstract public function createRules(); |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Get create validation messages. |
124
|
|
|
* |
125
|
|
|
* @return array |
126
|
|
|
*/ |
127
|
|
|
protected function createMessages() |
128
|
|
|
{ |
129
|
|
|
return []; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @param Validator $validator |
134
|
|
|
* @return array |
135
|
|
|
*/ |
136
|
|
|
protected function formatErrors(Validator $validator) |
137
|
|
|
{ |
138
|
|
|
$errors = []; |
139
|
|
|
|
140
|
|
|
collect($validator->errors())->each(function ($error, $key) use (&$errors) { |
141
|
|
|
$errors[] = [ |
142
|
|
|
'name' => $key, |
143
|
|
|
'status' => $error[0], |
144
|
|
|
]; |
145
|
|
|
}); |
146
|
|
|
|
147
|
|
|
return $errors; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Display success data in dataTables editor format. |
152
|
|
|
* |
153
|
|
|
* @param array $data |
154
|
|
|
* @param array $errors |
155
|
|
|
* @return JsonResponse |
156
|
|
|
*/ |
157
|
|
|
protected function toJson(array $data, array $errors = []) |
158
|
|
|
{ |
159
|
|
|
$response = ['data' => $data]; |
160
|
|
|
if ($errors) { |
|
|
|
|
161
|
|
|
$response['fieldErrors'] = $errors; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return new JsonResponse($response, 200); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Process edit action request. |
169
|
|
|
* |
170
|
|
|
* @param Request $request |
171
|
|
|
* @return JsonResponse |
172
|
|
|
*/ |
173
|
|
|
public function edit(Request $request) |
174
|
|
|
{ |
175
|
|
|
$instance = $this->resolveModel(); |
176
|
|
|
$connection = $instance->getConnection(); |
177
|
|
|
$affected = []; |
178
|
|
|
$errors = []; |
179
|
|
|
|
180
|
|
|
$connection->beginTransaction(); |
181
|
|
|
foreach ($request->get('data') as $key => $data) { |
182
|
|
|
$model = $instance->newQuery()->find($key); |
183
|
|
|
$validator = $this->getValidationFactory()->make($data, $this->editRules($model), $this->editMessages(), $this->attributes()); |
184
|
|
|
if ($validator->fails()) { |
185
|
|
|
foreach ($this->formatErrors($validator) as $error) { |
186
|
|
|
$errors[] = $error; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
continue; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
if (method_exists($this, 'updating')) { |
193
|
|
|
$data = $this->updating($model, $data); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
if (method_exists($this, 'saving')) { |
197
|
|
|
$data = $this->saving($model, $data); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
$model->update($data); |
201
|
|
|
|
202
|
|
|
if (method_exists($this, 'updated')) { |
203
|
|
|
$this->updated($model, $data); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
if (method_exists($this, 'saved')) { |
207
|
|
|
$this->saved($model, $data); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
$model->setAttribute('DT_RowId', $model->getKey()); |
211
|
|
|
$affected[] = $model; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
if (! $errors) { |
|
|
|
|
215
|
|
|
$connection->commit(); |
216
|
|
|
} else { |
217
|
|
|
$connection->rollBack(); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
return $this->toJson($affected, $errors); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Get edit action validation rules. |
225
|
|
|
* |
226
|
|
|
* @param Model $model |
227
|
|
|
* @return array |
228
|
|
|
*/ |
229
|
|
|
abstract public function editRules(Model $model); |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Get edit validation messages. |
233
|
|
|
* |
234
|
|
|
* @return array |
235
|
|
|
*/ |
236
|
|
|
protected function editMessages() |
237
|
|
|
{ |
238
|
|
|
return []; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Process remove action request. |
243
|
|
|
* |
244
|
|
|
* @param Request $request |
245
|
|
|
* @return JsonResponse |
246
|
|
|
*/ |
247
|
|
|
public function remove(Request $request) |
248
|
|
|
{ |
249
|
|
|
$instance = $this->resolveModel(); |
250
|
|
|
$connection = $instance->getConnection(); |
251
|
|
|
$affected = []; |
252
|
|
|
$errors = []; |
253
|
|
|
|
254
|
|
|
$connection->beginTransaction(); |
255
|
|
|
foreach ($request->get('data') as $key => $data) { |
256
|
|
|
$model = $instance->newQuery()->find($key); |
257
|
|
|
$validator = $this->getValidationFactory() |
258
|
|
|
->make($data, $this->removeRules($model), $this->removeMessages(), $this->attributes()); |
259
|
|
|
if ($validator->fails()) { |
260
|
|
|
foreach ($this->formatErrors($validator) as $error) { |
261
|
|
|
$errors[] = $error['status']; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
continue; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
try { |
268
|
|
|
if (method_exists($this, 'deleting')) { |
269
|
|
|
$this->deleting($model, $data); |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
$model->delete(); |
273
|
|
|
|
274
|
|
|
if (method_exists($this, 'deleted')) { |
275
|
|
|
$this->deleted($model, $data); |
276
|
|
|
} |
277
|
|
|
} catch (QueryException $exception) { |
|
|
|
|
278
|
|
|
$error = config('app.debug') ? $exception->errorInfo[2] : $this->removeExceptionMessage($exception, $model); |
279
|
|
|
$errors[] = $error; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
$affected[] = $model; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
if (! $errors) { |
|
|
|
|
286
|
|
|
$connection->commit(); |
287
|
|
|
} else { |
288
|
|
|
$connection->rollBack(); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
$response = ['data' => $affected]; |
292
|
|
|
if ($errors) { |
|
|
|
|
293
|
|
|
$response['error'] = implode("\n", $errors); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
return new JsonResponse($response, 200); |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* Get remove action validation rules. |
301
|
|
|
* |
302
|
|
|
* @param Model $model |
303
|
|
|
* @return array |
304
|
|
|
*/ |
305
|
|
|
abstract public function removeRules(Model $model); |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* Get remove validation messages. |
309
|
|
|
* |
310
|
|
|
* @return array |
311
|
|
|
*/ |
312
|
|
|
protected function removeMessages() |
313
|
|
|
{ |
314
|
|
|
return []; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Get remove query exception message. |
319
|
|
|
* |
320
|
|
|
* @param QueryException $exception |
321
|
|
|
* @param Model $model |
322
|
|
|
* @return string |
323
|
|
|
*/ |
324
|
|
|
protected function removeExceptionMessage(QueryException $exception, Model $model) |
325
|
|
|
{ |
326
|
|
|
return "Record {$model->getKey()} is protected and cannot be deleted!"; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* Get dataTables model. |
331
|
|
|
* |
332
|
|
|
* @return Model |
333
|
|
|
*/ |
334
|
|
|
public function getModel() |
335
|
|
|
{ |
336
|
|
|
return $this->model; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Set the dataTables model on runtime. |
341
|
|
|
* |
342
|
|
|
* @param Model|string $model |
343
|
|
|
* @return DataTablesEditor |
344
|
|
|
*/ |
345
|
|
|
public function setModel($model) |
346
|
|
|
{ |
347
|
|
|
$this->model = $model; |
|
|
|
|
348
|
|
|
|
349
|
|
|
return $this; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Display dataTables editor validation errors. |
354
|
|
|
* |
355
|
|
|
* @param Validator $validator |
356
|
|
|
* @return JsonResponse |
357
|
|
|
*/ |
358
|
|
|
protected function displayValidationErrors(Validator $validator) |
359
|
|
|
{ |
360
|
|
|
$errors = $this->formatErrors($validator); |
361
|
|
|
|
362
|
|
|
return new JsonResponse([ |
363
|
|
|
'data' => [], |
364
|
|
|
'fieldErrors' => $errors, |
365
|
|
|
]); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
/** |
369
|
|
|
* Get custom attributes for validator errors. |
370
|
|
|
* |
371
|
|
|
* @return array |
372
|
|
|
*/ |
373
|
|
|
public function attributes() |
374
|
|
|
{ |
375
|
|
|
return []; |
376
|
|
|
} |
377
|
|
|
} |
378
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.