Passed
Push — master ( 5d0f2f...49b4e9 )
by Darko
10:54
created

RolePromotionStat   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 10
eloc 48
c 1
b 0
f 0
dl 0
loc 132
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getPromotionSummary() 0 11 1
A recordPromotion() 0 16 1
A getUserSummary() 0 15 1
A role() 0 3 1
A scopeAppliedBetween() 0 3 1
A scopeForPromotion() 0 3 1
A scopeForUser() 0 3 1
A user() 0 3 1
A scopeForRole() 0 3 1
A promotion() 0 3 1
1
<?php
2
3
namespace App\Models;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Database\Eloquent\Relations\BelongsTo;
7
8
/**
9
 * App\Models\RolePromotionStat
10
 *
11
 * @property int $id
12
 * @property int $user_id
13
 * @property int $role_promotion_id
14
 * @property int $role_id
15
 * @property int $days_added
16
 * @property \Carbon\Carbon|null $previous_expiry_date
17
 * @property \Carbon\Carbon|null $new_expiry_date
18
 * @property \Carbon\Carbon $applied_at
19
 * @property \Carbon\Carbon|null $created_at
20
 * @property \Carbon\Carbon|null $updated_at
21
 * @property-read \App\Models\User $user
22
 * @property-read \App\Models\RolePromotion $promotion
23
 * @property-read \Spatie\Permission\Models\Role $role
24
 */
25
class RolePromotionStat extends Model
26
{
27
    protected $fillable = [
28
        'user_id',
29
        'role_promotion_id',
30
        'role_id',
31
        'days_added',
32
        'previous_expiry_date',
33
        'new_expiry_date',
34
        'applied_at',
35
    ];
36
37
    protected $casts = [
38
        'days_added' => 'integer',
39
        'previous_expiry_date' => 'datetime',
40
        'new_expiry_date' => 'datetime',
41
        'applied_at' => 'datetime',
42
    ];
43
44
    /**
45
     * Get the user that received the promotion
46
     */
47
    public function user(): BelongsTo
48
    {
49
        return $this->belongsTo(User::class);
50
    }
51
52
    /**
53
     * Get the promotion that was applied
54
     */
55
    public function promotion(): BelongsTo
56
    {
57
        return $this->belongsTo(RolePromotion::class, 'role_promotion_id');
58
    }
59
60
    /**
61
     * Get the role that was upgraded
62
     */
63
    public function role(): BelongsTo
64
    {
65
        return $this->belongsTo(\Spatie\Permission\Models\Role::class);
66
    }
67
68
    /**
69
     * Scope to get stats for a specific promotion
70
     */
71
    public function scopeForPromotion($query, int $promotionId)
72
    {
73
        return $query->where('role_promotion_id', $promotionId);
74
    }
75
76
    /**
77
     * Scope to get stats for a specific user
78
     */
79
    public function scopeForUser($query, int $userId)
80
    {
81
        return $query->where('user_id', $userId);
82
    }
83
84
    /**
85
     * Scope to get stats for a specific role
86
     */
87
    public function scopeForRole($query, int $roleId)
88
    {
89
        return $query->where('role_id', $roleId);
90
    }
91
92
    /**
93
     * Scope to get stats within a date range
94
     */
95
    public function scopeAppliedBetween($query, $startDate, $endDate)
96
    {
97
        return $query->whereBetween('applied_at', [$startDate, $endDate]);
98
    }
99
100
    /**
101
     * Get statistics summary for a promotion
102
     */
103
    public static function getPromotionSummary(int $promotionId): array
104
    {
105
        $stats = static::forPromotion($promotionId)->get();
106
107
        return [
108
            'total_upgrades' => $stats->count(),
109
            'total_days_added' => $stats->sum('days_added'),
110
            'unique_users' => $stats->unique('user_id')->count(),
111
            'roles_affected' => $stats->unique('role_id')->count(),
112
            'latest_application' => $stats->max('applied_at'),
113
            'earliest_application' => $stats->min('applied_at'),
114
        ];
115
    }
116
117
    /**
118
     * Get statistics summary for a user
119
     */
120
    public static function getUserSummary(int $userId): array
121
    {
122
        $stats = static::forUser($userId)->get();
123
124
        return [
125
            'total_promotions_received' => $stats->count(),
126
            'total_days_added' => $stats->sum('days_added'),
127
            'promotions' => $stats->groupBy('role_promotion_id')->map(function ($group) {
128
                return [
129
                    'promotion_id' => $group->first()->role_promotion_id,
130
                    'promotion_name' => $group->first()->promotion?->name,
131
                    'times_applied' => $group->count(),
132
                    'total_days' => $group->sum('days_added'),
133
                ];
134
            })->values()->all(),
135
        ];
136
    }
137
138
    /**
139
     * Record a promotion application
140
     */
141
    public static function recordPromotion(
142
        int $userId,
143
        int $promotionId,
144
        int $roleId,
145
        int $daysAdded,
146
        ?\Carbon\Carbon $previousExpiryDate = null,
147
        ?\Carbon\Carbon $newExpiryDate = null
148
    ): self {
149
        return static::create([
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::create(ar...'applied_at' => now())) could return the type Illuminate\Database\Eloq...gHasThroughRelationship which is incompatible with the type-hinted return App\Models\RolePromotionStat. Consider adding an additional type-check to rule them out.
Loading history...
150
            'user_id' => $userId,
151
            'role_promotion_id' => $promotionId,
152
            'role_id' => $roleId,
153
            'days_added' => $daysAdded,
154
            'previous_expiry_date' => $previousExpiryDate,
155
            'new_expiry_date' => $newExpiryDate,
156
            'applied_at' => now(),
157
        ]);
158
    }
159
}
160
161