forge/app/Models/SptVersion.php

223 lines
7.4 KiB
PHP
Raw Normal View History

2024-05-15 00:31:24 -04:00
<?php
2025-01-30 00:23:55 -05:00
declare(strict_types=1);
2024-05-15 00:31:24 -04:00
namespace App\Models;
use App\Exceptions\InvalidVersionNumberException;
use App\Support\Version;
2025-01-30 15:44:05 -05:00
use Carbon\Carbon;
2025-01-30 20:49:56 -05:00
use Database\Factories\SptVersionFactory;
use Illuminate\Database\Eloquent\Collection;
2024-05-15 00:31:24 -04:00
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
2024-05-15 00:31:24 -04:00
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Cache;
2025-01-30 00:23:55 -05:00
use Override;
2025-01-30 15:44:05 -05:00
use Throwable;
/**
* SptVersion Model
*
* @property int $id
* @property int|null $hub_id
* @property string $version
* @property int $version_major
* @property int $version_minor
* @property int $version_patch
* @property string $version_pre_release
* @property int $mod_count
* @property string $link
* @property string $color_class
* @property Carbon|null $deleted_at
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read Collection<int, ModVersion> $modVersions
* @property-read string $version_formatted
*/
2024-05-15 00:31:24 -04:00
class SptVersion extends Model
{
2025-01-30 20:49:56 -05:00
/** @use HasFactory<SptVersionFactory> */
2024-09-12 13:19:52 -04:00
use HasFactory;
2025-01-30 20:49:56 -05:00
2024-09-12 13:19:52 -04:00
use SoftDeletes;
2024-05-15 00:31:24 -04:00
/**
* Get all versions for the last three minor versions.
2025-01-30 20:49:56 -05:00
*
* @return Collection<int, $this>
*/
public static function getVersionsForLastThreeMinors(): Collection
{
$lastThreeMinorVersions = self::getLastThreeMinorVersions();
// Extract major and minor arrays.
$majorVersions = array_column($lastThreeMinorVersions, 'major');
$minorVersions = array_column($lastThreeMinorVersions, 'minor');
// Fetch all versions for the last three minor versions with mod count.
2025-01-30 00:50:28 -05:00
return self::query()->select(['spt_versions.id', 'spt_versions.version', 'spt_versions.color_class', 'spt_versions.mod_count'])
->join('mod_version_spt_version', 'spt_versions.id', '=', 'mod_version_spt_version.spt_version_id')
->join('mod_versions', 'mod_version_spt_version.mod_version_id', '=', 'mod_versions.id')
->join('mods', 'mod_versions.mod_id', '=', 'mods.id')
->where('spt_versions.version', '!=', '0.0.0')
->whereIn('spt_versions.version_major', $majorVersions)
->whereIn('spt_versions.version_minor', $minorVersions)
->where('spt_versions.mod_count', '>', 0)
->groupBy('spt_versions.id', 'spt_versions.version', 'spt_versions.color_class', 'spt_versions.mod_count')
->orderBy('spt_versions.version_major', 'DESC')
->orderBy('spt_versions.version_minor', 'DESC')
->orderBy('spt_versions.version_patch', 'DESC')
->orderBy('spt_versions.version_pre_release', 'ASC')
->get();
}
/**
* Get the last three minor versions (major.minor format).
2025-01-30 20:49:56 -05:00
*
* @return array<int, array{major: int, minor: int}>
*/
public static function getLastThreeMinorVersions(): array
{
2025-01-30 00:50:28 -05:00
return self::query()->selectRaw('CONCAT(version_major, ".", version_minor) AS minor_version, version_major, version_minor')
->where('version', '!=', '0.0.0')
->groupBy('version_major', 'version_minor')
->orderByDesc('version_major')
->orderByDesc('version_minor')
->limit(3)
->get()
2025-01-30 00:23:55 -05:00
->map(fn (SptVersion $sptVersion): array => [
'major' => (int) $sptVersion->version_major,
'minor' => (int) $sptVersion->version_minor,
])
->toArray();
}
/**
* Extract the version sections from the version string.
*
2025-01-30 20:49:56 -05:00
* @return array{major: int, minor: int, patch: int, pre_release: string}
*
2025-01-30 15:44:05 -05:00
* @throws InvalidVersionNumberException|Throwable
*/
public static function extractVersionSections(string $version): array
{
$matches = [];
// Perform the regex match to capture the version sections, including the possible preRelease section.
preg_match('/^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([a-zA-Z0-9]+))?$/', $version, $matches);
2025-01-30 00:50:28 -05:00
throw_if($matches === [], new InvalidVersionNumberException('Invalid SPT version number: '.$version));
return [
'major' => $matches[1] ?? 0,
'minor' => $matches[2] ?? 0,
'patch' => $matches[3] ?? 0,
'pre_release' => $matches[4] ?? '',
];
}
/**
* Called when the model is booted.
*/
2025-01-30 00:23:55 -05:00
#[Override]
protected static function booted(): void
{
2025-01-30 00:23:55 -05:00
static::saving(function (SptVersion $sptVersion): void {
// Extract the version sections from the version string.
try {
2025-01-30 00:23:55 -05:00
$version = new Version($sptVersion->version);
$sptVersion->version_major = $version->getMajor();
$sptVersion->version_minor = $version->getMinor();
$sptVersion->version_patch = $version->getPatch();
$sptVersion->version_pre_release = $version->getPreRelease();
} catch (InvalidVersionNumberException) {
$sptVersion->version_major = 0;
$sptVersion->version_minor = 0;
$sptVersion->version_patch = 0;
$sptVersion->version_pre_release = '';
}
});
}
/**
* Update the mod count for this SptVersion.
*/
public function updateModCount(): void
{
$modCount = $this->modVersions()
->distinct('mod_id')
->count('mod_id');
$this->mod_count = $modCount;
$this->saveQuietly();
}
2024-07-20 19:52:36 -04:00
/**
* The relationship between an SPT version and mod version.
2024-09-12 13:19:52 -04:00
*
2025-01-30 15:44:05 -05:00
* @return BelongsToMany<ModVersion, $this>
2024-07-20 19:52:36 -04:00
*/
public function modVersions(): BelongsToMany
2024-05-15 00:31:24 -04:00
{
return $this->belongsToMany(ModVersion::class)
->using(ModVersionSptVersion::class);
2024-05-15 00:31:24 -04:00
}
/**
* Get the version with "SPT " prepended.
*/
public function getVersionFormattedAttribute(): string
{
return __('SPT ').$this->version;
}
/**
* Determine if the version is part of the latest version's minor releases.
* For example, if the latest version is 1.2.0, this method will return true for 1.2.0, 1.2.1, 1.2.2, etc.
*/
public function isLatestMinor(): bool
{
$latestVersion = self::getLatest();
2025-01-30 00:23:55 -05:00
if (! $latestVersion instanceof \App\Models\SptVersion) {
return false;
}
return $this->version_major == $latestVersion->version_major && $this->version_minor == $latestVersion->version_minor;
}
/**
* Get the latest SPT version.
*
* @cached latest_spt_version 300s
*/
public static function getLatest(): ?SptVersion
{
2025-01-30 00:50:28 -05:00
return Cache::remember('latest_spt_version', 300, fn () => \App\Models\SptVersion::query()->select(['version', 'version_major', 'version_minor', 'version_patch', 'version_pre_release'])
2025-01-30 00:23:55 -05:00
->orderByDesc('version_major')
->orderByDesc('version_minor')
->orderByDesc('version_patch')
->first());
}
2024-10-12 13:18:04 -06:00
/**
* The attributes that should be cast to native types.
*/
protected function casts(): array
{
return [
'hub_id' => 'integer',
'version_major' => 'integer',
'version_minor' => 'integer',
'version_patch' => 'integer',
'mod_count' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
}
2024-05-15 00:31:24 -04:00
}