Search SPT Version & Homepage Queries

The global search results now include the SPT version number the latest version of the mod is compatible with. Additionally, mod thumbnails and the SPT version numbers

Homepage queries have been further optimized and are now cached for 5 minutes.
This commit is contained in:
Refringe 2024-07-15 23:13:51 -04:00
parent 69857abe4f
commit 49fd8b83df
Signed by: Refringe
SSH Key Fingerprint: SHA256:t865XsQpfTeqPRBMN2G6+N8wlDjkgUCZF3WGW6O9N/k
9 changed files with 79 additions and 88 deletions

View File

@ -28,9 +28,8 @@ class ModController extends Controller
public function show(int $modId, string $slug)
{
$mod = Mod::select()
->withLatestSptVersion()
->withTotalDownloads()
->with('users:id,name')
->with(['latestSptVersion', 'users:id,name'])
->with('license:id,name,link')
->find($modId);

View File

@ -56,6 +56,7 @@ class ImportHubData implements ShouldBeUnique, ShouldQueue
Artisan::call('scout:delete-all-indexes');
Artisan::call('scout:sync-index-settings');
Artisan::call('scout:import', ['model' => '\App\Models\Mod']);
Artisan::call('scout:import', ['model' => '\App\Models\User']);
}
/**

View File

@ -42,8 +42,8 @@ class GlobalSearch extends Component
if (Str::length($query)) {
$results['data'] = [
'user' => User::search($query)->get(),
'mod' => Mod::search($query)->get(),
'user' => collect(User::search($query)->raw()['hits']),
'mod' => collect(Mod::search($query)->raw()['hits']),
];
$results['total'] = $this->countTotalResults($results['data']);
}

View File

@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
@ -50,55 +51,15 @@ class Mod extends Model
*/
public function scopeWithTotalDownloads($query)
{
return $query->addSelect(['total_downloads' => ModVersion::selectRaw('SUM(downloads) AS total_downloads')
return $query->addSelect([
'total_downloads' => ModVersion::selectRaw('SUM(downloads) AS total_downloads')
->whereColumn('mod_id', 'mods.id'),
]);
}
public function latestSptVersion(): BelongsTo
public function lastUpdatedVersion(): HasOne
{
return $this->belongsTo(ModVersion::class, 'latest_spt_version_id');
}
public function scopeWithLatestSptVersion($query)
{
return $query
->addSelect(['latest_spt_version_id' => ModVersion::select('id')
->whereColumn('mod_id', 'mods.id')
->orderByDesc(
SptVersion::select('version')
->whereColumn('mod_versions.spt_version_id', 'spt_versions.id')
->orderByDesc('version')
->take(1),
)
->orderByDesc('version')
->take(1),
])
->havingNotNull('latest_spt_version_id')
->with(['latestSptVersion', 'latestSptVersion.sptVersion']);
}
public function lastUpdatedVersion(): BelongsTo
{
return $this->belongsTo(ModVersion::class, 'last_updated_spt_version_id');
}
public function scopeWithLastUpdatedVersion($query)
{
return $query
->addSelect(['last_updated_spt_version_id' => ModVersion::select('id')
->whereColumn('mod_id', 'mods.id')
->orderByDesc('updated_at')
->take(1),
])
->orderByDesc(
ModVersion::select('updated_at')
->whereColumn('mod_id', 'mods.id')
->orderByDesc('updated_at')
->take(1)
)
->havingNotNull('last_updated_spt_version_id')
->with(['lastUpdatedVersion', 'lastUpdatedVersion.sptVersion']);
return $this->hasOne(ModVersion::class)->orderByDesc('updated_at')->with('sptVersion');
}
/**
@ -106,6 +67,8 @@ class Mod extends Model
*/
public function toSearchableArray(): array
{
$latestSptVersion = $this->latestSptVersion()->first();
return [
'id' => (int) $this->id,
'name' => $this->name,
@ -115,9 +78,25 @@ class Mod extends Model
'featured' => $this->featured,
'created_at' => strtotime($this->created_at),
'updated_at' => strtotime($this->updated_at),
'latestSptVersion' => $latestSptVersion?->sptVersion->version,
'latestSptVersionColorClass' => $latestSptVersion?->sptVersion->color_class,
];
}
public function latestSptVersion(): HasOne
{
return $this->hasOne(ModVersion::class)
->orderByDesc(
SptVersion::select('version')
->whereColumn('mod_versions.spt_version_id', 'spt_versions.id')
->orderByDesc('version')
->take(1),
)
->with('sptVersion')
->orderByDesc('version')
->take(1);
}
/**
* Determine if the model should be searchable.
*/

View File

@ -3,8 +3,10 @@
namespace App\View\Components;
use App\Models\Mod;
use App\Models\ModVersion;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\Component;
class ModListSection extends Component
@ -24,36 +26,44 @@ class ModListSection extends Component
private function fetchFeaturedMods(): Collection
{
return Cache::remember('homepage-featured-mods', now()->addMinutes(5), function () {
return Mod::select(['id', 'name', 'slug', 'teaser', 'thumbnail', 'featured'])
->withLatestSptVersion()
->withTotalDownloads()
->with('users:id,name')
->with(['latestSptVersion', 'users:id,name'])
->where('featured', true)
->latest()
->limit(6)
->get();
});
}
private function fetchLatestMods(): Collection
{
return Cache::remember('homepage-latest-mods', now()->addMinutes(5), function () {
return Mod::select(['id', 'name', 'slug', 'teaser', 'thumbnail', 'featured', 'created_at'])
->withLatestSptVersion()
->withTotalDownloads()
->with('users:id,name')
->with(['latestSptVersion', 'users:id,name'])
->latest()
->limit(6)
->get();
});
}
private function fetchUpdatedMods(): Collection
{
return Cache::remember('homepage-updated-mods', now()->addMinutes(5), function () {
return Mod::select(['id', 'name', 'slug', 'teaser', 'thumbnail', 'featured'])
->withLastUpdatedVersion()
->withTotalDownloads()
->with('users:id,name')
->latest()
->with(['lastUpdatedVersion', 'users:id,name'])
->orderByDesc(
ModVersion::select('updated_at')
->whereColumn('mod_id', 'mods.id')
->orderByDesc('updated_at')
->take(1)
)
->limit(6)
->get();
});
}
public function render(): View

View File

@ -1,9 +1,12 @@
<a href="/mod/{{ $result->id }}/{{ $result->slug }}" class="{{ $linkClass }}" role="listitem" tabindex="0">
<a href="/mod/{{ $result['id'] }}/{{ $result['slug'] }}" class="{{ $linkClass }}" role="listitem" tabindex="0" class="flex flex-col">
@if(empty($result->thumbnail))
<img src="https://placehold.co/450x450/EEE/31343C?font=source-sans-pro&text={{ $result->name }}" alt="{{ $result->name }}" class="block dark:hidden h-6 w-6 flex-none border border-gray-200 group-hover/global-search-link:border-gray-400">
<img src="https://placehold.co/450x450/31343C/EEE?font=source-sans-pro&text={{ $result->name }}" alt="{{ $result->name }}" class="hidden dark:block h-6 w-6 flex-none border border-gray-700 group-hover/global-search-link:border-gray-600">
<img src="https://placehold.co/450x450/EEE/31343C?font=source-sans-pro&text={{ $result['name'] }}" alt="{{ $result['name'] }}" class="block dark:hidden h-6 w-6 self-center border border-gray-200 group-hover/global-search-link:border-gray-400">
<img src="https://placehold.co/450x450/31343C/EEE?font=source-sans-pro&text={{ $result['name'] }}" alt="{{ $result['name'] }}" class="hidden dark:block h-6 w-6 self-center border border-gray-700 group-hover/global-search-link:border-gray-600">
@else
<img src="{{ Storage::url($result->thumbnail) }}" alt="{{ $result->name }}" class="h-6 w-6 flex-none">
<img src="{{ Storage::url($result['thumbnail']) }}" alt="{{ $result['name'] }}" class="h-6 w-6 self-center">
@endif
<p>{{ $result->name }}</p>
<p class="flex-grow">{{ $result['name'] }}</p>
<p class="ml-auto self-center badge-version {{ $result['latestSptVersionColorClass'] }} }} inline-flex items-center rounded-md px-2 py-1 text-xs font-medium text-nowrap">
{{ $result['latestSptVersion'] }}
</p>
</a>

View File

@ -1,3 +1,3 @@
<a href="#/{{ Str::slug($result->name) }}" class="{{ $linkClass }}">
<p>{{ $result->name }}</p>
<a href="#/{{ Str::slug($result['name']) }}" class="{{ $linkClass }}">
<p>{{ $result['name'] }}</p>
</a>

View File

@ -10,13 +10,15 @@
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</h4>
<div class="divide-y divide-dashed divide-gray-200 dark:divide-gray-800">
@foreach($typeResults as $result)
@component('components.global-search-result-' . Str::lower($typeName), [
'result' => $result,
'linkClass' => 'group/global-search-link flex flex-row gap-3 py-1.5 px-4 text-gray-900 dark:text-gray-100 hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors duration-100 ease-in-out',
'linkClass' => 'group/global-search-link flex flex-row gap-3 py-1.5 px-4 text-gray-900 dark:text-gray-100 hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors duration-200 ease-in-out',
])
@endcomponent
@endforeach
</div>
@endif
@endforeach
</div>

View File

@ -16,9 +16,6 @@
<div class="flex flex-col w-full justify-between p-5">
<div>
<div class="flex justify-between items-center space-x-3">
@if(is_null($mod->{$versionScope}))
@dd($mod)
@endif
<h3 class="block mt-1 text-lg leading-tight font-medium text-black dark:text-white group-hover:underline">{{ $mod->name }}</h3>
<span class="badge-version {{ $mod->{$versionScope}->sptVersion->color_class }} inline-flex items-center rounded-md px-2 py-1 text-xs font-medium text-nowrap">
{{ $mod->{$versionScope}->sptVersion->version }}