Passed
Push — master ( 4c841c...172093 )
by Darko
03:36
created

Category   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 519
Duplicated Lines 0 %

Importance

Changes 7
Bugs 2 Features 0
Metric Value
wmc 44
eloc 225
c 7
b 2
f 0
dl 0
loc 519
rs 8.8798

19 Methods

Rating   Name   Duplication   Size   Complexity  
A releases() 0 3 1
A parent() 0 3 1
A getRecentlyAdded() 0 20 2
A getNameByID() 0 5 2
A getIdByName() 0 5 2
A getDisabledIDs() 0 5 1
A getEnabledParentNames() 0 3 1
A getChildren() 0 12 2
A isParent() 0 5 1
A getByIds() 0 16 3
A getForSelect() 0 13 3
A getFlat() 0 3 1
A getCategories() 0 16 3
A getForApi() 0 13 2
A getCategoryValue() 0 3 1
A updateCategory() 0 9 1
A getForMenu() 0 17 4
C getCategorySearch() 0 40 12
A getCategoryOthersGroup() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like Category often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Category, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace App\Models;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Database\Eloquent\Relations\BelongsTo;
7
use Illuminate\Database\Eloquent\Relations\HasMany;
8
use Illuminate\Support\Facades\Cache;
9
use Illuminate\Support\Facades\DB;
10
11
/**
12
 * App\Models\Category.
13
 *
14
 * @property int $id
15
 * @property string $title
16
 * @property int|null $parentid
17
 * @property int $status
18
 * @property string|null $description
19
 * @property bool $disablepreview
20
 * @property int $minsizetoformrelease
21
 * @property int $maxsizetoformrelease
22
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Category[] $children
23
 * @property-read Category|null $parent
24
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Release[] $releases
25
 *
26
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereDescription($value)
27
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereDisablepreview($value)
28
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereId($value)
29
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereMaxsizetoformrelease($value)
30
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereMinsizetoformrelease($value)
31
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereParentid($value)
32
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereStatus($value)
33
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereTitle($value)
34
 *
35
 * @mixin \Eloquent
36
 *
37
 * @property int|null $root_categories_id
38
 *
39
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category newModelQuery()
40
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category newQuery()
41
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category query()
42
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereRootCategoriesId($value)
43
 */
44
class Category extends Model
45
{
46
    /**
47
     * Category constants.
48
     * Do NOT use the values, as they may change, always use the constant - that's what it's for.
49
     */
50
    public const OTHER_MISC = 10;
51
52
    public const OTHER_HASHED = 20;
53
54
    public const GAME_NDS = 1010;
55
56
    public const GAME_PSP = 1020;
57
58
    public const GAME_WII = 1030;
59
60
    public const GAME_XBOX = 1040;
61
62
    public const GAME_XBOX360 = 1050;
63
64
    public const GAME_WIIWARE = 1060;
65
66
    public const GAME_XBOX360DLC = 1070;
67
68
    public const GAME_PS3 = 1080;
69
70
    public const GAME_OTHER = 1999;
71
72
    public const GAME_3DS = 1110;
73
74
    public const GAME_PSVITA = 1120;
75
76
    public const GAME_WIIU = 1130;
77
78
    public const GAME_XBOXONE = 1140;
79
80
    public const GAME_PS4 = 1180;
81
82
    public const MOVIE_FOREIGN = 2010;
83
84
    public const MOVIE_OTHER = 2999;
85
86
    public const MOVIE_SD = 2030;
87
88
    public const MOVIE_HD = 2040;
89
90
    public const MOVIE_UHD = 2045;
91
92
    public const MOVIE_3D = 2050;
93
94
    public const MOVIE_BLURAY = 2060;
95
96
    public const MOVIE_DVD = 2070;
97
98
    public const MOVIE_WEBDL = 2080;
99
100
    public const MOVIE_X265 = 2090;
101
102
    public const MUSIC_MP3 = 3010;
103
104
    public const MUSIC_VIDEO = 3020;
105
106
    public const MUSIC_AUDIOBOOK = 3030;
107
108
    public const MUSIC_LOSSLESS = 3040;
109
110
    public const MUSIC_PODCAST = 3050;
111
112
    public const MUSIC_OTHER = 3999;
113
114
    public const MUSIC_FOREIGN = 3060;
115
116
    public const PC_0DAY = 4010;
117
118
    public const PC_ISO = 4020;
119
120
    public const PC_MAC = 4030;
121
122
    public const PC_PHONE_OTHER = 4040;
123
124
    public const PC_GAMES = 4050;
125
126
    public const PC_PHONE_IOS = 4060;
127
128
    public const PC_PHONE_ANDROID = 4070;
129
130
    public const TV_WEBDL = 5010;
131
132
    public const TV_FOREIGN = 5020;
133
134
    public const TV_SD = 5030;
135
136
    public const TV_HD = 5040;
137
138
    public const TV_UHD = 5045;
139
140
    public const TV_OTHER = 5999;
141
142
    public const TV_SPORT = 5060;
143
144
    public const TV_ANIME = 5070;
145
146
    public const TV_DOCU = 5080;
147
148
    public const TV_X265 = 5090;
149
150
    public const XXX_DVD = 6010;
151
152
    public const XXX_WMV = 6020;
153
154
    public const XXX_XVID = 6030;
155
156
    public const XXX_X264 = 6040;
157
158
    public const XXX_CLIPHD = 6041;
159
160
    public const XXX_CLIPSD = 6042;
161
162
    public const XXX_UHD = 6045;
163
164
    public const XXX_VR = 6046;
165
166
    public const XXX_PACK = 6050;
167
168
    public const XXX_IMAGESET = 6060;
169
170
    public const XXX_OTHER = 6999;
171
172
    public const XXX_SD = 6080;
173
174
    public const XXX_WEBDL = 6090;
175
176
    public const BOOKS_MAGAZINES = 7010;
177
178
    public const BOOKS_EBOOK = 7020;
179
180
    public const BOOKS_COMICS = 7030;
181
182
    public const BOOKS_TECHNICAL = 7040;
183
184
    public const BOOKS_FOREIGN = 7060;
185
186
    public const BOOKS_UNKNOWN = 7999;
187
188
    public const OTHER_ROOT = 1;
189
190
    public const GAME_ROOT = 1000;
191
192
    public const MOVIE_ROOT = 2000;
193
194
    public const MUSIC_ROOT = 3000;
195
196
    public const PC_ROOT = 4000;
197
198
    public const TV_ROOT = 5000;
199
200
    public const XXX_ROOT = 6000;
201
202
    public const BOOKS_ROOT = 7000;
203
204
    public const STATUS_INACTIVE = 0;
205
206
    public const STATUS_ACTIVE = 1;
207
208
    public const STATUS_DISABLED = 2;
209
210
    public const OTHERS_GROUP =
211
        [
212
            self::BOOKS_UNKNOWN,
213
            self::GAME_OTHER,
214
            self::MOVIE_OTHER,
215
            self::MUSIC_OTHER,
216
            self::PC_PHONE_OTHER,
217
            self::TV_OTHER,
218
            self::OTHER_HASHED,
219
            self::XXX_OTHER,
220
            self::OTHER_MISC,
221
        ];
222
223
    public const MOVIES_GROUP =
224
        [
225
            self::MOVIE_FOREIGN,
226
            self::MOVIE_ROOT,
227
            self::MOVIE_OTHER,
228
            self::MOVIE_SD,
229
            self::MOVIE_HD,
230
            self::MOVIE_UHD,
231
            self::MOVIE_3D,
232
            self::MOVIE_BLURAY,
233
            self::MOVIE_DVD,
234
            self::MOVIE_WEBDL,
235
            self::MOVIE_X265,
236
        ];
237
238
    public const TV_GROUP =
239
        [
240
            self::TV_FOREIGN,
241
            self::TV_ROOT,
242
            self::TV_OTHER,
243
            self::TV_SD,
244
            self::TV_HD,
245
            self::TV_UHD,
246
            self::TV_ANIME,
247
            self::TV_DOCU,
248
            self::TV_SPORT,
249
            self::TV_WEBDL,
250
            self::TV_X265,
251
        ];
252
253
    /**
254
     * @var string
255
     */
256
257
    /**
258
     * @var bool
259
     */
260
    public $timestamps = false;
261
262
    /**
263
     * @var bool
264
     */
265
    protected $dateFormat = false;
266
267
    /**
268
     * @var array
269
     */
270
    protected $guarded = [];
271
272
    public function releases(): HasMany
273
    {
274
        return $this->hasMany(Release::class, 'categories_id');
275
    }
276
277
    public function parent(): BelongsTo
278
    {
279
        return $this->belongsTo(RootCategory::class, 'root_categories_id');
280
    }
281
282
    /**
283
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[]
284
     */
285
    public static function getRecentlyAdded()
286
    {
287
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_long'));
288
        $result = Cache::get(md5('RecentlyAdded'));
289
        if ($result !== null) {
290
            return $result;
291
        }
292
293
        $result = self::query()
294
            ->with('parent')
295
            ->where('r.adddate', '>', now()->subWeek())
296
            ->select(['root_categories_id', DB::raw('COUNT(r.id) as count'), 'title'])
297
            ->join('releases as r', 'r.categories_id', '=', 'categories.id')
298
            ->groupBy('title')
299
            ->orderByDesc('count')
0 ignored issues
show
Bug introduced by
'count' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderByDesc(). ( Ignorable by Annotation )

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

299
            ->orderByDesc(/** @scrutinizer ignore-type */ 'count')
Loading history...
300
            ->get();
301
302
        Cache::put(md5('RecentlyAdded'), $result, $expiresAt);
303
304
        return $result;
305
    }
306
307
    public static function getCategorySearch(array $cat = [], ?string $searchType = null): string
308
    {
309
        $categories = [];
310
311
        // if searchType is tv return TV categories
312
        if ($searchType === 'tv') {
313
            $cat = self::TV_GROUP;
314
        }
315
316
        // is searchType is movies return MOVIES categories
317
        if ($searchType === 'movies') {
318
            $cat = self::MOVIES_GROUP;
319
        }
320
321
        // If multiple categories were sent in a single array position, slice and add them
322
        if (str_contains($cat[0], ',')) {
323
            $tmpcats = explode(',', $cat[0]);
324
            // Reset the category to the first comma separated value in the string
325
            $cat[0] = $tmpcats[0];
326
            // Add the remaining categories in the string to the original array
327
            foreach (array_slice($tmpcats, 1) as $tmpcat) {
328
                $cat[] = $tmpcat;
329
            }
330
        }
331
332
        foreach ($cat as $category) {
333
            if (is_numeric($category) && $category !== -1 && self::isParent($category)) {
334
                $children = RootCategory::find($category)->categories->pluck('id')->toArray();
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist on Illuminate\Database\Eloq...gHasThroughRelationship.
Loading history...
335
                $categories = array_merge($categories, $children);
336
            } elseif (is_numeric($category) && $category > 0) {
337
                $categories[] = $category;
338
            }
339
        }
340
341
        $catCount = count($categories);
342
343
        return match ($catCount) {
344
            0 => 'AND 1=1',
345
            1 => $categories[0] !== -1 ? ' AND r.categories_id = '.$categories[0] : '',
346
            default => ' AND r.categories_id IN ('.implode(', ', $categories).') ',
347
        };
348
    }
349
350
    /**
351
     * Returns a concatenated list of other categories.
352
     */
353
    public static function getCategoryOthersGroup(): string
354
    {
355
        return implode(
356
            ',',
357
            self::OTHERS_GROUP
358
        );
359
    }
360
361
    /**
362
     * @return mixed
363
     */
364
    public static function getCategoryValue($category)
365
    {
366
        return \constant('self::'.$category);
367
    }
368
369
    /**
370
     * Check if category is parent.
371
     */
372
    public static function isParent($cid): bool
373
    {
374
        $ret = RootCategory::query()->where(['id' => $cid])->first();
375
376
        return $ret !== null;
377
    }
378
379
    /**
380
     * @return \Illuminate\Database\Eloquent\Collection|static[]
381
     */
382
    public static function getFlat()
383
    {
384
        return self::query()->get();
385
    }
386
387
    /**
388
     * Get children of a parent category.
389
     *
390
     *
391
     * @return mixed
392
     */
393
    public static function getChildren($categoryId)
394
    {
395
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_long'));
396
        $result = Cache::get(md5($categoryId));
397
        if ($result !== null) {
398
            return $result;
399
        }
400
401
        $result = RootCategory::find($categoryId)->categories;
0 ignored issues
show
Bug introduced by
The property categories does not seem to exist on Illuminate\Database\Eloq...gHasThroughRelationship.
Loading history...
402
        Cache::put(md5($categoryId), $result, $expiresAt);
403
404
        return $result;
405
    }
406
407
    /**
408
     * Get names of enabled parent categories.
409
     *
410
     * @return \Illuminate\Database\Eloquent\Collection|static[]
411
     */
412
    public static function getEnabledParentNames()
413
    {
414
        return RootCategory::query()->where('status', '=', 1)->get(['title']);
415
    }
416
417
    /**
418
     * Returns category ID's for site disabled categories.
419
     *
420
     *
421
     * @return \Illuminate\Database\Eloquent\Collection|static[]
422
     */
423
    public static function getDisabledIDs()
424
    {
425
        return self::query()
426
            ->where('status', '=', 2)
427
            ->get(['id']);
428
    }
429
430
    /**
431
     * Get multiple categories.
432
     *
433
     * @return bool|\Illuminate\Database\Eloquent\Collection|static[]
434
     */
435
    public static function getByIds($ids)
436
    {
437
        if (\count($ids) > 0) {
438
            $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_long'));
439
            $result = Cache::get(md5(implode(',', $ids)));
440
            if ($result !== null) {
441
                return $result;
442
            }
443
            $result = self::query()->whereIn('id', $ids)->get();
444
445
            Cache::put(md5(md5(implode(',', $ids))), $result, $expiresAt);
446
447
            return $result;
448
        }
449
450
        return false;
451
    }
452
453
    /**
454
     * Return the parent and category name from the supplied categoryID.
455
     */
456
    public static function getNameByID($categoryId): string
457
    {
458
        $cat = self::query()->where('id', $categoryId)->first();
459
460
        return $cat !== null ? $cat->parent->title.' -> '.$cat->title : '';
461
    }
462
463
    /**
464
     * @return bool|mixed
465
     */
466
    public static function getIdByName($title, $parent)
467
    {
468
        $cat = self::query()->where('title', $title)->with('parent.'.$parent)->first(['id']);
469
470
        return $cat !== null ? $cat->id : false;
471
    }
472
473
    /**
474
     * Update a category.
475
     */
476
    public static function updateCategory($id, $status, $desc, $disablepreview, $minsize, $maxsize): int
477
    {
478
        return self::query()->where('id', $id)->update(
479
            [
480
                'disablepreview' => $disablepreview,
481
                'status' => $status,
482
                'minsizetoformrelease' => $minsize,
483
                'maxsizetoformrelease' => $maxsize,
484
                'description' => $desc,
485
            ]
486
        );
487
    }
488
489
    public static function getForMenu(array $excludedCats = []): array
490
    {
491
        $categoriesResult = [];
492
        $categoriesArray = RootCategory::query()->with(['categories' => function ($query) use ($excludedCats) {
493
            if (! empty($excludedCats)) {
494
                $query->whereNotIn('id', $excludedCats);
495
            }
496
            $query->select(['id', 'title', 'root_categories_id', 'description']);
497
        }])->select(['id', 'title'])->get()->toArray();
498
499
        foreach ($categoriesArray as $category) {
500
            if (! empty($category['categories'])) {
501
                $categoriesResult[] = $category;
502
            }
503
        }
504
505
        return $categoriesResult;
506
    }
507
508
    /**
509
     * @return mixed
510
     */
511
    public static function getForApi()
512
    {
513
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_long'));
514
        $result = Cache::get(md5('ForApi'));
515
        if ($result !== null) {
516
            return $result;
517
        }
518
519
        $result = RootCategory::query()->select(['id', 'title'])->where('status', '=', self::STATUS_ACTIVE)->get();
520
521
        Cache::put(md5('ForApi'), $result, $expiresAt);
522
523
        return $result;
524
    }
525
526
    /**
527
     * Return a list of categories for use in a dropdown.
528
     */
529
    public static function getForSelect(bool $blnIncludeNoneSelected = true): array
530
    {
531
        $categories = self::getCategories();
532
        $temp_array = [];
533
534
        if ($blnIncludeNoneSelected) {
535
            $temp_array[-1] = '--Please Select--';
536
        }
537
        foreach ($categories as $category) {
538
            $temp_array[$category->id] = $category->parent->title.' > '.$category->title;
539
        }
540
541
        return $temp_array;
542
    }
543
544
    /**
545
     * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
546
     */
547
    public static function getCategories(bool $activeOnly = false, array $excludedCats = []): \Illuminate\Database\Eloquent\Collection|array
548
    {
549
        $sql = self::query()
550
            ->with('parent')
551
            ->select(['id', 'status', 'title', 'root_categories_id'])
552
            ->orderBy('id');
0 ignored issues
show
Bug introduced by
'id' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy(). ( Ignorable by Annotation )

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

552
            ->orderBy(/** @scrutinizer ignore-type */ 'id');
Loading history...
553
554
        if ($activeOnly) {
555
            $sql->where('status', '=', self::STATUS_ACTIVE);
556
        }
557
558
        if (! empty($excludedCats)) {
559
            $sql->whereNotIn('id', $excludedCats);
560
        }
561
562
        return $sql->get();
563
    }
564
}
565