-
Notifications
You must be signed in to change notification settings - Fork 2
fix: genre filter 500 error and clickable genre hierarchy #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f79377d
9395e3b
c8e6b07
f74d955
4daf300
a3c7cfe
cbe455e
4f75c7c
296cd58
10461df
038d783
4ff3781
e10893e
b353751
a386e0d
7b505d2
4bb21bd
ea69a2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,10 +128,10 @@ public function books(Request $request, Response $response, mysqli $db): Respons | |
| l.copie_disponibili, | ||
| l.copie_totali | ||
| FROM libri l | ||
| WHERE l.deleted_at IS NULL AND (l.titolo LIKE ? OR l.sottotitolo LIKE ? OR l.isbn10 LIKE ? OR l.isbn13 LIKE ? OR l.ean LIKE ?) | ||
| WHERE l.deleted_at IS NULL AND (l.titolo LIKE ? OR l.sottotitolo LIKE ? OR l.isbn10 LIKE ? OR l.isbn13 LIKE ? OR l.ean LIKE ? OR COALESCE(l.descrizione_plain, l.descrizione) LIKE ?) | ||
| ORDER BY l.titolo | ||
| "); | ||
| $stmt->bind_param('sssss', $s, $s, $s, $s, $s); | ||
| $stmt->bind_param('ssssss', $s, $s, $s, $s, $s, $s); | ||
|
Comment on lines
+131
to
+134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard These queries now hard-reference Also applies to: 238-241, 351-354 🤖 Prompt for AI Agents |
||
| $stmt->execute(); | ||
| $res = $stmt->get_result(); | ||
| while ($r = $res->fetch_assoc()) { | ||
|
|
@@ -227,18 +227,18 @@ private function searchBooks(mysqli $db, string $query): array | |
| $results = []; | ||
| $s = '%'.$query.'%'; | ||
|
|
||
| // Search by ISBN, EAN, title, subtitle - include author via subquery | ||
| // Search by ISBN, EAN, title, subtitle, description - include author via subquery | ||
| $stmt = $db->prepare(" | ||
| SELECT l.id, l.titolo AS label, l.isbn10, l.isbn13, l.ean, | ||
| (SELECT GROUP_CONCAT(a.nome ORDER BY la.ruolo='principale' DESC, a.nome SEPARATOR ', ') | ||
| FROM libri_autori la | ||
| JOIN autori a ON la.autore_id = a.id | ||
| WHERE la.libro_id = l.id) AS autori | ||
| FROM libri l | ||
| WHERE l.deleted_at IS NULL AND (l.isbn10 LIKE ? OR l.isbn13 LIKE ? OR l.ean LIKE ? OR l.titolo LIKE ? OR l.sottotitolo LIKE ?) | ||
| WHERE l.deleted_at IS NULL AND (l.isbn10 LIKE ? OR l.isbn13 LIKE ? OR l.ean LIKE ? OR l.titolo LIKE ? OR l.sottotitolo LIKE ? OR COALESCE(l.descrizione_plain, l.descrizione) LIKE ?) | ||
| ORDER BY l.titolo LIMIT 10 | ||
| "); | ||
| $stmt->bind_param('sssss', $s, $s, $s, $s, $s); | ||
| $stmt->bind_param('ssssss', $s, $s, $s, $s, $s, $s); | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| $stmt->execute(); | ||
| $res = $stmt->get_result(); | ||
|
|
||
|
|
@@ -348,10 +348,10 @@ private function searchBooksWithDetails(mysqli $db, string $query): array | |
| FROM libri l | ||
| LEFT JOIN libri_autori la ON l.id = la.libro_id | ||
| LEFT JOIN autori a ON la.autore_id = a.id | ||
| WHERE l.deleted_at IS NULL AND (l.titolo LIKE ? OR l.sottotitolo LIKE ? OR l.isbn10 LIKE ? OR l.isbn13 LIKE ? OR l.ean LIKE ? OR a.nome LIKE ?) | ||
| WHERE l.deleted_at IS NULL AND (l.titolo LIKE ? OR l.sottotitolo LIKE ? OR COALESCE(l.descrizione_plain, l.descrizione) LIKE ? OR l.isbn10 LIKE ? OR l.isbn13 LIKE ? OR l.ean LIKE ? OR a.nome LIKE ?) | ||
| ORDER BY l.titolo LIMIT 8 | ||
| "); | ||
| $stmt->bind_param('ssssss', $s, $s, $s, $s, $s, $s); | ||
| $stmt->bind_param('sssssss', $s, $s, $s, $s, $s, $s, $s); | ||
| $stmt->execute(); | ||
| $res = $stmt->get_result(); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,6 +93,20 @@ public function getById(int $id): ?array | |
| if (!$row) | ||
| return null; | ||
|
|
||
| // Lazy backfill: populate descrizione_plain for pre-migration rows on first read | ||
| if ($this->hasColumn('descrizione_plain') | ||
| && $row['descrizione_plain'] === null | ||
| && !empty($row['descrizione']) | ||
| ) { | ||
| $plain = $this->toPlainTextDescription((string)$row['descrizione']); | ||
| $upd = $this->db->prepare("UPDATE libri SET descrizione_plain = ? WHERE id = ?"); | ||
| if ($upd) { | ||
| $upd->bind_param('si', $plain, $id); | ||
| $upd->execute(); | ||
| } | ||
| $row['descrizione_plain'] = $plain; | ||
| } | ||
|
Comment on lines
+96
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep This read path now issues an ♻️ Minimal fix- // Lazy backfill: populate descrizione_plain for pre-migration rows on first read
- if ($this->hasColumn('descrizione_plain')
- && $row['descrizione_plain'] === null
- && !empty($row['descrizione'])
- ) {
- $plain = $this->toPlainTextDescription((string)$row['descrizione']);
- $upd = $this->db->prepare("UPDATE libri SET descrizione_plain = ? WHERE id = ?");
- if ($upd) {
- $upd->bind_param('si', $plain, $id);
- $upd->execute();
- }
- $row['descrizione_plain'] = $plain;
- }
+ if ($this->hasColumn('descrizione_plain')
+ && $row['descrizione_plain'] === null
+ && !empty($row['descrizione'])
+ ) {
+ // Keep reads side-effect free; persist backfills in migrations or write paths.
+ $row['descrizione_plain'] = $this->toPlainTextDescription((string) $row['descrizione']);
+ }🤖 Prompt for AI Agents |
||
|
|
||
| // Resolve genre hierarchy for the 3-level cascade (Radice → Genere → Sottogenere) | ||
| // Walk up the tree from genere_id to find the full ancestor chain, then map to cascade levels | ||
| $this->resolveGenreHierarchy($row); | ||
|
|
@@ -282,6 +296,10 @@ public function createBasic(array $data): int | |
| if ($this->hasColumn('descrizione')) { | ||
| $addField('descrizione', 's', $data['descrizione'] ?? null); | ||
| } | ||
| if ($this->hasColumn('descrizione_plain')) { | ||
| $raw = $data['descrizione'] ?? null; | ||
| $addField('descrizione_plain', 's', $this->toPlainTextDescription($raw)); | ||
| } | ||
| if ($this->hasColumn('parole_chiave')) { | ||
| $addField('parole_chiave', 's', $data['parole_chiave'] ?? null); | ||
| } | ||
|
|
@@ -608,6 +626,10 @@ public function updateBasic(int $id, array $data): bool | |
| if ($this->hasColumn('descrizione')) { | ||
| $addSet('descrizione', 's', $data['descrizione'] ?? null); | ||
| } | ||
| if ($this->hasColumn('descrizione_plain')) { | ||
| $raw = $data['descrizione'] ?? null; | ||
| $addSet('descrizione_plain', 's', $this->toPlainTextDescription($raw)); | ||
| } | ||
| if ($this->hasColumn('parole_chiave')) { | ||
| $addSet('parole_chiave', 's', $data['parole_chiave'] ?? null); | ||
| } | ||
|
|
@@ -1150,6 +1172,23 @@ private function resolveGenreHierarchy(array &$row): void | |
| } | ||
| } | ||
|
|
||
| private function toPlainTextDescription(?string $html): ?string | ||
| { | ||
| if ($html === null || $html === '') { | ||
| return $html; | ||
| } | ||
| $text = preg_replace( | ||
| '/<(?:\/?(?:p|div|li|ul|ol|h[1-6]|blockquote|tr|th|td)\b[^>]*|br\b[^>]*\/?)>/i', | ||
| "\n", | ||
| $html | ||
| ); | ||
| $text = html_entity_decode(strip_tags((string) $text), ENT_QUOTES | ENT_HTML5, 'UTF-8'); | ||
| $text = str_replace("\xC2\xA0", ' ', (string) $text); | ||
| $text = preg_replace("/[ \t]+/", ' ', (string) $text); | ||
| $text = preg_replace("/\n{3,}/", "\n\n", (string) $text); | ||
| return trim((string) $text); | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private static array $columnCacheByDb = []; | ||
| private function hasColumn(string $name): bool | ||
| { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.