<?php
// Catalogue search with category filter and pagination. Run: php -S 127.0.0.1:8097 (from this folder)
declare(strict_types=1);
const PER_PAGE = 12;
$db = new PDO('sqlite::memory:'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec('CREATE TABLE p(sku TEXT, name TEXT, category TEXT, price REAL, stock INT)');
$f = fopen(__DIR__ . '/catalogue.csv', 'r'); fgetcsv($f, null, ',', '"', ''); $ins = $db->prepare('INSERT INTO p VALUES (?,?,?,?,?)');
while ($r = fgetcsv($f, null, ',', '"', '')) $ins->execute($r);
$q = trim((string)($_GET['q'] ?? '')); $cat = (string)($_GET['cat'] ?? ''); $page = max(1, (int)($_GET['page'] ?? 1));
$where = []; $args = [];
if ($q !== '') { $where[] = "name LIKE ? ESCAPE '\\'"; $args[] = '%' . addcslashes($q, '%_\\') . '%'; }
if ($cat !== '') { $where[] = 'category = ?'; $args[] = $cat; }
$sqlWhere = $where ? 'WHERE ' . implode(' AND ', $where) : '';
$c = $db->prepare("SELECT COUNT(*) FROM p $sqlWhere"); $c->execute($args); $total = (int)$c->fetchColumn();
$pages = max(1, (int)ceil($total / PER_PAGE)); $page = min($page, $pages);
$s = $db->prepare("SELECT * FROM p $sqlWhere ORDER BY name LIMIT " . PER_PAGE . ' OFFSET ' . (($page - 1) * PER_PAGE)); $s->execute($args);
$rows = $s->fetchAll(PDO::FETCH_ASSOC); $cats = $db->query('SELECT DISTINCT category FROM p ORDER BY 1')->fetchAll(PDO::FETCH_COLUMN);
function h(string $s): string { return htmlspecialchars($s, ENT_QUOTES); }
function link_to(int $p): string { return '?' . http_build_query(array_filter(['q' => $_GET['q'] ?? '', 'cat' => $_GET['cat'] ?? '', 'page' => $p])); }
?><!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Catalogue search · Sample Store</title><link rel="stylesheet" href="style.css"></head><body><main>
<h1>Sample Store catalogue</h1>
<form method="get"><input name="q" value="<?= h($q) ?>" placeholder="Search products" aria-label="Search products">
<select name="cat" aria-label="Category"><option value="">All categories</option><?php foreach ($cats as $k): ?><option<?= $k === $cat ? ' selected' : '' ?>><?= h($k) ?></option><?php endforeach ?></select>
<button>Search</button></form>
<p class="meta"><?= $total ?> result<?= $total === 1 ? '' : 's' ?><?= $q !== '' ? ' for “' . h($q) . '”' : '' ?> · page <?= $page ?> of <?= $pages ?></p>
<?php if (!$rows): ?><p class="empty">No products match. Try a shorter search.</p><?php else: ?>
<table><thead><tr><th>SKU</th><th>Product</th><th>Category</th><th class="r">Price</th><th class="r">Stock</th></tr></thead><tbody>
<?php foreach ($rows as $r): ?><tr><td><?= h($r['sku']) ?></td><td><?= h($r['name']) ?></td><td><?= h($r['category']) ?></td><td class="r">$<?= number_format((float)$r['price'], 2) ?></td><td class="r<?= $r['stock'] == 0 ? ' out' : '' ?>"><?= $r['stock'] == 0 ? 'Out' : (int)$r['stock'] ?></td></tr><?php endforeach ?>
</tbody></table><?php endif ?>
<nav class="pager" aria-label="Pages"><?php for ($i = 1; $i <= $pages; $i++): ?><a href="<?= h(link_to($i)) ?>"<?= $i === $page ? ' aria-current="page"' : '' ?>><?= $i ?></a><?php endfor ?></nav>
</main></body></html>
