Passed
Pull Request — 2.x (#640)
by Antonio Carlos
05:47
created

ModuleRepository::prepareFieldsBeforeCreate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
namespace A17\Twill\Repositories;
4
5
use A17\Twill\Models\Model;
6
use A17\Twill\Models\Behaviors\Sortable;
7
use A17\Twill\Repositories\Behaviors\HandleBrowsers;
8
use A17\Twill\Repositories\Behaviors\HandleDates;
9
use A17\Twill\Repositories\Behaviors\HandleFieldsGroups;
10
use A17\Twill\Repositories\Behaviors\HandleRepeaters;
11
use Illuminate\Support\Arr;
12
use Illuminate\Support\Collection;
13
use Illuminate\Support\Facades\App;
14
use Illuminate\Support\Facades\Config;
15
use Illuminate\Support\Facades\DB;
16
use Illuminate\Support\Facades\Log;
17
use Illuminate\Support\Str;
18
use PDO;
19
20
abstract class ModuleRepository
21
{
22
    use HandleDates, HandleBrowsers, HandleRepeaters, HandleFieldsGroups;
0 ignored issues
show
Bug introduced by
The trait A17\Twill\Repositories\Behaviors\HandleRepeaters requires the property $id which is not provided by A17\Twill\Repositories\ModuleRepository.
Loading history...
introduced by
The trait A17\Twill\Repositories\Behaviors\HandleBrowsers requires some properties which are not provided by A17\Twill\Repositories\ModuleRepository: $titleInBrowser, $id, $adminEditUrl, $title
Loading history...
23
24
    /**
25
     * @var \A17\Twill\Models\Model
26
     */
27
    protected $model;
28
29
    /**
30
     * @var string[]
31
     */
32
    protected $ignoreFieldsBeforeSave = [];
33
34
    /**
35
     * @var array
36
     */
37
    protected $countScope = [];
38
39
    /**
40
     * @var array
41
     */
42
    protected $fieldsGroups = [];
43
44
    /**
45
     * @param array $with
46
     * @param array $scopes
47
     * @param array $orders
48
     * @param int $perPage
49
     * @param bool $forcePagination
50
     * @return \Illuminate\Database\Eloquent\Collection
51
     */
52 12
    public function get($with = [], $scopes = [], $orders = [], $perPage = 20, $forcePagination = false)
53
    {
54 12
        $query = $this->model->with($with);
55
56 12
        $query = $this->filter($query, $scopes);
0 ignored issues
show
Bug introduced by
$query of type Illuminate\Database\Eloquent\Builder is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of A17\Twill\Repositories\ModuleRepository::filter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

56
        $query = $this->filter(/** @scrutinizer ignore-type */ $query, $scopes);
Loading history...
57 12
        $query = $this->order($query, $orders);
58
59 12
        if (!$forcePagination && $this->model instanceof Sortable) {
60 3
            return $query->ordered()->get();
61
        }
62
63 10
        if ($perPage == -1) {
64
            return $query->get();
65
        }
66
67 10
        return $query->paginate($perPage);
68
    }
69
70
    /**
71
     * @param string $slug
72
     * @param array $scope
73
     * @return int
74
     */
75 6
    public function getCountByStatusSlug($slug, $scope = [])
76
    {
77 6
        $this->countScope = $scope;
78
79 6
        switch ($slug) {
80 6
            case 'all':
81 5
                return $this->getCountForAll();
82 6
            case 'published':
83 6
                return $this->getCountForPublished();
84 6
            case 'draft':
85 6
                return $this->getCountForDraft();
86 6
            case 'trash':
87 6
                return $this->getCountForTrash();
88
        }
89
90 5
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
91 5
            if (($count = $this->$method($slug)) !== false) {
92 5
                return $count;
93
            }
94
        }
95
96
        return 0;
97
    }
98
99
    /**
100
     * @return int
101
     */
102 5
    public function getCountForAll()
103
    {
104 5
        $query = $this->model->newQuery();
105 5
        return $this->filter($query, $this->countScope)->count();
0 ignored issues
show
Bug introduced by
$query of type Illuminate\Database\Eloquent\Builder is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of A17\Twill\Repositories\ModuleRepository::filter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->count();
Loading history...
106
    }
107
108
    /**
109
     * @return int
110
     */
111 5
    public function getCountForPublished()
112
    {
113 5
        $query = $this->model->newQuery();
114 5
        return $this->filter($query, $this->countScope)->published()->count();
0 ignored issues
show
Bug introduced by
$query of type Illuminate\Database\Eloquent\Builder is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of A17\Twill\Repositories\ModuleRepository::filter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

114
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->published()->count();
Loading history...
115
    }
116
117
    /**
118
     * @return int
119
     */
120 5
    public function getCountForDraft()
121
    {
122 5
        $query = $this->model->newQuery();
123 5
        return $this->filter($query, $this->countScope)->draft()->count();
0 ignored issues
show
Bug introduced by
$query of type Illuminate\Database\Eloquent\Builder is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of A17\Twill\Repositories\ModuleRepository::filter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->draft()->count();
Loading history...
124
    }
125
126
    /**
127
     * @return int
128
     */
129 5
    public function getCountForTrash()
130
    {
131 5
        $query = $this->model->newQuery();
132 5
        return $this->filter($query, $this->countScope)->onlyTrashed()->count();
0 ignored issues
show
Bug introduced by
$query of type Illuminate\Database\Eloquent\Builder is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of A17\Twill\Repositories\ModuleRepository::filter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->onlyTrashed()->count();
Loading history...
133
    }
134
135
    /**
136
     * @param $id
137
     * @param array $with
138
     * @param array $withCount
139
     * @return \A17\Twill\Models\Model
140
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
141
     */
142 17
    public function getById($id, $with = [], $withCount = [])
143
    {
144 17
        return $this->model->with($with)->withCount($withCount)->findOrFail($id);
145
    }
146
147
    /**
148
     * @param string $column
149
     * @param array $orders
150
     * @param null $exceptId
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $exceptId is correct as it would always require null to be passed?
Loading history...
151
     * @return \Illuminate\Support\Collection
152
     */
153
    public function listAll($column = 'title', $orders = [], $exceptId = null)
154
    {
155
        $query = $this->model->newQuery();
156
157
        if ($exceptId) {
0 ignored issues
show
introduced by
$exceptId is of type null, thus it always evaluated to false.
Loading history...
158
            $query = $query->where($this->model->getTable() . '.id', '<>', $exceptId);
159
        }
160
161
        if ($this->model instanceof Sortable) {
162
            $query = $query->ordered();
163
        } elseif (!empty($orders)) {
164
            $query = $this->order($query, $orders);
0 ignored issues
show
Bug introduced by
$query of type Illuminate\Database\Eloquent\Builder is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of A17\Twill\Repositories\ModuleRepository::order(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

164
            $query = $this->order(/** @scrutinizer ignore-type */ $query, $orders);
Loading history...
165
        }
166
167
        if ($this->model->isTranslatable()) {
168
            $query = $query->withTranslation();
169
        }
170
171
        return $query->get()->pluck($column, 'id');
172
    }
173
174
    /**
175
     * @param $search
176
     * @param array $fields
177
     * @return \Illuminate\Database\Eloquent\Collection
178
     */
179
    public function cmsSearch($search, $fields = [])
180
    {
181
        $query = $this->model->latest();
182
183
        $translatedAttributes = $this->model->translatedAttributes ?? [];
0 ignored issues
show
Bug introduced by
The property translatedAttributes does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
184
185
        foreach ($fields as $field) {
186
            if (in_array($field, $translatedAttributes)) {
187
                $query->orWhereHas('translations', function ($q) use ($field, $search) {
188
                    $q->where($field, $this->getLikeOperator(), "%{$search}%");
189
                });
190
            } else {
191
                $query->orWhere($field, $this->getLikeOperator(), "%{$search}%");
192
            }
193
        }
194
195
        return $query->get();
196
    }
197
198
    /**
199
     * @param $attributes
200
     * @param $fields
201
     * @return \A17\Twill\Models\Model
202
     */
203
    public function firstOrCreate($attributes, $fields = [])
204
    {
205
        return $this->model->where($attributes)->first() ?? $this->create($attributes + $fields);
206
    }
207
208
    /**
209
     * @param string[] $fields
210
     * @return \A17\Twill\Models\Model
211
     */
212 27
    public function create($fields)
213
    {
214
        return DB::transaction(function () use ($fields) {
215 27
            $original_fields = $fields;
216
217 27
            $fields = $this->prepareFieldsBeforeCreate($fields);
218
219 27
            $object = $this->model->create(Arr::except($fields, $this->getReservedFields()));
220
221 27
            $this->beforeSave($object, $original_fields);
222
223 27
            $fields = $this->prepareFieldsBeforeSave($object, $fields);
224
225 27
            $object->save();
226
227 27
            $this->afterSave($object, $fields);
228
229 27
            return $object;
230 27
        }, 3);
231
    }
232
233
    /**
234
     * @param array $fields
235
     * @return \A17\Twill\Models\Model
236
     */
237 2
    public function createForPreview($fields)
238
    {
239 2
        $fields = $this->prepareFieldsBeforeCreate($fields);
240
241 2
        $object = $this->model->newInstance(Arr::except($fields, $this->getReservedFields()));
242
243 2
        return $this->hydrate($object, $fields);
244
    }
245
246
    /**
247
     * @param array $attributes
248
     * @param array $fields
249
     * @return \A17\Twill\Models\Model
250
     */
251
    public function updateOrCreate($attributes, $fields)
252
    {
253
        $object = $this->model->where($attributes)->first();
254
255
        if (!$object) {
256
            return $this->create($fields);
257
        }
258
259
        $this->update($object->id, $fields);
260
    }
261
262
    /**
263
     * @param mixed $id
264
     * @param array $fields
265
     * @return void
266
     */
267 11
    public function update($id, $fields)
268
    {
269
        DB::transaction(function () use ($id, $fields) {
270 11
            $object = $this->model->findOrFail($id);
271
272 11
            $this->beforeSave($object, $fields);
273
274 11
            $fields = $this->prepareFieldsBeforeSave($object, $fields);
275
276 11
            $object->fill(Arr::except($fields, $this->getReservedFields()));
277
278 11
            $object->save();
279
280 11
            $this->afterSave($object, $fields);
281 11
        }, 3);
282 11
    }
283
284
    /**
285
     * @param mixed $id
286
     * @param array $values
287
     * @param array $scopes
288
     * @return mixed
289
     */
290 4
    public function updateBasic($id, $values, $scopes = [])
291
    {
292
        return DB::transaction(function () use ($id, $values, $scopes) {
293
            // apply scopes if no id provided
294 4
            if (is_null($id)) {
295 1
                $query = $this->model->query();
296
297 1
                foreach ($scopes as $column => $value) {
298
                    $query->where($column, $value);
299
                }
300
301 1
                $query->update($values);
302
303
                $query->get()->each(function ($object) use ($values) {
304
                    $this->afterUpdateBasic($object, $values);
305 1
                });
306
307 1
                return true;
308
            }
309
310
            // apply to all ids if array of ids provided
311 3
            if (is_array($id)) {
312
                $query = $this->model->whereIn('id', $id);
313
                $query->update($values);
314
315
                $query->get()->each(function ($object) use ($values) {
316
                    $this->afterUpdateBasic($object, $values);
317
                });
318
319
                return true;
320
            }
321
322 3
            if (($object = $this->model->find($id)) != null) {
323 2
                $object->update($values);
324 2
                $this->afterUpdateBasic($object, $values);
325 2
                return true;
326
            }
327
328 1
            return false;
329 4
        }, 3);
330
    }
331
332
    /**
333
     * @param array $ids
334
     * @return void
335
     */
336 2
    public function setNewOrder($ids)
337
    {
338
        DB::transaction(function () use ($ids) {
339 2
            $this->model->setNewOrder($ids);
340 2
        }, 3);
341 1
    }
342
343
    /**
344
     * @param mixed $id
345
     * @return mixed
346
     */
347
    public function duplicate($id, $titleColumnKey = 'title')
348
    {
349
350
        if (($object = $this->model->find($id)) === null) {
351
            return false;
352
        }
353
354
        if (($revision = $object->revisions()->orderBy('created_at', 'desc')->first()) === null) {
355
            return false;
356
        }
357
358
        $revisionInput = json_decode($revision->payload, true);
0 ignored issues
show
Bug introduced by
The property payload does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
359
        $baseInput = collect($revisionInput)->only([
360
            $titleColumnKey,
361
            'slug',
362
            'languages'
363
        ])->filter()->toArray();
364
365
        $newObject = $this->create($baseInput);
366
367
        $this->update($newObject->id, $revisionInput);
368
369
        return $newObject;
370
    }
371
372
    /**
373
     * @param mixed $id
374
     * @return mixed
375
     */
376 2
    public function delete($id)
377
    {
378
        return DB::transaction(function () use ($id) {
379 2
            if (($object = $this->model->find($id)) === null) {
380
                return false;
381
            }
382
383 2
            if (!method_exists($object, 'canDeleteSafely') || $object->canDeleteSafely()) {
384 2
                $object->delete();
385 2
                $this->afterDelete($object);
386 2
                return true;
387
            }
388
            return false;
389 2
        }, 3);
390
    }
391
392
    /**
393
     * @param array $ids
394
     * @return mixed
395
     */
396 17
    public function bulkDelete($ids)
397
    {
398
        return DB::transaction(function () use ($ids) {
399
            try {
400
                Collection::make($ids)->each(function ($id) {
401
                    $this->delete($id);
402 17
                });
403
            } catch (\Exception $e) {
404
                Log::error($e);
405
                return false;
406
            }
407
408 17
            return true;
409 17
        }, 3);
410
    }
411
412
    /**
413
     * @param mixed $id
414
     * @return mixed
415
     */
416
    public function forceDelete($id)
417
    {
418
        return DB::transaction(function () use ($id) {
419
            if (($object = $this->model->onlyTrashed()->find($id)) === null) {
420
                return false;
421
            } else {
422
                $object->forceDelete();
423
                $this->afterDelete($object);
424
                return true;
425
            }
426
        }, 3);
427
    }
428
429
    /**
430
     * @param mixed $id
431
     * @return mixed
432
     */
433
    public function bulkForceDelete($ids)
434
    {
435
        return DB::transaction(function () use ($ids) {
436
            try {
437
                $query = $this->model->onlyTrashed()->whereIn('id', $ids);
438
                $objects = $query->get();
439
440
                $query->forceDelete();
441
442
                $objects->each(function ($object) {
443
                    $this->afterDelete($object);
444
                });
445
            } catch (\Exception $e) {
446
                Log::error($e);
447
                return false;
448
            }
449
450
            return true;
451
        }, 3);
452
    }
453
454
    /**
455
     * @param mixed $id
456
     * @return mixed
457
     */
458 2
    public function restore($id)
459
    {
460
        return DB::transaction(function () use ($id) {
461 2
            if (($object = $this->model->withTrashed()->find($id)) != null) {
462 1
                $object->restore();
463 1
                $this->afterRestore($object);
464 1
                return true;
465
            }
466
467 1
            return false;
468 2
        }, 3);
469
    }
470
471
    /**
472
     * @param array $ids
473
     * @return mixed
474
     */
475
    public function bulkRestore($ids)
476
    {
477
        return DB::transaction(function () use ($ids) {
478
            try {
479
                $query = $this->model->withTrashed()->whereIn('id', $ids);
480
                $objects = $query->get();
481
482
                $query->restore();
483
484
                $objects->each(function ($object) {
485
                    $this->afterRestore($object);
486
                });
487
            } catch (\Exception $e) {
488
                Log::error($e);
489
                return false;
490
            }
491
492
            return true;
493
        }, 3);
494
    }
495
496
    /**
497
     * @param \A17\Twill\Models\Model $object
498
     * @param array $fields
499
     * @return array
500
     */
501 28
    public function cleanupFields($object, $fields)
502
    {
503 28
        if (property_exists($this->model, 'checkboxes')) {
504 21
            foreach ($this->model->checkboxes as $field) {
0 ignored issues
show
Bug introduced by
The property checkboxes does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
505 21
                if (!$this->shouldIgnoreFieldBeforeSave($field)) {
506 21
                    if (!isset($fields[$field])) {
507 5
                        $fields[$field] = false;
508
                    } else {
509 21
                        $fields[$field] = !empty($fields[$field]);
510
                    }
511
                }
512
            }
513
        }
514
515 28
        if (property_exists($this->model, 'nullable')) {
516
            foreach ($this->model->nullable as $field) {
0 ignored issues
show
Bug introduced by
The property nullable does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
517
                if (!isset($fields[$field]) && !$this->shouldIgnoreFieldBeforeSave($field)) {
518
                    $fields[$field] = null;
519
                }
520
            }
521
        }
522
523 28
        foreach ($fields as $key => $value) {
524 28
            if (!$this->shouldIgnoreFieldBeforeSave($key)) {
525 28
                if (is_array($value) && empty($value)) {
526 7
                    $fields[$key] = null;
527
                }
528 28
                if ($value === '') {
529
                    $fields[$key] = null;
530
                }
531
            }
532
        }
533
534 28
        return $fields;
535
    }
536
537
    /**
538
     * @param array $fields
539
     * @return array
540
     */
541 22
    public function prepareFieldsBeforeCreate($fields)
542
    {
543 22
        $fields = $this->cleanupFields(null, $fields);
544
545 22
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
546 22
            $fields = $this->$method($fields);
547
        }
548
549 22
        return $fields;
550
    }
551
552
    /**
553
     * @param \A17\Twill\Models\Model $object
554
     * @param array $fields
555
     * @return string[]
556
     */
557 27
    public function prepareFieldsBeforeSave($object, $fields)
558
    {
559 27
        $fields = $this->cleanupFields($object, $fields);
560
561 27
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
562 27
            $fields = $this->$method($object, $fields);
563
        }
564
565 27
        return $fields;
566
    }
567
568
    /**
569
     * @param \A17\Twill\Models\Model $object
570
     * @param array $fields
571
     * @return void
572
     */
573 2
    public function afterUpdateBasic($object, $fields)
574
    {
575 2
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
576
            $this->$method($object, $fields);
577
        }
578 2
    }
579
580
    /**
581
     * @param \A17\Twill\Models\Model $object
582
     * @param array $fields
583
     * @return void
584
     */
585 27
    public function beforeSave($object, $fields)
586
    {
587 27
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
588 17
            $this->$method($object, $fields);
589
        }
590 27
    }
591
592
    /**
593
     * @param \A17\Twill\Models\Model $object
594
     * @param array $fields
595
     * @return void
596
     */
597 27
    public function afterSave($object, $fields)
598
    {
599 27
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
600 27
            $this->$method($object, $fields);
601
        }
602 27
    }
603
604
    /**
605
     * @param \A17\Twill\Models\Model $object
606
     * @return void
607
     */
608 2
    public function afterDelete($object)
609
    {
610 2
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
611 2
            $this->$method($object);
612
        }
613 2
    }
614
615
    /**
616
     * @param \A17\Twill\Models\Model $object
617
     * @return void
618
     */
619 1
    public function afterRestore($object)
620
    {
621 1
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
622 1
            $this->$method($object);
623
        }
624 1
    }
625
626
    /**
627
     * @param \A17\Twill\Models\Model $object
628
     * @param array $fields
629
     * @return \A17\Twill\Models\Model
630
     */
631 3
    public function hydrate($object, $fields)
632
    {
633 3
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
634 3
            $object = $this->$method($object, $fields);
635
        }
636
637 3
        return $object;
638
    }
639
640
    /**
641
     * @param \A17\Twill\Models\Model $object
642
     * @return array
643
     */
644 5
    public function getFormFields($object)
645
    {
646 5
        $fields = $object->attributesToArray();
647
648 5
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
649 5
            $fields = $this->$method($object, $fields);
650
        }
651
652 5
        return $fields;
653
    }
654
655
    /**
656
     * @param \Illuminate\Database\Query\Builder $query
657
     * @param array $scopes
658
     * @return \Illuminate\Database\Query\Builder
659
     */
660 12
    public function filter($query, array $scopes = [])
661
    {
662 12
        $likeOperator = $this->getLikeOperator();
663
664 12
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
665 11
            $this->$method($query, $scopes);
666
        }
667
668 12
        unset($scopes['search']);
669
670 12
        if (isset($scopes['exceptIds'])) {
671 2
            $query->whereNotIn($this->model->getTable() . '.id', $scopes['exceptIds']);
672 2
            unset($scopes['exceptIds']);
673
        }
674
675 12
        foreach ($scopes as $column => $value) {
676 5
            if (method_exists($this->model, 'scope' . ucfirst($column))) {
677 1
                $query->$column();
678
            } else {
679 4
                if (is_array($value)) {
680 2
                    $query->whereIn($column, $value);
681 2
                } elseif ($column[0] == '%') {
682
                    $value && ($value[0] == '!') ? $query->where(substr($column, 1), "not $likeOperator", '%' . substr($value, 1) . '%') : $query->where(substr($column, 1), $likeOperator, '%' . $value . '%');
683 2
                } elseif (isset($value[0]) && $value[0] == '!') {
684
                    $query->where($column, '<>', substr($value, 1));
685 2
                } elseif ($value !== '') {
686 2
                    $query->where($column, $value);
687
                }
688
            }
689
        }
690
691 12
        return $query;
692
    }
693
694
    /**
695
     * @param \Illuminate\Database\Query\Builder $query
696
     * @param array $orders
697
     * @return \Illuminate\Database\Query\Builder
698
     */
699 12
    public function order($query, array $orders = [])
700
    {
701 12
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
702 7
            $this->$method($query, $orders);
703
        }
704
705 12
        foreach ($orders as $column => $direction) {
706 5
            $query->orderBy($column, $direction);
707
        }
708
709 12
        return $query;
710
    }
711
712
    /**
713
     * @param \A17\Twill\Models\Model $object
714
     * @param array $fields
715
     * @param string $relationship
716
     * @param string $formField
717
     * @param string $attribute
718
     * @return void
719
     */
720
    public function updateOneToMany($object, $fields, $relationship, $formField, $attribute)
721
    {
722
        if (isset($fields[$formField])) {
723
            foreach ($fields[$formField] as $id) {
724
                $object->$relationship()->updateOrCreate([$attribute => $id]);
725
            }
726
727
            foreach ($object->$relationship as $relationshipObject) {
728
                if (!in_array($relationshipObject->$attribute, $fields[$formField])) {
729
                    $relationshipObject->delete();
730
                }
731
            }
732
        } else {
733
            $object->$relationship()->delete();
734
        }
735
    }
736
737
    /**
738
     * @param \A17\Twill\Models\Model $object
739
     * @param array $fields
740
     * @param string $relationship
741
     * @return void
742
     */
743
    public function updateMultiSelect($object, $fields, $relationship)
744
    {
745
        $object->$relationship()->sync($fields[$relationship] ?? []);
746
    }
747
748
    /**
749
     * @param \Illuminate\Database\Query\Builder $query
750
     * @param array $scopes
751
     * @param string $scopeField
752
     * @param string $scopeRelation
753
     * @return void
754
     */
755 9
    public function addRelationFilterScope($query, &$scopes, $scopeField, $scopeRelation)
756
    {
757 9
        if (isset($scopes[$scopeField])) {
758
            $id = $scopes[$scopeField];
759
            $query->whereHas($scopeRelation, function ($query) use ($id, $scopeField) {
760
                $query->where($scopeField, $id);
761
            });
762
            unset($scopes[$scopeField]);
763
        }
764 9
    }
765
766
    /**
767
     * @param \Illuminate\Database\Query\Builder $query
768
     * @param array $scopes
769
     * @param string $scopeField
770
     * @return void
771
     */
772
    public function addLikeFilterScope($query, &$scopes, $scopeField)
773
    {
774
        if (isset($scopes[$scopeField]) && is_string($scopes[$scopeField])) {
775
            $query->where($scopeField, $this->getLikeOperator(), '%' . $scopes[$scopeField] . '%');
776
            unset($scopes[$scopeField]);
777
        }
778
    }
779
780
    /**
781
     * @param \Illuminate\Database\Query\Builder $query
782
     * @param array $scopes
783
     * @param string $scopeField
784
     * @param string[] $orFields
785
     */
786 5
    public function searchIn($query, &$scopes, $scopeField, $orFields = [])
787
    {
788
789 5
        if (isset($scopes[$scopeField]) && is_string($scopes[$scopeField])) {
790
            $query->where(function ($query) use (&$scopes, $scopeField, $orFields) {
791 2
                foreach ($orFields as $field) {
792 2
                    $query->orWhere($field, $this->getLikeOperator(), '%' . $scopes[$scopeField] . '%');
793 2
                    unset($scopes[$field]);
794
                }
795 2
            });
796
        }
797 5
    }
798
799
    /**
800
     * @return bool
801
     */
802 2
    public function isUniqueFeature()
803
    {
804 2
        return false;
805
    }
806
807
    /**
808
     * @param array $ignore
809
     * @return void
810
     */
811
    public function addIgnoreFieldsBeforeSave($ignore = [])
812
    {
813
        $this->ignoreFieldsBeforeSave = is_array($ignore)
0 ignored issues
show
introduced by
The condition is_array($ignore) is always true.
Loading history...
814
        ? array_merge($this->ignoreFieldsBeforeSave, $ignore)
815
        : array_merge($this->ignoreFieldsBeforeSave, [$ignore]);
816
    }
817
818
    /**
819
     * @param string $ignore
820
     * @return bool
821
     */
822 28
    public function shouldIgnoreFieldBeforeSave($ignore)
823
    {
824 28
        return in_array($ignore, $this->ignoreFieldsBeforeSave);
825
    }
826
827
    /**
828
     * @return string[]
829
     */
830 28
    public function getReservedFields()
831
    {
832
        return [
833 28
            'medias',
834
            'browsers',
835
            'repeaters',
836
            'blocks',
837
        ];
838
    }
839
840
    /**
841
     * @param string $relation
842
     * @param \A17\Twill\Models\Model|null $model
843
     * @return mixed
844
     */
845
    protected function getModelRepository($relation, $model = null)
846
    {
847
        if (!$model) {
848
            if (class_exists($relation) && (new $relation) instanceof Model) {
849
                $model = Str::afterLast($relation, '\\');
850
            } else {
851
                $model = ucfirst(Str::singular($relation));
852
            }
853
        }
854
855
        return App::make(Config::get('twill.namespace') . "\\Repositories\\" . ucfirst($model) . "Repository");
856
    }
857
858
    /**
859
     * @param string|null $method
860
     * @return array
861
     */
862 34
    protected function traitsMethods(string $method = null)
863
    {
864 34
        $method = $method ?? debug_backtrace()[1]['function'];
865
866 34
        $traits = array_values(class_uses_recursive(get_called_class()));
867
868 34
        $uniqueTraits = array_unique(array_map('class_basename', $traits));
869
870
        $methods = array_map(function (string $trait) use ($method) {
871 34
            return $method . $trait;
872 34
        }, $uniqueTraits);
873
874
        return array_filter($methods, function (string $method) {
875 34
            return method_exists(get_called_class(), $method);
876 34
        });
877
    }
878
879
    /**
880
     * @return string
881
     */
882 12
    private function getLikeOperator()
883
    {
884 12
        if (DB::connection()->getPDO()->getAttribute(PDO::ATTR_DRIVER_NAME) === 'pgsql') {
885
            return 'ILIKE';
886
        }
887
888 12
        return 'LIKE';
889
    }
890
891
    /**
892
     * @param string $method
893
     * @param array $parameters
894
     * @return mixed
895
     */
896 2
    public function __call($method, $parameters)
897
    {
898 2
        return $this->model->$method(...$parameters);
899
    }
900
901
    /**
902
     * @param string $behavior
903
     * @return boolean
904
     */
905 29
    public function hasBehavior($behavior)
906
    {
907 29
        $hasBehavior = classHasTrait($this, 'A17\Twill\Repositories\Behaviors\Handle' . ucfirst($behavior));
908
909 29
        if (Str::startsWith($behavior, 'translation')) {
910 28
            $hasBehavior = $hasBehavior && $this->model->isTranslatable();
911
        }
912
913 29
        return $hasBehavior;
914
    }
915
916
    /**
917
     * @return boolean
918
     */
919 6
    public function isTranslatable($column)
920
    {
921 6
        return $this->model->isTranslatable($column);
922
    }
923
}
924