Completed
Push — master ( b85859...bcf5c2 )
by Arjay
01:08
created

src/DataTablesEditor.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Support\Facades\Storage;
10
use Illuminate\Contracts\Validation\Validator;
11
use Illuminate\Validation\ValidationException;
12
use Illuminate\Foundation\Validation\ValidatesRequests;
13
14
abstract class DataTablesEditor
15
{
16
    use ValidatesRequests;
17
18
    /**
19
     * Allowed dataTables editor actions.
20
     *
21
     * @var array
22
     */
23
    protected $actions = ['create', 'edit', 'remove', 'upload', 'forceDelete'];
24
25
    /**
26
     * @var \Illuminate\Database\Eloquent\Model
27
     */
28
    protected $model = null;
29
30
    /**
31
     * Indicates if all mass assignment is enabled on model.
32
     *
33
     * @var bool
34
     */
35
    protected $unguarded = false;
36
37
    /**
38
     * Upload directory relative to storage path.
39
     *
40
     * @var string
41
     */
42
    protected $uploadDir = 'editor';
43
44
    /**
45
     * Flag to force delete a model.
46
     *
47
     * @var bool
48
     */
49
    protected $forceDeleting = false;
50
51
    /**
52
     * Filesystem disk config to use for upload.
53
     *
54
     * @var string
55
     */
56
    protected $disk = 'public';
57
58
    /**
59
     * Process dataTables editor action request.
60
     *
61
     * @param Request $request
62
     * @return JsonResponse|mixed
63
     * @throws DataTablesEditorException
64
     */
65
    public function process(Request $request)
66
    {
67
        $action = $request->get('action');
68
69
        if (! in_array($action, $this->actions)) {
70
            throw new DataTablesEditorException('Requested action not supported!');
71
        }
72
73
        return $this->{$action}($request);
74
    }
75
76
    /**
77
     * Process create action request.
78
     *
79
     * @param Request $request
80
     * @return JsonResponse
81
     */
82 View Code Duplication
    public function create(Request $request)
83
    {
84
        $model      = $this->resolveModel();
85
        $connection = $model->getConnection();
86
        $affected   = [];
87
        $errors     = [];
88
89
        $connection->beginTransaction();
90
        foreach ($request->get('data') as $data) {
91
            $instance  = $model->newInstance();
92
            $validator = $this->getValidationFactory()
93
                              ->make(
94
                                  $data,
95
                                  $this->createRules(), $this->messages() + $this->createMessages(),
0 ignored issues
show
Deprecated Code introduced by
The method Yajra\DataTables\DataTab...ditor::createMessages() has been deprecated with message: deprecated since v1.12.0, please use messages() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
96
                                  $this->attributes()
97
                              );
98
            if ($validator->fails()) {
99
                foreach ($this->formatErrors($validator) as $error) {
100
                    $errors[] = $error;
101
                }
102
103
                continue;
104
            }
105
106
            if (method_exists($this, 'creating')) {
107
                $data = $this->creating($instance, $data);
108
            }
109
110
            if (method_exists($this, 'saving')) {
111
                $data = $this->saving($instance, $data);
112
            }
113
114
            $instance->fill($data)->save();
115
116
            if (method_exists($this, 'created')) {
117
                $instance = $this->created($instance, $data);
118
            }
119
120
            if (method_exists($this, 'saved')) {
121
                $instance = $this->saved($instance, $data);
122
            }
123
124
            $instance->setAttribute('DT_RowId', $instance->getKey());
125
            $affected[] = $instance;
126
        }
127
128
        if (! $errors) {
129
            $connection->commit();
130
        } else {
131
            $connection->rollBack();
132
        }
133
134
        return $this->toJson($affected, $errors);
135
    }
136
137
    /**
138
     * Resolve model to used.
139
     *
140
     * @return Model|\Illuminate\Database\Eloquent\SoftDeletes
141
     */
142
    protected function resolveModel()
143
    {
144
        if (! $this->model instanceof Model) {
145
            $this->model = new $this->model;
146
        }
147
148
        $this->model->unguard($this->unguarded);
149
150
        return $this->model;
151
    }
152
153
    /**
154
     * Get create action validation rules.
155
     *
156
     * @return array
157
     */
158
    abstract public function createRules();
159
160
    /**
161
     * Get create validation messages.
162
     *
163
     * @deprecated deprecated since v1.12.0, please use messages() instead.
164
     * @return array
165
     */
166
    protected function createMessages()
167
    {
168
        return [];
169
    }
170
171
    /**
172
     * Get custom attributes for validator errors.
173
     *
174
     * @return array
175
     */
176
    public function attributes()
177
    {
178
        return [];
179
    }
180
181
    /**
182
     * @param Validator $validator
183
     * @return array
184
     */
185
    protected function formatErrors(Validator $validator)
186
    {
187
        $errors = [];
188
189
        collect($validator->errors())->each(function ($error, $key) use (&$errors) {
190
            $errors[] = [
191
                'name'   => $key,
192
                'status' => $error[0],
193
            ];
194
        });
195
196
        return $errors;
197
    }
198
199
    /**
200
     * Display success data in dataTables editor format.
201
     *
202
     * @param array $data
203
     * @param array $errors
204
     * @return JsonResponse
205
     */
206
    protected function toJson(array $data, array $errors = [])
207
    {
208
        $response = ['data' => $data];
209
        if ($errors) {
210
            $response['fieldErrors'] = $errors;
211
        }
212
213
        return new JsonResponse($response, 200);
214
    }
215
216
    /**
217
     * Process edit action request.
218
     *
219
     * @param Request $request
220
     * @return JsonResponse
221
     */
222 View Code Duplication
    public function edit(Request $request)
223
    {
224
        $connection = $this->getBuilder()->getConnection();
225
        $affected   = [];
226
        $errors     = [];
227
228
        $connection->beginTransaction();
229
        foreach ($request->get('data') as $key => $data) {
230
            $model     = $this->getBuilder()->findOrFail($key);
231
            $validator = $this->getValidationFactory()
232
                              ->make($data, $this->editRules($model), $this->messages() + $this->editMessages(), $this->attributes());
233
            if ($validator->fails()) {
234
                foreach ($this->formatErrors($validator) as $error) {
235
                    $errors[] = $error;
236
                }
237
238
                continue;
239
            }
240
241
            if (method_exists($this, 'updating')) {
242
                $data = $this->updating($model, $data);
243
            }
244
245
            if (method_exists($this, 'saving')) {
246
                $data = $this->saving($model, $data);
247
            }
248
249
            $model->fill($data)->save();
250
251
            if (method_exists($this, 'updated')) {
252
                $model = $this->updated($model, $data);
253
            }
254
255
            if (method_exists($this, 'saved')) {
256
                $model = $this->saved($model, $data);
257
            }
258
259
            $model->setAttribute('DT_RowId', $model->getKey());
260
            $affected[] = $model;
261
        }
262
263
        if (! $errors) {
264
            $connection->commit();
265
        } else {
266
            $connection->rollBack();
267
        }
268
269
        return $this->toJson($affected, $errors);
270
    }
271
272
    /**
273
     * Get elqouent builder of the model.
274
     *
275
     * @return \Illuminate\Database\Eloquent\Builder
276
     */
277
    protected function getBuilder()
278
    {
279
        $model = $this->resolveModel();
280
281
        if (in_array(\Illuminate\Database\Eloquent\SoftDeletes::class, class_uses($model))) {
282
            return $model->newQuery()->withTrashed();
283
        }
284
285
        return $model->newQuery();
286
    }
287
288
    /**
289
     * Get edit action validation rules.
290
     *
291
     * @param Model $model
292
     * @return array
293
     */
294
    abstract public function editRules(Model $model);
295
296
    /**
297
     * Get edit validation messages.
298
     *
299
     * @deprecated deprecated since v1.12.0, please use messages() instead.
300
     * @return array
301
     */
302
    protected function editMessages()
303
    {
304
        return [];
305
    }
306
307
    /**
308
     * Process force delete action request.
309
     *
310
     * @param \Illuminate\Http\Request $request
311
     * @return \Illuminate\Http\JsonResponse
312
     */
313
    public function forceDelete(Request $request)
314
    {
315
        $this->forceDeleting = true;
316
317
        return $this->remove($request);
318
    }
319
320
    /**
321
     * Process remove action request.
322
     *
323
     * @param Request $request
324
     * @return JsonResponse
325
     */
326
    public function remove(Request $request)
327
    {
328
        $connection = $this->getBuilder()->getConnection();
329
        $affected   = [];
330
        $errors     = [];
331
332
        $connection->beginTransaction();
333
        foreach ($request->get('data') as $key => $data) {
334
            $model     = $this->getBuilder()->findOrFail($key);
335
            $validator = $this->getValidationFactory()
336
                              ->make($data, $this->removeRules($model), $this->messages() + $this->removeMessages(), $this->attributes());
337
            if ($validator->fails()) {
338
                foreach ($this->formatErrors($validator) as $error) {
339
                    $errors[] = $error['status'];
340
                }
341
342
                continue;
343
            }
344
345
            try {
346
                $deleted = clone $model;
347
                if (method_exists($this, 'deleting')) {
348
                    $this->deleting($model, $data);
349
                }
350
351
                $this->forceDeleting ? $model->forceDelete() : $model->delete();
352
353
                if (method_exists($this, 'deleted')) {
354
                    $this->deleted($deleted, $data);
355
                }
356
            } catch (QueryException $exception) {
357
                $error = config('app.debug')
358
                    ? $exception->errorInfo[2]
359
                    : $this->removeExceptionMessage($exception, $model);
360
361
                $errors[] = $error;
362
            }
363
364
            $affected[] = $deleted;
365
        }
366
367
        if (! $errors) {
368
            $connection->commit();
369
        } else {
370
            $connection->rollBack();
371
        }
372
373
        $response = ['data' => $affected];
374
        if ($errors) {
375
            $response['error'] = implode("\n", $errors);
376
        }
377
378
        return new JsonResponse($response, 200);
379
    }
380
381
    /**
382
     * Get remove action validation rules.
383
     *
384
     * @param Model $model
385
     * @return array
386
     */
387
    abstract public function removeRules(Model $model);
388
389
    /**
390
     * Get remove validation messages.
391
     *
392
     * @deprecated deprecated since v1.12.0, please use messages() instead.
393
     * @return array
394
     */
395
    protected function removeMessages()
396
    {
397
        return [];
398
    }
399
400
    /**
401
     * Get remove query exception message.
402
     *
403
     * @param QueryException $exception
404
     * @param Model $model
405
     * @return string
406
     */
407
    protected function removeExceptionMessage(QueryException $exception, Model $model)
408
    {
409
        return "Record {$model->getKey()} is protected and cannot be deleted!";
410
    }
411
412
    /**
413
     * Get dataTables model.
414
     *
415
     * @return Model
416
     */
417
    public function getModel()
418
    {
419
        return $this->model;
420
    }
421
422
    /**
423
     * Set the dataTables model on runtime.
424
     *
425
     * @param Model|string $model
426
     * @return DataTablesEditor
427
     */
428
    public function setModel($model)
429
    {
430
        $this->model = $model;
431
432
        return $this;
433
    }
434
435
    /**
436
     * Set model unguard state.
437
     *
438
     * @param bool $state
439
     * @return $this
440
     */
441
    public function unguard($state = true)
442
    {
443
        $this->unguarded = $state;
444
445
        return $this;
446
    }
447
448
    /**
449
     * Handle uploading of file.
450
     *
451
     * @param \Illuminate\Http\Request $request
452
     * @return \Illuminate\Http\JsonResponse
453
     */
454
    public function upload(Request $request)
455
    {
456
        $field   = $request->input('uploadField');
457
        $storage = Storage::disk($this->disk);
458
459
        try {
460
            $rules      = $this->uploadRules();
461
            $fieldRules = ['upload' => data_get($rules, $field, [])];
462
463
            $this->validate($request, $fieldRules, $this->messages(), $this->attributes());
464
465
            $id = $storage->putFile($this->uploadDir, $request->file('upload'));
466
467
            if (method_exists($this, 'uploaded')) {
468
                $id = $this->uploaded($id);
469
            }
470
471
            return response()->json([
472
                'data'   => [],
473
                'files'   => [
474
                    'files' => [
475
                        $id => [
476
                            'filename'  => $id,
477
                            'size'      => $request->file('upload')->getSize(),
478
                            'directory' => $this->uploadDir,
479
                            'disk'      => $this->disk,
480
                            'url'       => $storage->url($id),
481
                        ]
482
                    ]
483
                ],
484
                'upload' => [
485
                    'id' => $id,
486
                ],
487
            ]);
488
        } catch (ValidationException $exception) {
489
            return response()->json([
490
                'data'        => [],
491
                'fieldErrors' => [
492
                    [
493
                        'name'   => $field,
494
                        'status' => str_replace('upload', $field, $exception->errors()['upload'][0]),
495
                    ],
496
                ],
497
            ]);
498
        }
499
    }
500
501
    /**
502
     * Upload validation rules.
503
     *
504
     * @return array
505
     */
506
    public function uploadRules()
507
    {
508
        return [];
509
    }
510
511
    /**
512
     * Get validation messages.
513
     *
514
     * @return array
515
     */
516
    protected function messages()
517
    {
518
        return [];
519
    }
520
521
    /**
522
     * Display dataTables editor validation errors.
523
     *
524
     * @param Validator $validator
525
     * @return JsonResponse
526
     */
527
    protected function displayValidationErrors(Validator $validator)
528
    {
529
        $errors = $this->formatErrors($validator);
530
531
        return new JsonResponse([
532
            'data'        => [],
533
            'fieldErrors' => $errors,
534
        ]);
535
    }
536
}
537