Files
newznab-tmux-NNTmux/app/Models/RolePromotionStat.php
T
2026-03-11 10:11:30 +01:00

172 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Spatie\Permission\Models\Role;
/**
* App\Models\RolePromotionStat
*
* @property int $id
* @property int $user_id
* @property int $role_promotion_id
* @property int $role_id
* @property int $days_added
* @property Carbon|null $previous_expiry_date
* @property Carbon|null $new_expiry_date
* @property Carbon $applied_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property-read User $user
* @property-read RolePromotion $promotion
* @property-read Role $role
*/
class RolePromotionStat extends Model
{
protected $fillable = [
'user_id',
'role_promotion_id',
'role_id',
'days_added',
'previous_expiry_date',
'new_expiry_date',
'applied_at',
];
protected $casts = [
'days_added' => 'integer',
'previous_expiry_date' => 'datetime',
'new_expiry_date' => 'datetime',
'applied_at' => 'datetime',
];
/**
* Get the user that received the promotion
*
* @return BelongsTo<User, $this>
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the promotion that was applied
*
* @return BelongsTo<RolePromotion, $this>
*/
public function promotion(): BelongsTo
{
return $this->belongsTo(RolePromotion::class, 'role_promotion_id');
}
/**
* Get the role that was upgraded
*/
public function role(): BelongsTo // @phpstan-ignore missingType.generics
{
return $this->belongsTo(Role::class);
}
/**
* Scope to get stats for a specific promotion
*/
public function scopeForPromotion(mixed $query, int $promotionId): mixed
{
return $query->where('role_promotion_id', $promotionId);
}
/**
* Scope to get stats for a specific user
*/
public function scopeForUser(mixed $query, int $userId): mixed
{
return $query->where('user_id', $userId);
}
/**
* Scope to get stats for a specific role
*/
public function scopeForRole(mixed $query, int $roleId): mixed
{
return $query->where('role_id', $roleId);
}
/**
* Scope to get stats within a date range
*/
public function scopeAppliedBetween(mixed $query, mixed $startDate, mixed $endDate): mixed
{
return $query->whereBetween('applied_at', [$startDate, $endDate]);
}
/**
* Get statistics summary for a promotion
*
* @return array<string, mixed>
*/
public static function getPromotionSummary(int $promotionId): array
{
$stats = static::forPromotion($promotionId)->get();
return [
'total_upgrades' => $stats->count(),
'total_days_added' => $stats->sum('days_added'),
'unique_users' => $stats->unique('user_id')->count(),
'roles_affected' => $stats->unique('role_id')->count(),
'latest_application' => $stats->max('applied_at'),
'earliest_application' => $stats->min('applied_at'),
];
}
/**
* Get statistics summary for a user
*
* @return array<string, mixed>
*/
public static function getUserSummary(int $userId): array
{
$stats = static::forUser($userId)->get();
return [
'total_promotions_received' => $stats->count(),
'total_days_added' => $stats->sum('days_added'),
'promotions' => $stats->groupBy('role_promotion_id')->map(function ($group) {
return [
'promotion_id' => $group->first()->role_promotion_id,
'promotion_name' => $group->first()->promotion->name,
'times_applied' => $group->count(),
'total_days' => $group->sum('days_added'),
];
})->values()->all(),
];
}
/**
* Record a promotion application
*/
public static function recordPromotion(
int $userId,
int $promotionId,
int $roleId,
int $daysAdded,
?Carbon $previousExpiryDate = null,
?Carbon $newExpiryDate = null
): self {
return static::create([
'user_id' => $userId,
'role_promotion_id' => $promotionId,
'role_id' => $roleId,
'days_added' => $daysAdded,
'previous_expiry_date' => $previousExpiryDate,
'new_expiry_date' => $newExpiryDate,
'applied_at' => now(),
]);
}
}