Files
RomhackPlaza/app/Livewire/Database.php
2026-06-29 19:24:35 +02:00

395 lines
12 KiB
PHP

<?php
namespace App\Livewire;
use App\Models\Author;
use App\Models\Category;
use App\Models\Entry;
use App\Models\Game;
use App\Models\Genre;
use App\Models\Language;
use App\Models\Level;
use App\Models\Modification;
use App\Models\Platform;
use App\Models\Status;
use App\Models\System;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;
class Database extends Component
{
use WithPagination;
/**
* entry_title search
* @var string
*/
#[Url(as: 's',except: '')]
public string $search = '';
/**
* type filter.
* @var array
*/
#[Url(except:[])]
public array $types = [];
/**
* Games IDs filter.
* @var array
*/
#[Url(except:[])]
public array $games = [];
/**
* Current game search
* @var string
*/
public string $gameSearch = '';
/**
* Platform IDs filter.
* @var array
*/
#[Url(except:[])]
public array $platforms = [];
/**
* Genre IDs filter.
* @var array
*/
#[Url(except:[])]
public array $genres = [];
/**
* Status IDs filter.
* @var array
*/
#[Url(except:[])]
public array $statuses = [];
/**
* Authors IDs filter.
* @var array
*/
#[Url(except:[])]
public array $authors = [];
/**
* Authors mode and/or.
* @var string
*/
#[Url(except:'or')]
public string $authorsMode = 'or';
/**
* Current author search.
* @var string
*/
public string $authorSearch = '';
/**
* Languages IDs filter.
* @var array
*/
#[Url(except:[])]
public array $languages = [];
/**
* Languages mode and/or
* @var string
*/
#[Url(except:'or')]
public string $languagesMode = 'or';
/**
* Modifications IDs filter.
* @var array
*/
#[Url(except:[])]
public array $modifications = [];
/**
* Modifications mode and/or.
* @var string
*/
#[Url(except:'or')]
public string $modificationsMode = 'or';
/**
* Categories IDs filter.
* @var array
*/
#[Url(except:[])]
public array $categories = [];
/**
* Categories mode and/or
* @var string
*/
#[Url(except:'or')]
public string $categoriesMode = 'or';
/**
* Systems IDs filter.
* @var array
*/
#[Url(except:[])]
public array $systems = [];
/**
* Systems mode and/or
* @var string
*/
#[Url(except:'or')]
public string $systemsMode = 'or';
/**
* Levels IDs filter.
* @var array
*/
#[Url(except:[])]
public array $levels = [];
#[Url(except:null)]
public ?int $userId = null;
/**
* Sort by field.
* @var string
*/
#[Url(as: 'sort',except: 'created_at')]
public string $sortBy = 'created_at';
/**
* asc/desc
* @var string
*/
#[Url(as: 'dir',except: 'desc')]
public string $sortDir = 'desc';
/**
* Translation of sort options key.
*/
public const array SORT_OPTIONS = [
'created_at' => 'Date added',
'release_date' => 'Release date',
'total_downloads' => 'Total downloads',
'title' => 'Title'
];
/**
* Translation of entries key.
*/
public const array ENTRY_TYPES = [
'translations' => 'Translations',
'romhacks' => 'Romhacks',
'homebrew' => 'Homebrew',
'utilities' => 'Utilities',
'documents' => 'Documents',
'lua-scripts' => 'Lua Scripts',
];
public const int PAGINATION = 30;
public function updatedSearch(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedTypes(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedGames(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedPlatforms(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedGenres(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedStatuses(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedAuthors(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedAuthorsMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedLanguages(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedLanguagesMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedModifications(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedModificationsMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedCategories(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedCategoriesMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedSystems(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedSystemsMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedLevels(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedUserId(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function clearFilters(): void
{
$this->reset([
'search', 'types', 'platforms', 'genres', 'statuses', 'authors', 'authorsMode', 'languages', 'languagesMode', 'modifications', 'modificationsMode', 'categories', 'categoriesMode', 'systems', 'systemsMode', 'levels', 'userId'
]);
$this->dispatch('filters-updated');
$this->resetPage();
}
public function setSort(string $field): void
{
if( $this->sortBy === $field ) {
$this->sortDir = $this->sortDir === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $field;
$this->sortDir = 'asc';
}
$this->resetPage();
$this->dispatch('filters-updated');
}
private function buildQuery()
{
$query = Entry::query()->published()->with([
'game.platform', 'game.genre', 'status', 'authors', 'languages', 'level', 'systems', 'categories', 'modifications'
])->withSum('files', 'download_count');
if( $this->search ) {
$query->where(function($q) {
$q->where('title', 'like', '%'.$this->search.'%');
$q->orWhere('complete_title', 'like', '%'.$this->search.'%');
});
}
if( $this->types ) {
$query->whereIn('type', $this->types);
}
if( $this->platforms ) {
$query->where(function($q) {
$q->whereIn('platform_id', $this->platforms)
->orWhereHas('game', fn($q2) => $q2->whereIn('platform_id', $this->platforms) );
});
}
if( $this->genres ) {
$query->where(function($q) {
$q->whereHas('game', fn($q2) => $q2->whereIn('genre_id', $this->genres) );
});
}
if( $this->games ){
$query->whereIn('game_id', $this->games);
}
if( $this->statuses ) {
$query->whereIn('status_id', $this->statuses);
}
if( $this->authors ) {
if( $this->authorsMode === 'and' ) {
foreach ( $this->authors as $authorId ) {
$query->whereHas('authors', fn($q) => $q->where('authors.id', $authorId));
}
} else {
$query->whereHas('authors', fn($q) => $q->whereIn('authors.id', $this->authors));
}
}
if( $this->languages ) {
if( $this->languagesMode === 'and' ) {
foreach ( $this->languages as $langId ) {
$query->whereHas('languages', fn($q) => $q->where('languages.id', $langId));
}
} else {
$query->whereHas('languages', fn($q) => $q->whereIn('languages.id', $this->languages));
}
}
if( $this->modifications ) {
if( $this->modificationsMode === 'and' ) {
foreach ( $this->modifications as $modificationId ) {
$query->whereHas('modifications', fn($q) => $q->where('modifications.id', $modificationId));
}
} else {
$query->whereHas('modifications', fn($q) => $q->whereIn('modifications.id', $this->modifications));
}
}
if( $this->levels ) {
$query->whereIn('level_id', $this->levels);
}
if( $this->categories ) {
if( $this->categoriesMode === 'and' ) {
foreach ( $this->categories as $categoryId ) {
$query->whereHas('categories', fn($q) => $q->where('categories.id', $categoryId));
}
} else {
$query->whereHas('categories', fn($q) => $q->whereIn('categories.id', $this->categories));
}
}
if( $this->systems ) {
if( $this->systemsMode === 'and' ) {
foreach ( $this->systems as $systemId ) {
$query->whereHas('systems', fn($q) => $q->where('systems.id', $systemId));
}
} else {
$query->whereHas('systems', fn($q) => $q->whereIn('systems.id', $this->systems));
}
}
if( $this->userId ){
$query->where('user_id', $this->userId);
}
$sortColumn = $this->sortBy;
if ($sortColumn === 'total_downloads') {
$sortColumn = 'files_sum_download_count';
}
return $query->orderBy($sortColumn, $this->sortDir);
}
private function searchFilter( string $modelClass, string $search )
{
$this->dispatch('filters-updated');
if( mb_strlen( $search ) < 3 ) {
return collect();
}
return $modelClass::where('name', 'like', "%{$search}%")
->orderBy('name')
->limit(50)
->get();
}
private function searchGameFilter()
{
$search = $this->gameSearch;
$this->dispatch('filters-updated');
if( mb_strlen( $search ) < 3 ) {
return collect();
}
$collect = Game::where('name', 'like', "%{$search}%")
->orderBy('name')
->limit(50)
->get();
return $collect->map(function($item){
$item->name = $item->name . ' (' . ($item->platform?->short_name ?? $item->platform->name) . ')';
return $item;
} );
}
public function render()
{
return view('livewire.database', [
'entries' => $this->buildQuery()->paginate(self::PAGINATION),
'allGames' => $this->searchGameFilter(),
'allPlatforms' => Platform::orderBy('name')->get(),
'allGenres' => Genre::orderBy('name')->get(),
'allStatuses' => Status::orderBy('name')->get(),
'allAuthors' => $this->searchFilter(Author::class, $this->authorSearch),
'allLanguages' => Language::orderBy('name')->get(),
'allModifications' => Modification::orderBy('name')->get(),
'allCategories' => Category::orderBy('name')->get(),
'allLevels' => Level::orderBy('name')->get(),
'allSystems' => System::orderBy('name')->get(),
]);
}
}