GG.deals clone: CodeIgniter 4 + MongoDB game price tracker
- Full gg.deals-style UI: deal feed with filters, game pages with price history charts, rankings, vouchers, news, prepaids, subscriptions, bundles, franchises, wishlist, API docs - Real data crawlers: * gg:crawl (Steam Store API + GOG Catalog + Epic free games) * gg:catalog (252K game slugs from gg.deals sitemaps) * gg:ggdeals (per-game prices via FlareSolverr session, JSON-LD parsing) * gg:seed / gg:crawl-covers (demo seed + Steam CDN cover art) - 24/7 self-updating scheduler (scripts/scheduler_loop.php, lockfile-protected) - Tailwind v4 dark/light theme, Alpine.js, Chart.js
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\GameModel;
|
||||
use App\Models\StoreModel;
|
||||
use CodeIgniter\Controller;
|
||||
|
||||
class Games extends Controller
|
||||
{
|
||||
public function index(string $genre = ''): string
|
||||
{
|
||||
$model = new GameModel();
|
||||
$request = service('request');
|
||||
|
||||
// genre map (slug => name)
|
||||
$genres = [];
|
||||
foreach ($model->genres() as $g) {
|
||||
$slug = url_title((string) $g['_id'], '-', true);
|
||||
$genres[$slug] = ['name' => $g['_id'], 'count' => $g['count']];
|
||||
}
|
||||
ksort($genres);
|
||||
|
||||
$genreName = '';
|
||||
if ($genre !== '') {
|
||||
if (! isset($genres[$genre])) {
|
||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
$genreName = $genres[$genre]['name'];
|
||||
}
|
||||
|
||||
// ---- filters (same shape as the deal feed) ----
|
||||
$filters = [
|
||||
'stores' => array_values(array_filter(array_map('strval', (array) $request->getGet('stores')))),
|
||||
'kind' => (string) ($request->getGet('kind') ?? ''),
|
||||
'min_price' => $request->getGet('min_price') !== null ? (string) $request->getGet('min_price') : '',
|
||||
'max_price' => $request->getGet('max_price') !== null ? (string) $request->getGet('max_price') : '',
|
||||
'min_cut' => (int) ($request->getGet('min_cut') ?? 0),
|
||||
'hl_only' => (bool) $request->getGet('hl_only'),
|
||||
'sort' => (string) ($request->getGet('sort') ?? 'trending'),
|
||||
'q' => trim((string) ($request->getGet('q') ?? '')),
|
||||
'price_tier' => (string) ($request->getGet('price_tier') ?? ''),
|
||||
'discount_tier' => (string) ($request->getGet('discount_tier') ?? ''),
|
||||
'deal_rating' => (string) ($request->getGet('deal_rating') ?? ''),
|
||||
'release_range' => (string) ($request->getGet('release_range') ?? ''),
|
||||
'time_range' => (string) ($request->getGet('time_range') ?? ''),
|
||||
'genre' => $genreName,
|
||||
'genres' => array_values(array_filter(array_map('strval', (array) $request->getGet('genres')))),
|
||||
];
|
||||
|
||||
$page = max(1, (int) $request->getGet('page'));
|
||||
$perPage = 20;
|
||||
|
||||
$feed = $model->feed($filters, $page, $perPage);
|
||||
|
||||
$data = [
|
||||
'pageTitle' => ($genreName !== '' ? ucwords($genreName) . ' games — ' : '') . 'GG.deals',
|
||||
'filters' => $filters,
|
||||
'feed' => $feed['rows'],
|
||||
'total' => $feed['total'],
|
||||
'pages' => $feed['pages'],
|
||||
'page' => $page,
|
||||
'perPage' => $perPage,
|
||||
'genres' => $genres,
|
||||
'activeGenre' => $genre,
|
||||
'activeGenreName' => $genreName,
|
||||
'stores' => (new StoreModel())->all(),
|
||||
'stats' => $model->stats(),
|
||||
];
|
||||
|
||||
return view('games', $data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user