Completed
Push — master ( 33359f...302cd5 )
by Arjay
22s queued 11s
created

src/DataTablesEditor.php (2 issues)

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\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
     * Indicates if all mass assignment is enabled on model.
30
     *
31
     * @var bool
32
     */
33
    protected $unguarded = false;
34
35
    /**
36
     * Process dataTables editor action request.
37
     *
38
     * @param Request $request
39
     * @return JsonResponse|mixed
40
     * @throws DataTablesEditorException
41
     */
42
    public function process(Request $request)
43
    {
44
        $action = $request->get('action');
45
46
        if (! in_array($action, $this->actions)) {
47
            throw new DataTablesEditorException('Requested action not supported!');
48
        }
49
50
        return $this->{$action}($request);
51
    }
52
53
    /**
54
     * Process create action request.
55
     *
56
     * @param Request $request
57
     * @return JsonResponse
58
     */
59 View Code Duplication
    public function create(Request $request)
60
    {
61
        $instance   = $this->resolveModel();
62
        $connection = $instance->getConnection();
63
        $affected   = [];
64
        $errors     = [];
65
66
        $connection->beginTransaction();
67
        foreach ($request->get('data') as $data) {
68
            $validator = $this->getValidationFactory()
69
                              ->make($data, $this->createRules(), $this->createMessages(), $this->attributes());
70
            if ($validator->fails()) {
71
                foreach ($this->formatErrors($validator) as $error) {
72
                    $errors[] = $error;
73
                }
74
75
                continue;
76
            }
77
78
            if (method_exists($this, 'creating')) {
79
                $data = $this->creating($instance, $data);
80
            }
81
82
            if (method_exists($this, 'saving')) {
83
                $data = $this->saving($instance, $data);
84
            }
85
86
            $instance->fill($data)->save();
87
88
            if (method_exists($this, 'created')) {
89
                $instance = $this->created($instance, $data);
90
            }
91
92
            if (method_exists($this, 'saved')) {
93
                $instance = $this->saved($instance, $data);
94
            }
95
96
            $instance->setAttribute('DT_RowId', $instance->getKey());
97
            $affected[] = $instance;
98
        }
99
100
        if (! $errors) {
101
            $connection->commit();
102
        } else {
103
            $connection->rollBack();
104
        }
105
106
        return $this->toJson($affected, $errors);
107
    }
108
109
    /**
110
     * Resolve model to used.
111
     *
112
     * @return Model|\Illuminate\Database\Eloquent\SoftDeletes
113
     */
114
    protected function resolveModel()
115
    {
116
        if (! $this->model instanceof Model) {
117
            $this->model = new $this->model;
118
        }
119
120
        $this->model->unguard($this->unguarded);
121
122
        return $this->model;
123
    }
124
125
    /**
126
     * Get create action validation rules.
127
     *
128
     * @return array
129
     */
130
    abstract public function createRules();
131
132
    /**
133
     * Get create validation messages.
134
     *
135
     * @return array
136
     */
137
    protected function createMessages()
138
    {
139
        return [];
140
    }
141
142
    /**
143
     * Get custom attributes for validator errors.
144
     *
145
     * @return array
146
     */
147
    public function attributes()
148
    {
149
        return [];
150
    }
151
152
    /**
153
     * @param Validator $validator
154
     * @return array
155
     */
156
    protected function formatErrors(Validator $validator)
157
    {
158
        $errors = [];
159
160
        collect($validator->errors())->each(function ($error, $key) use (&$errors) {
161
            $errors[] = [
162
                'name'   => $key,
163
                'status' => $error[0],
164
            ];
165
        });
166
167
        return $errors;
168
    }
169
170
    /**
171
     * Display success data in dataTables editor format.
172
     *
173
     * @param array $data
174
     * @param array $errors
175
     * @return JsonResponse
176
     */
177
    protected function toJson(array $data, array $errors = [])
178
    {
179
        $response = ['data' => $data];
180
        if ($errors) {
181
            $response['fieldErrors'] = $errors;
182
        }
183
184
        return new JsonResponse($response, 200);
185
    }
186
187
    /**
188
     * Process edit action request.
189
     *
190
     * @param Request $request
191
     * @return JsonResponse
192
     */
193 View Code Duplication
    public function edit(Request $request)
194
    {
195
        $connection = $this->getBuilder()->getConnection();
196
        $affected   = [];
197
        $errors     = [];
198
199
        $connection->beginTransaction();
200
        foreach ($request->get('data') as $key => $data) {
201
            $model     = $this->getBuilder()->findOrFail($key);
202
            $validator = $this->getValidationFactory()
203
                              ->make($data, $this->editRules($model), $this->editMessages(), $this->attributes());
0 ignored issues
show
$model is of type object|null, but the function expects a object<Illuminate\Database\Eloquent\Model>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
204
            if ($validator->fails()) {
205
                foreach ($this->formatErrors($validator) as $error) {
206
                    $errors[] = $error;
207
                }
208
209
                continue;
210
            }
211
212
            if (method_exists($this, 'updating')) {
213
                $data = $this->updating($model, $data);
214
            }
215
216
            if (method_exists($this, 'saving')) {
217
                $data = $this->saving($model, $data);
218
            }
219
220
            $model->fill($data)->save();
221
222
            if (method_exists($this, 'updated')) {
223
                $model = $this->updated($model, $data);
224
            }
225
226
            if (method_exists($this, 'saved')) {
227
                $model = $this->saved($model, $data);
228
            }
229
230
            $model->setAttribute('DT_RowId', $model->getKey());
231
            $affected[] = $model;
232
        }
233
234
        if (! $errors) {
235
            $connection->commit();
236
        } else {
237
            $connection->rollBack();
238
        }
239
240
        return $this->toJson($affected, $errors);
241
    }
242
243
    /**
244
     * Get elqouent builder of the model.
245
     *
246
     * @return \Illuminate\Database\Eloquent\Builder
247
     */
248
    protected function getBuilder()
249
    {
250
        $model = $this->resolveModel();
251
252
        if (in_array(\Illuminate\Database\Eloquent\SoftDeletes::class, class_uses($model))) {
253
            return $model->newQuery()->withTrashed();
254
        }
255
256
        return $model->newQuery();
257
    }
258
259
    /**
260
     * Get edit action validation rules.
261
     *
262
     * @param Model $model
263
     * @return array
264
     */
265
    abstract public function editRules(Model $model);
266
267
    /**
268
     * Get edit validation messages.
269
     *
270
     * @return array
271
     */
272
    protected function editMessages()
273
    {
274
        return [];
275
    }
276
277
    /**
278
     * Process remove action request.
279
     *
280
     * @param Request $request
281
     * @return JsonResponse
282
     */
283
    public function remove(Request $request)
284
    {
285
        $connection = $this->getBuilder()->getConnection();
286
        $affected   = [];
287
        $errors     = [];
288
289
        $connection->beginTransaction();
290
        foreach ($request->get('data') as $key => $data) {
291
            $model     = $this->getBuilder()->findOrFail($key);
292
            $validator = $this->getValidationFactory()
293
                              ->make($data, $this->removeRules($model), $this->removeMessages(), $this->attributes());
0 ignored issues
show
$model is of type object|null, but the function expects a object<Illuminate\Database\Eloquent\Model>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
294
            if ($validator->fails()) {
295
                foreach ($this->formatErrors($validator) as $error) {
296
                    $errors[] = $error['status'];
297
                }
298
299
                continue;
300
            }
301
302
            try {
303
                $deleted = clone $model;
304
                if (method_exists($this, 'deleting')) {
305
                    $this->deleting($model, $data);
306
                }
307
308
                $model->delete();
309
310
                if (method_exists($this, 'deleted')) {
311
                    $this->deleted($deleted, $data);
312
                }
313
            } catch (QueryException $exception) {
314
                $error = config('app.debug')
315
                    ? $exception->errorInfo[2]
316
                    : $this->removeExceptionMessage($exception, $model);
317
318
                $errors[] = $error;
319
            }
320
321
            $affected[] = $deleted;
322
        }
323
324
        if (! $errors) {
325
            $connection->commit();
326
        } else {
327
            $connection->rollBack();
328
        }
329
330
        $response = ['data' => $affected];
331
        if ($errors) {
332
            $response['error'] = implode("\n", $errors);
333
        }
334
335
        return new JsonResponse($response, 200);
336
    }
337
338
    /**
339
     * Get remove action validation rules.
340
     *
341
     * @param Model $model
342
     * @return array
343
     */
344
    abstract public function removeRules(Model $model);
345
346
    /**
347
     * Get remove validation messages.
348
     *
349
     * @return array
350
     */
351
    protected function removeMessages()
352
    {
353
        return [];
354
    }
355
356
    /**
357
     * Get remove query exception message.
358
     *
359
     * @param QueryException $exception
360
     * @param Model $model
361
     * @return string
362
     */
363
    protected function removeExceptionMessage(QueryException $exception, Model $model)
364
    {
365
        return "Record {$model->getKey()} is protected and cannot be deleted!";
366
    }
367
368
    /**
369
     * Get dataTables model.
370
     *
371
     * @return Model
372
     */
373
    public function getModel()
374
    {
375
        return $this->model;
376
    }
377
378
    /**
379
     * Set the dataTables model on runtime.
380
     *
381
     * @param Model|string $model
382
     * @return DataTablesEditor
383
     */
384
    public function setModel($model)
385
    {
386
        $this->model = $model;
387
388
        return $this;
389
    }
390
391
    /**
392
     * Set model unguard state.
393
     *
394
     * @param bool $state
395
     * @return $this
396
     */
397
    public function unguard($state = true)
398
    {
399
        $this->unguarded = $state;
400
401
        return $this;
402
    }
403
404
    /**
405
     * Display dataTables editor validation errors.
406
     *
407
     * @param Validator $validator
408
     * @return JsonResponse
409
     */
410
    protected function displayValidationErrors(Validator $validator)
411
    {
412
        $errors = $this->formatErrors($validator);
413
414
        return new JsonResponse([
415
            'data'        => [],
416
            'fieldErrors' => $errors,
417
        ]);
418
    }
419
}
420