Passed
Push — dependabot/npm_and_yarn/docs/w... ( a770a9...3a5b31 )
by
unknown
07:47
created

ModuleRepository::getCountByStatusSlug()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7.0145

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 14
c 1
b 0
f 0
nc 7
nop 2
dl 0
loc 22
ccs 14
cts 15
cp 0.9333
crap 7.0145
rs 8.8333
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 33
    public function getCountByStatusSlug($slug, $scope = [])
76
    {
77 33
        $this->countScope = $scope;
78
79 33
        switch ($slug) {
80 33
            case 'all':
81 32
                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 32
    public function getCountForAll()
103
    {
104 32
        $query = $this->model->newQuery();
105 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

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 18
    public function getById($id, $with = [], $withCount = [])
143
    {
144 18
        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 1
    public function cmsSearch($search, $fields = [])
180
    {
181 1
        $query = $this->model->latest();
182
183 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...
184
185 1
        foreach ($fields as $field) {
186 1
            if (in_array($field, $translatedAttributes)) {
187
                $query->orWhereHas('translations', function ($q) use ($field, $search) {
188 1
                    $q->where($field, $this->getLikeOperator(), "%{$search}%");
189 1
                });
190
            } else {
191
                $query->orWhere($field, $this->getLikeOperator(), "%{$search}%");
192
            }
193
        }
194
195 1
        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 31
    public function create($fields)
213
    {
214
        return DB::transaction(function () use ($fields) {
215 31
            $original_fields = $fields;
216
217 31
            $fields = $this->prepareFieldsBeforeCreate($fields);
218
219 31
            $object = $this->model->create(Arr::except($fields, $this->getReservedFields()));
220
221 31
            $this->beforeSave($object, $original_fields);
222
223 31
            $fields = $this->prepareFieldsBeforeSave($object, $fields);
224
225 31
            $object->save();
226
227 31
            $this->afterSave($object, $fields);
228
229 31
            return $object;
230 31
        }, 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 12
    public function update($id, $fields)
268
    {
269
        DB::transaction(function () use ($id, $fields) {
270 12
            $object = $this->model->findOrFail($id);
271
272 12
            $this->beforeSave($object, $fields);
273
274 12
            $fields = $this->prepareFieldsBeforeSave($object, $fields);
275
276 12
            $object->fill(Arr::except($fields, $this->getReservedFields()));
277
278 12
            $object->save();
279
280 12
            $this->afterSave($object, $fields);
281 12
        }, 3);
282 12
    }
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
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

358
        $revisionInput = json_decode(/** @scrutinizer ignore-type */ $revision->payload, true);
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 21
    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 21
                });
403
            } catch (\Exception $e) {
404
                Log::error($e);
405
                return false;
406
            }
407
408 21
            return true;
409 21
        }, 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 32
    public function cleanupFields($object, $fields)
502
    {
503 32
        if (property_exists($this->model, 'checkboxes')) {
504 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...
505 25
                if (!$this->shouldIgnoreFieldBeforeSave($field)) {
506 25
                    if (!isset($fields[$field])) {
507 5
                        $fields[$field] = false;
508
                    } else {
509 25
                        $fields[$field] = !empty($fields[$field]);
510
                    }
511
                }
512
            }
513
        }
514
515 32
        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 32
        foreach ($fields as $key => $value) {
524 32
            if (!$this->shouldIgnoreFieldBeforeSave($key)) {
525 32
                if (is_array($value) && empty($value)) {
526 8
                    $fields[$key] = null;
527
                }
528 32
                if ($value === '') {
529
                    $fields[$key] = null;
530
                }
531
            }
532
        }
533
534 32
        return $fields;
535
    }
536
537
    /**
538
     * @param array $fields
539
     * @return array
540
     */
541 26
    public function prepareFieldsBeforeCreate($fields)
542
    {
543 26
        $fields = $this->cleanupFields(null, $fields);
544
545 26
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
546 26
            $fields = $this->$method($fields);
547
        }
548
549 26
        return $fields;
550
    }
551
552
    /**
553
     * @param \A17\Twill\Models\Model $object
554
     * @param array $fields
555
     * @return string[]
556
     */
557 31
    public function prepareFieldsBeforeSave($object, $fields)
558
    {
559 31
        $fields = $this->cleanupFields($object, $fields);
560
561 31
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
562 31
            $fields = $this->$method($object, $fields);
563
        }
564
565 31
        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 31
    public function beforeSave($object, $fields)
586
    {
587 31
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
588 21
            $this->$method($object, $fields);
589
        }
590 31
    }
591
592
    /**
593
     * @param \A17\Twill\Models\Model $object
594
     * @param array $fields
595
     * @return void
596
     */
597 31
    public function afterSave($object, $fields)
598
    {
599 31
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
600 31
            $this->$method($object, $fields);
601
        }
602 31
    }
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 6
    public function getFormFields($object)
645
    {
646 6
        $fields = $object->attributesToArray();
647
648 6
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
649 6
            $fields = $this->$method($object, $fields);
650
        }
651
652 6
        return $fields;
653
    }
654
655
    /**
656
     * @param \Illuminate\Database\Query\Builder $query
657
     * @param array $scopes
658
     * @return \Illuminate\Database\Query\Builder
659
     */
660 37
    public function filter($query, array $scopes = [])
661
    {
662 37
        $likeOperator = $this->getLikeOperator();
663
664 37
        foreach ($this->traitsMethods(__FUNCTION__) as $method) {
665 36
            $this->$method($query, $scopes);
666
        }
667
668 37
        unset($scopes['search']);
669
670 37
        if (isset($scopes['exceptIds'])) {
671 2
            $query->whereNotIn($this->model->getTable() . '.id', $scopes['exceptIds']);
672 2
            unset($scopes['exceptIds']);
673
        }
674
675 37
        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 37
        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 36
    public function addRelationFilterScope($query, &$scopes, $scopeField, $scopeRelation)
756
    {
757 36
        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 36
    }
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 32
    public function shouldIgnoreFieldBeforeSave($ignore)
823
    {
824 32
        return in_array($ignore, $this->ignoreFieldsBeforeSave);
825
    }
826
827
    /**
828
     * @return string[]
829
     */
830 32
    public function getReservedFields()
831
    {
832
        return [
833 32
            '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 46
    protected function traitsMethods(string $method = null)
863
    {
864 46
        $method = $method ?? debug_backtrace()[1]['function'];
865
866 46
        $traits = array_values(class_uses_recursive(get_called_class()));
867
868 46
        $uniqueTraits = array_unique(array_map('class_basename', $traits));
869
870
        $methods = array_map(function (string $trait) use ($method) {
871 46
            return $method . $trait;
872 46
        }, $uniqueTraits);
873
874
        return array_filter($methods, function (string $method) {
875 46
            return method_exists(get_called_class(), $method);
876 46
        });
877
    }
878
879
    /**
880
     * @return string
881
     */
882 37
    private function getLikeOperator()
883
    {
884 37
        if (DB::connection()->getPDO()->getAttribute(PDO::ATTR_DRIVER_NAME) === 'pgsql') {
885
            return 'ILIKE';
886
        }
887
888 37
        return 'LIKE';
889
    }
890
891
    /**
892
     * @param string $method
893
     * @param array $parameters
894
     * @return mixed
895
     */
896 31
    public function __call($method, $parameters)
897
    {
898 31
        return $this->model->$method(...$parameters);
899
    }
900
901
    /**
902
     * @param string $behavior
903
     * @return boolean
904
     */
905 35
    public function hasBehavior($behavior)
906
    {
907 35
        $hasBehavior = classHasTrait($this, 'A17\Twill\Repositories\Behaviors\Handle' . ucfirst($behavior));
908
909 35
        if (Str::startsWith($behavior, 'translation')) {
910 32
            $hasBehavior = $hasBehavior && $this->model->isTranslatable();
911
        }
912
913 35
        return $hasBehavior;
914
    }
915
916
    /**
917
     * @return boolean
918
     */
919 11
    public function isTranslatable($column)
920
    {
921 11
        return $this->model->isTranslatable($column);
922
    }
923
}
924