Passed
Push — 2.x ( 13643d...3dd660 )
by Quentin
07:04
created

ModuleRepository::cleanupFields()   C

Complexity

Conditions 14
Paths 24

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 16.1502

Importance

Changes 0
Metric Value
cc 14
eloc 18
nc 24
nop 2
dl 0
loc 34
ccs 14
cts 18
cp 0.7778
crap 16.1502
rs 6.2666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 Illuminate\Database\Eloquent\Relations\Relation;
19
20
use PDO;
21
22
abstract class ModuleRepository
23
{
24
    use HandleDates, HandleBrowsers, HandleRepeaters, HandleFieldsGroups;
0 ignored issues
show
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...
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...
25
26
    /**
27
     * @var \A17\Twill\Models\Model
28
     */
29
    protected $model;
30
31
    /**
32
     * @var string[]
33
     */
34
    protected $ignoreFieldsBeforeSave = [];
35
36
    /**
37
     * @var array
38
     */
39
    protected $countScope = [];
40
41
    /**
42
     * @var array
43
     */
44
    protected $fieldsGroups = [];
45
46
    /**
47
     * @param array $with
48
     * @param array $scopes
49
     * @param array $orders
50
     * @param int $perPage
51
     * @param bool $forcePagination
52
     * @return \Illuminate\Database\Eloquent\Collection
53
     */
54 12
    public function get($with = [], $scopes = [], $orders = [], $perPage = 20, $forcePagination = false)
55
    {
56 12
        $query = $this->model->with($with);
57
58 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

58
        $query = $this->filter(/** @scrutinizer ignore-type */ $query, $scopes);
Loading history...
59 12
        $query = $this->order($query, $orders);
60
61 12
        if (!$forcePagination && $this->model instanceof Sortable) {
62 3
            return $query->ordered()->get();
63
        }
64
65 10
        if ($perPage == -1) {
66
            return $query->get();
67
        }
68
69 10
        return $query->paginate($perPage);
70
    }
71
72
    /**
73
     * @param string $slug
74
     * @param array $scope
75
     * @return int
76
     */
77 33
    public function getCountByStatusSlug($slug, $scope = [])
78
    {
79 33
        $this->countScope = $scope;
80
81 33
        switch ($slug) {
82 33
            case 'all':
83 32
                return $this->getCountForAll();
84 6
            case 'published':
85 6
                return $this->getCountForPublished();
86 6
            case 'draft':
87 6
                return $this->getCountForDraft();
88 6
            case 'trash':
89 6
                return $this->getCountForTrash();
90
        }
91
92 5
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
93 5
            if (($count = $this->$method($slug)) !== false) {
94 5
                return $count;
95
            }
96
        }
97
98
        return 0;
99
    }
100
101
    /**
102
     * @return int
103
     */
104 32
    public function getCountForAll()
105
    {
106 32
        $query = $this->model->newQuery();
107 32
        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

107
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->count();
Loading history...
108
    }
109
110
    /**
111
     * @return int
112
     */
113 5
    public function getCountForPublished()
114
    {
115 5
        $query = $this->model->newQuery();
116 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

116
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->published()->count();
Loading history...
117
    }
118
119
    /**
120
     * @return int
121
     */
122 5
    public function getCountForDraft()
123
    {
124 5
        $query = $this->model->newQuery();
125 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

125
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->draft()->count();
Loading history...
126
    }
127
128
    /**
129
     * @return int
130
     */
131 5
    public function getCountForTrash()
132
    {
133 5
        $query = $this->model->newQuery();
134 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

134
        return $this->filter(/** @scrutinizer ignore-type */ $query, $this->countScope)->onlyTrashed()->count();
Loading history...
135
    }
136
137
    /**
138
     * @param $id
139
     * @param array $with
140
     * @param array $withCount
141
     * @return \A17\Twill\Models\Model
142
     * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
143
     */
144 18
    public function getById($id, $with = [], $withCount = [])
145
    {
146 18
        return $this->model->with($with)->withCount($withCount)->findOrFail($id);
147
    }
148
149
    /**
150
     * @param string $column
151
     * @param array $orders
152
     * @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...
153
     * @return \Illuminate\Support\Collection
154
     */
155
    public function listAll($column = 'title', $orders = [], $exceptId = null)
156
    {
157
        $query = $this->model->newQuery();
158
159
        if ($exceptId) {
0 ignored issues
show
introduced by
$exceptId is of type null, thus it always evaluated to false.
Loading history...
160
            $query = $query->where($this->model->getTable() . '.id', '<>', $exceptId);
161
        }
162
163
        if ($this->model instanceof Sortable) {
164
            $query = $query->ordered();
165
        } elseif (!empty($orders)) {
166
            $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

166
            $query = $this->order(/** @scrutinizer ignore-type */ $query, $orders);
Loading history...
167
        }
168
169
        if ($this->model->isTranslatable()) {
170
            $query = $query->withTranslation();
171
        }
172
173
        return $query->get()->pluck($column, 'id');
174
    }
175
176
    /**
177
     * @param $search
178
     * @param array $fields
179
     * @return \Illuminate\Database\Eloquent\Collection
180
     */
181 1
    public function cmsSearch($search, $fields = [])
182
    {
183 1
        $query = $this->model->latest();
184
185 1
        $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...
186
187 1
        foreach ($fields as $field) {
188 1
            if (in_array($field, $translatedAttributes)) {
189
                $query->orWhereHas('translations', function ($q) use ($field, $search) {
190 1
                    $q->where($field, $this->getLikeOperator(), "%{$search}%");
191 1
                });
192
            } else {
193
                $query->orWhere($field, $this->getLikeOperator(), "%{$search}%");
194
            }
195
        }
196
197 1
        return $query->get();
198
    }
199
200
    /**
201
     * @param $attributes
202
     * @param $fields
203
     * @return \A17\Twill\Models\Model
204
     */
205
    public function firstOrCreate($attributes, $fields = [])
206
    {
207
        return $this->model->where($attributes)->first() ?? $this->create($attributes + $fields);
208
    }
209
210
    /**
211
     * @param string[] $fields
212
     * @return \A17\Twill\Models\Model
213
     */
214 31
    public function create($fields)
215
    {
216
        return DB::transaction(function () use ($fields) {
217 31
            $original_fields = $fields;
218
219 31
            $fields = $this->prepareFieldsBeforeCreate($fields);
220
221 31
            $object = $this->model->create(Arr::except($fields, $this->getReservedFields()));
222
223 31
            $this->beforeSave($object, $original_fields);
224
225 31
            $fields = $this->prepareFieldsBeforeSave($object, $fields);
226
227 31
            $object->save();
228
229 31
            $this->afterSave($object, $fields);
230
231 31
            return $object;
232 31
        }, 3);
233
    }
234
235
    /**
236
     * @param array $fields
237
     * @return \A17\Twill\Models\Model
238
     */
239 2
    public function createForPreview($fields)
240
    {
241 2
        $fields = $this->prepareFieldsBeforeCreate($fields);
242
243 2
        $object = $this->model->newInstance(Arr::except($fields, $this->getReservedFields()));
244
245 2
        return $this->hydrate($object, $fields);
246
    }
247
248
    /**
249
     * @param array $attributes
250
     * @param array $fields
251
     * @return \A17\Twill\Models\Model
252
     */
253
    public function updateOrCreate($attributes, $fields)
254
    {
255
        $object = $this->model->where($attributes)->first();
256
257
        if (!$object) {
258
            return $this->create($fields);
259
        }
260
261
        $this->update($object->id, $fields);
262
    }
263
264
    /**
265
     * @param mixed $id
266
     * @param array $fields
267
     * @return void
268
     */
269 12
    public function update($id, $fields)
270
    {
271
        DB::transaction(function () use ($id, $fields) {
272 12
            $object = $this->model->findOrFail($id);
273
274 12
            $this->beforeSave($object, $fields);
275
276 12
            $fields = $this->prepareFieldsBeforeSave($object, $fields);
277
278 12
            $object->fill(Arr::except($fields, $this->getReservedFields()));
279
280 12
            $object->save();
281
282 12
            $this->afterSave($object, $fields);
283 12
        }, 3);
284 12
    }
285
286
    /**
287
     * @param mixed $id
288
     * @param array $values
289
     * @param array $scopes
290
     * @return mixed
291
     */
292 4
    public function updateBasic($id, $values, $scopes = [])
293
    {
294
        return DB::transaction(function () use ($id, $values, $scopes) {
295
            // apply scopes if no id provided
296 4
            if (is_null($id)) {
297 1
                $query = $this->model->query();
298
299 1
                foreach ($scopes as $column => $value) {
300
                    $query->where($column, $value);
301
                }
302
303 1
                $query->update($values);
304
305
                $query->get()->each(function ($object) use ($values) {
306
                    $this->afterUpdateBasic($object, $values);
307 1
                });
308
309 1
                return true;
310
            }
311
312
            // apply to all ids if array of ids provided
313 3
            if (is_array($id)) {
314
                $query = $this->model->whereIn('id', $id);
315
                $query->update($values);
316
317
                $query->get()->each(function ($object) use ($values) {
318
                    $this->afterUpdateBasic($object, $values);
319
                });
320
321
                return true;
322
            }
323
324 3
            if (($object = $this->model->find($id)) != null) {
325 2
                $object->update($values);
326 2
                $this->afterUpdateBasic($object, $values);
327 2
                return true;
328
            }
329
330 1
            return false;
331 4
        }, 3);
332
    }
333
334
    /**
335
     * @param array $ids
336
     * @return void
337
     */
338 2
    public function setNewOrder($ids)
339
    {
340
        DB::transaction(function () use ($ids) {
341 2
            $this->model->setNewOrder($ids);
342 2
        }, 3);
343 1
    }
344
345
    /**
346
     * @param mixed $id
347
     * @return mixed
348
     */
349
    public function duplicate($id, $titleColumnKey = 'title')
350
    {
351
352
        if (($object = $this->model->find($id)) === null) {
353
            return false;
354
        }
355
356
        if (($revision = $object->revisions()->orderBy('created_at', 'desc')->first()) === null) {
357
            return false;
358
        }
359
360
        $revisionInput = json_decode($revision->payload, true);
0 ignored issues
show
Bug introduced by
It seems like $revision->payload can also be of type Illuminate\Database\Eloq...uent\Relations\Relation and Illuminate\Database\Eloquent\Relations\Relation; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

360
        $revisionInput = json_decode(/** @scrutinizer ignore-type */ $revision->payload, true);
Loading history...
361
        $baseInput = collect($revisionInput)->only([
362
            $titleColumnKey,
363
            'slug',
364
            'languages'
365
        ])->filter()->toArray();
366
367
        $newObject = $this->create($baseInput);
368
369
        $this->update($newObject->id, $revisionInput);
370
371
        return $newObject;
372
    }
373
374
    /**
375
     * @param mixed $id
376
     * @return mixed
377
     */
378 2
    public function delete($id)
379
    {
380
        return DB::transaction(function () use ($id) {
381 2
            if (($object = $this->model->find($id)) === null) {
382
                return false;
383
            }
384
385 2
            if (!method_exists($object, 'canDeleteSafely') || $object->canDeleteSafely()) {
386 2
                $object->delete();
387 2
                $this->afterDelete($object);
388 2
                return true;
389
            }
390
            return false;
391 2
        }, 3);
392
    }
393
394
    /**
395
     * @param array $ids
396
     * @return mixed
397
     */
398 21
    public function bulkDelete($ids)
399
    {
400
        return DB::transaction(function () use ($ids) {
401
            try {
402
                Collection::make($ids)->each(function ($id) {
403
                    $this->delete($id);
404 21
                });
405
            } catch (\Exception $e) {
406
                Log::error($e);
407
                return false;
408
            }
409
410 21
            return true;
411 21
        }, 3);
412
    }
413
414
    /**
415
     * @param mixed $id
416
     * @return mixed
417
     */
418
    public function forceDelete($id)
419
    {
420
        return DB::transaction(function () use ($id) {
421
            if (($object = $this->model->onlyTrashed()->find($id)) === null) {
422
                return false;
423
            } else {
424
                $object->forceDelete();
425
                $this->afterDelete($object);
426
                return true;
427
            }
428
        }, 3);
429
    }
430
431
    /**
432
     * @param mixed $id
433
     * @return mixed
434
     */
435
    public function bulkForceDelete($ids)
436
    {
437
        return DB::transaction(function () use ($ids) {
438
            try {
439
                $query = $this->model->onlyTrashed()->whereIn('id', $ids);
440
                $objects = $query->get();
441
442
                $query->forceDelete();
443
444
                $objects->each(function ($object) {
445
                    $this->afterDelete($object);
446
                });
447
            } catch (\Exception $e) {
448
                Log::error($e);
449
                return false;
450
            }
451
452
            return true;
453
        }, 3);
454
    }
455
456
    /**
457
     * @param mixed $id
458
     * @return mixed
459
     */
460 2
    public function restore($id)
461
    {
462
        return DB::transaction(function () use ($id) {
463 2
            if (($object = $this->model->withTrashed()->find($id)) != null) {
464 1
                $object->restore();
465 1
                $this->afterRestore($object);
466 1
                return true;
467
            }
468
469 1
            return false;
470 2
        }, 3);
471
    }
472
473
    /**
474
     * @param array $ids
475
     * @return mixed
476
     */
477
    public function bulkRestore($ids)
478
    {
479
        return DB::transaction(function () use ($ids) {
480
            try {
481
                $query = $this->model->withTrashed()->whereIn('id', $ids);
482
                $objects = $query->get();
483
484
                $query->restore();
485
486
                $objects->each(function ($object) {
487
                    $this->afterRestore($object);
488
                });
489
            } catch (\Exception $e) {
490
                Log::error($e);
491
                return false;
492
            }
493
494
            return true;
495
        }, 3);
496
    }
497
498
    /**
499
     * @param \A17\Twill\Models\Model $object
500
     * @param array $fields
501
     * @return array
502
     */
503 32
    public function cleanupFields($object, $fields)
504
    {
505 32
        if (property_exists($this->model, 'checkboxes')) {
506 25
            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...
507 25
                if (!$this->shouldIgnoreFieldBeforeSave($field)) {
508 25
                    if (!isset($fields[$field])) {
509 5
                        $fields[$field] = false;
510
                    } else {
511 25
                        $fields[$field] = !empty($fields[$field]);
512
                    }
513
                }
514
            }
515
        }
516
517 32
        if (property_exists($this->model, 'nullable')) {
518
            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...
519
                if (!isset($fields[$field]) && !$this->shouldIgnoreFieldBeforeSave($field)) {
520
                    $fields[$field] = null;
521
                }
522
            }
523
        }
524
525 32
        foreach ($fields as $key => $value) {
526 32
            if (!$this->shouldIgnoreFieldBeforeSave($key)) {
527 32
                if (is_array($value) && empty($value)) {
528 8
                    $fields[$key] = null;
529
                }
530 32
                if ($value === '') {
531
                    $fields[$key] = null;
532
                }
533
            }
534
        }
535
536 32
        return $fields;
537
    }
538
539
    /**
540
     * @param array $fields
541
     * @return array
542
     */
543 26
    public function prepareFieldsBeforeCreate($fields)
544
    {
545 26
        $fields = $this->cleanupFields(null, $fields);
546
547 26
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
548 26
            $fields = $this->$method($fields);
549
        }
550
551 26
        return $fields;
552
    }
553
554
    /**
555
     * @param \A17\Twill\Models\Model $object
556
     * @param array $fields
557
     * @return string[]
558
     */
559 31
    public function prepareFieldsBeforeSave($object, $fields)
560
    {
561 31
        $fields = $this->cleanupFields($object, $fields);
562
563 31
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
564 31
            $fields = $this->$method($object, $fields);
565
        }
566
567 31
        return $fields;
568
    }
569
570
    /**
571
     * @param \A17\Twill\Models\Model $object
572
     * @param array $fields
573
     * @return void
574
     */
575 2
    public function afterUpdateBasic($object, $fields)
576
    {
577 2
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
578
            $this->$method($object, $fields);
579
        }
580 2
    }
581
582
    /**
583
     * @param \A17\Twill\Models\Model $object
584
     * @param array $fields
585
     * @return void
586
     */
587 31
    public function beforeSave($object, $fields)
588
    {
589 31
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
590 21
            $this->$method($object, $fields);
591
        }
592 31
    }
593
594
    /**
595
     * @param \A17\Twill\Models\Model $object
596
     * @param array $fields
597
     * @return void
598
     */
599 31
    public function afterSave($object, $fields)
600
    {
601 31
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
602 31
            $this->$method($object, $fields);
603
        }
604 31
    }
605
606
    /**
607
     * @param \A17\Twill\Models\Model $object
608
     * @return void
609
     */
610 2
    public function afterDelete($object)
611
    {
612 2
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
613 2
            $this->$method($object);
614
        }
615 2
    }
616
617
    /**
618
     * @param \A17\Twill\Models\Model $object
619
     * @return void
620
     */
621 1
    public function afterRestore($object)
622
    {
623 1
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
624 1
            $this->$method($object);
625
        }
626 1
    }
627
628
    /**
629
     * @param \A17\Twill\Models\Model $object
630
     * @param array $fields
631
     * @return \A17\Twill\Models\Model
632
     */
633 3
    public function hydrate($object, $fields)
634
    {
635 3
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
636 3
            $object = $this->$method($object, $fields);
637
        }
638
639 3
        return $object;
640
    }
641
642
    /**
643
     * @param \A17\Twill\Models\Model $object
644
     * @return array
645
     */
646 6
    public function getFormFields($object)
647
    {
648 6
        $fields = $object->attributesToArray();
649
650 6
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
651 6
            $fields = $this->$method($object, $fields);
652
        }
653
654 6
        return $fields;
655
    }
656
657
    /**
658
     * @param \Illuminate\Database\Query\Builder $query
659
     * @param array $scopes
660
     * @return \Illuminate\Database\Query\Builder
661
     */
662 37
    public function filter($query, array $scopes = [])
663
    {
664 37
        $likeOperator = $this->getLikeOperator();
665
666 37
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
667 36
            $this->$method($query, $scopes);
668
        }
669
670 37
        unset($scopes['search']);
671
672 37
        if (isset($scopes['exceptIds'])) {
673 2
            $query->whereNotIn($this->model->getTable() . '.id', $scopes['exceptIds']);
674 2
            unset($scopes['exceptIds']);
675
        }
676
677 37
        foreach ($scopes as $column => $value) {
678 5
            if (method_exists($this->model, 'scope' . ucfirst($column))) {
679 1
                $query->$column();
680
            } else {
681 4
                if (is_array($value)) {
682 2
                    $query->whereIn($column, $value);
683 2
                } elseif ($column[0] == '%') {
684
                    $value && ($value[0] == '!') ? $query->where(substr($column, 1), "not $likeOperator", '%' . substr($value, 1) . '%') : $query->where(substr($column, 1), $likeOperator, '%' . $value . '%');
685 2
                } elseif (isset($value[0]) && $value[0] == '!') {
686
                    $query->where($column, '<>', substr($value, 1));
687 2
                } elseif ($value !== '') {
688 2
                    $query->where($column, $value);
689
                }
690
            }
691
        }
692
693 37
        return $query;
694
    }
695
696
    /**
697
     * @param \Illuminate\Database\Query\Builder $query
698
     * @param array $orders
699
     * @return \Illuminate\Database\Query\Builder
700
     */
701 12
    public function order($query, array $orders = [])
702
    {
703 12
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
704 7
            $this->$method($query, $orders);
705
        }
706
707 12
        foreach ($orders as $column => $direction) {
708 5
            $query->orderBy($column, $direction);
709
        }
710
711 12
        return $query;
712
    }
713
714
    /**
715
     * @param \A17\Twill\Models\Model $object
716
     * @param array $fields
717
     * @param string $relationship
718
     * @param string $formField
719
     * @param string $attribute
720
     * @return void
721
     */
722
    public function updateOneToMany($object, $fields, $relationship, $formField, $attribute)
723
    {
724
        if (isset($fields[$formField])) {
725
            foreach ($fields[$formField] as $id) {
726
                $object->$relationship()->updateOrCreate([$attribute => $id]);
727
            }
728
729
            foreach ($object->$relationship as $relationshipObject) {
730
                if (!in_array($relationshipObject->$attribute, $fields[$formField])) {
731
                    $relationshipObject->delete();
732
                }
733
            }
734
        } else {
735
            $object->$relationship()->delete();
736
        }
737
    }
738
739
    /**
740
     * @param \A17\Twill\Models\Model $object
741
     * @param array $fields
742
     * @param string $relationship
743
     * @return void
744
     */
745
    public function updateMultiSelect($object, $fields, $relationship)
746
    {
747
        $object->$relationship()->sync($fields[$relationship] ?? []);
748
    }
749
750
    /**
751
     * @param \Illuminate\Database\Query\Builder $query
752
     * @param array $scopes
753
     * @param string $scopeField
754
     * @param string $scopeRelation
755
     * @return void
756
     */
757 36
    public function addRelationFilterScope($query, &$scopes, $scopeField, $scopeRelation)
758
    {
759 36
        if (isset($scopes[$scopeField])) {
760
            $id = $scopes[$scopeField];
761
            $query->whereHas($scopeRelation, function ($query) use ($id, $scopeField) {
762
                $query->where($scopeField, $id);
763
            });
764
            unset($scopes[$scopeField]);
765
        }
766 36
    }
767
768
    /**
769
     * @param \Illuminate\Database\Query\Builder $query
770
     * @param array $scopes
771
     * @param string $scopeField
772
     * @return void
773
     */
774
    public function addLikeFilterScope($query, &$scopes, $scopeField)
775
    {
776
        if (isset($scopes[$scopeField]) && is_string($scopes[$scopeField])) {
777
            $query->where($scopeField, $this->getLikeOperator(), '%' . $scopes[$scopeField] . '%');
778
            unset($scopes[$scopeField]);
779
        }
780
    }
781
782
    /**
783
     * @param \Illuminate\Database\Query\Builder $query
784
     * @param array $scopes
785
     * @param string $scopeField
786
     * @param string[] $orFields
787
     */
788 5
    public function searchIn($query, &$scopes, $scopeField, $orFields = [])
789
    {
790
791 5
        if (isset($scopes[$scopeField]) && is_string($scopes[$scopeField])) {
792
            $query->where(function ($query) use (&$scopes, $scopeField, $orFields) {
793 2
                foreach ($orFields as $field) {
794 2
                    $query->orWhere($field, $this->getLikeOperator(), '%' . $scopes[$scopeField] . '%');
795 2
                    unset($scopes[$field]);
796
                }
797 2
            });
798
        }
799 5
    }
800
801
    /**
802
     * @return bool
803
     */
804 2
    public function isUniqueFeature()
805
    {
806 2
        return false;
807
    }
808
809
    /**
810
     * @param array $ignore
811
     * @return void
812
     */
813
    public function addIgnoreFieldsBeforeSave($ignore = [])
814
    {
815
        $this->ignoreFieldsBeforeSave = is_array($ignore)
0 ignored issues
show
introduced by
The condition is_array($ignore) is always true.
Loading history...
816
        ? array_merge($this->ignoreFieldsBeforeSave, $ignore)
817
        : array_merge($this->ignoreFieldsBeforeSave, [$ignore]);
818
    }
819
820
    /**
821
     * @param string $ignore
822
     * @return bool
823
     */
824 32
    public function shouldIgnoreFieldBeforeSave($ignore)
825
    {
826 32
        return in_array($ignore, $this->ignoreFieldsBeforeSave);
827
    }
828
829
    /**
830
     * @return string[]
831
     */
832 32
    public function getReservedFields()
833
    {
834
        return [
835 32
            'medias',
836
            'browsers',
837
            'repeaters',
838
            'blocks',
839
        ];
840
    }
841
842
    /**
843
     * @param string $relation
844
     * @param \A17\Twill\Models\Model|null $model
845
     * @return mixed
846
     */
847
    protected function getModelRepository($relation, $model = null)
848
    {
849
        if (!$model) {
850
            if (class_exists($relation) && (new $relation) instanceof Model) {
851
                $model = Str::afterLast($relation, '\\');
852
            } else {
853
                $morphedModel = Relation::getMorphedModel($relation);
854
                if (class_exists($morphedModel) && (new $morphedModel) instanceof Model) {
855
                    $model = (new \ReflectionClass($morphedModel))->getShortName();
856
                } else {
857
                    $model = ucfirst(Str::singular($relation));
858
                }
859
            }
860
        }
861
862
        return App::make(Config::get('twill.namespace') . "\\Repositories\\" . ucfirst($model) . "Repository");
863
    }
864
865
    /**
866
     * @param string|null $method
867
     * @return array
868
     */
869 46
    protected function traitsMethods(string $method = null)
870
    {
871 46
        $method = $method ?? debug_backtrace()[1]['function'];
872
873 46
        $traits = array_values(class_uses_recursive(get_called_class()));
874
875 46
        $uniqueTraits = array_unique(array_map('class_basename', $traits));
876
877
        $methods = array_map(function (string $trait) use ($method) {
878 46
            return $method . $trait;
879 46
        }, $uniqueTraits);
880
881
        return array_filter($methods, function (string $method) {
882 46
            return method_exists(get_called_class(), $method);
883 46
        });
884
    }
885
886
    /**
887
     * @return string
888
     */
889 37
    private function getLikeOperator()
890
    {
891 37
        if (DB::connection()->getPDO()->getAttribute(PDO::ATTR_DRIVER_NAME) === 'pgsql') {
892
            return 'ILIKE';
893
        }
894
895 37
        return 'LIKE';
896
    }
897
898
    /**
899
     * @param string $method
900
     * @param array $parameters
901
     * @return mixed
902
     */
903 31
    public function __call($method, $parameters)
904
    {
905 31
        return $this->model->$method(...$parameters);
906
    }
907
908
    /**
909
     * @param string $behavior
910
     * @return boolean
911
     */
912 35
    public function hasBehavior($behavior)
913
    {
914 35
        $hasBehavior = classHasTrait($this, 'A17\Twill\Repositories\Behaviors\Handle' . ucfirst($behavior));
915
916 35
        if (Str::startsWith($behavior, 'translation')) {
917 32
            $hasBehavior = $hasBehavior && $this->model->isTranslatable();
918
        }
919
920 35
        return $hasBehavior;
921
    }
922
923
    /**
924
     * @return boolean
925
     */
926 11
    public function isTranslatable($column)
927
    {
928 11
        return $this->model->isTranslatable($column);
929
    }
930
}
931