fix: étendre la recherche aux identifications
This commit is contained in:
parent
361bef8561
commit
a932db0ace
8 changed files with 66 additions and 12 deletions
|
|
@ -29,6 +29,17 @@ final class DB
|
|||
$pdo->exec('PRAGMA busy_timeout = 3000;');
|
||||
@chmod($dbPath, 0600);
|
||||
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
$pdo->sqliteCreateFunction(
|
||||
'search_fold',
|
||||
static function (mixed $value): string {
|
||||
$text = mb_strtolower(trim((string) $value), 'UTF-8');
|
||||
$text = strtr($text, ['œ' => 'oe', 'æ' => 'ae', 'ø' => 'o', 'ß' => 'ss']);
|
||||
$ascii = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text);
|
||||
return $ascii === false ? $text : strtolower($ascii);
|
||||
},
|
||||
1,
|
||||
PDO::SQLITE_DETERMINISTIC,
|
||||
);
|
||||
|
||||
self::$pdo = $pdo;
|
||||
return $pdo;
|
||||
|
|
|
|||
|
|
@ -11,17 +11,21 @@ final class GlobalSearchService
|
|||
return [];
|
||||
}
|
||||
$db = DB::pdo();
|
||||
$like = '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $query) . '%';
|
||||
$foldedQuery = self::fold($query);
|
||||
$like = '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $foldedQuery) . '%';
|
||||
$out = [];
|
||||
if (PermissionService::can('animals')) {
|
||||
$out['animals'] = self::rows(
|
||||
$db,
|
||||
"SELECT id,name,internal_code,status,species FROM animals WHERE deleted_at IS NULL AND (name LIKE :q ESCAPE '\\' OR internal_code LIKE :q ESCAPE '\\' OR COALESCE(chip,'') LIKE :q ESCAPE '\\') ORDER BY name COLLATE NOCASE LIMIT :lim",
|
||||
"SELECT id,name,internal_code,status,species,COALESCE(NULLIF(chip_id,''),NULLIF(chip,'')) identification_number FROM animals WHERE deleted_at IS NULL AND (search_fold(name) LIKE :q ESCAPE '\\' OR search_fold(internal_code) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(chip_id,'')) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(chip,'')) LIKE :q ESCAPE '\\') ORDER BY name COLLATE NOCASE LIMIT :lim",
|
||||
$like,
|
||||
$limit,
|
||||
static fn($r) => [
|
||||
'title' => $r['name'],
|
||||
'detail' => implode(' · ', array_filter([$r['internal_code'], $r['species'], $r['status']])),
|
||||
'detail' => implode(
|
||||
' · ',
|
||||
array_filter([$r['internal_code'], $r['identification_number'], $r['species'], $r['status']]),
|
||||
),
|
||||
'url' => '/animal?id=' . (int) $r['id'],
|
||||
],
|
||||
);
|
||||
|
|
@ -29,7 +33,7 @@ final class GlobalSearchService
|
|||
if (PermissionService::can('directory')) {
|
||||
$out['directory'] = self::rows(
|
||||
$db,
|
||||
"SELECT id,name,kind,phone,email,city FROM directory_contacts WHERE deleted_at IS NULL AND (name LIKE :q ESCAPE '\\' OR COALESCE(phone,'') LIKE :q ESCAPE '\\' OR COALESCE(email,'') LIKE :q ESCAPE '\\' OR COALESCE(city,'') LIKE :q ESCAPE '\\') ORDER BY name COLLATE NOCASE LIMIT :lim",
|
||||
"SELECT id,name,kind,phone,email,city FROM directory_contacts WHERE deleted_at IS NULL AND (search_fold(name) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(phone,'')) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(email,'')) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(city,'')) LIKE :q ESCAPE '\\') ORDER BY name COLLATE NOCASE LIMIT :lim",
|
||||
$like,
|
||||
$limit,
|
||||
static fn($r) => [
|
||||
|
|
@ -42,7 +46,7 @@ final class GlobalSearchService
|
|||
if (PermissionService::can('agenda')) {
|
||||
$out['agenda'] = self::rows(
|
||||
$db,
|
||||
"SELECT id,title,starts_at,location,status FROM agenda_items WHERE title LIKE :q ESCAPE '\\' OR COALESCE(description,'') LIKE :q ESCAPE '\\' OR COALESCE(location,'') LIKE :q ESCAPE '\\' ORDER BY starts_at DESC LIMIT :lim",
|
||||
"SELECT id,title,starts_at,location,status FROM agenda_items WHERE search_fold(title) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(description,'')) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(location,'')) LIKE :q ESCAPE '\\' ORDER BY starts_at DESC LIMIT :lim",
|
||||
$like,
|
||||
$limit,
|
||||
static fn($r) => [
|
||||
|
|
@ -58,7 +62,7 @@ final class GlobalSearchService
|
|||
if (PermissionService::can('accounting')) {
|
||||
$out['accounting'] = self::rows(
|
||||
$db,
|
||||
"SELECT ai.id,ai.reference,ai.invoice_date,ai.status,dc.name vendor FROM accounting_invoices ai LEFT JOIN directory_contacts dc ON dc.id=ai.vendor_contact_id WHERE ai.deleted_at IS NULL AND (ai.reference LIKE :q ESCAPE '\\' OR COALESCE(ai.notes,'') LIKE :q ESCAPE '\\' OR COALESCE(dc.name,'') LIKE :q ESCAPE '\\') ORDER BY ai.invoice_date DESC LIMIT :lim",
|
||||
"SELECT ai.id,ai.reference,ai.invoice_date,ai.status,dc.name vendor FROM accounting_invoices ai LEFT JOIN directory_contacts dc ON dc.id=ai.vendor_contact_id WHERE ai.deleted_at IS NULL AND (search_fold(ai.reference) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(ai.notes,'')) LIKE :q ESCAPE '\\' OR search_fold(COALESCE(dc.name,'')) LIKE :q ESCAPE '\\') ORDER BY ai.invoice_date DESC LIMIT :lim",
|
||||
$like,
|
||||
$limit,
|
||||
static fn($r) => [
|
||||
|
|
@ -71,6 +75,14 @@ final class GlobalSearchService
|
|||
return array_filter($out);
|
||||
}
|
||||
|
||||
private static function fold(string $value): string
|
||||
{
|
||||
$value = mb_strtolower(trim($value), 'UTF-8');
|
||||
$value = strtr($value, ['œ' => 'oe', 'æ' => 'ae', 'ø' => 'o', 'ß' => 'ss']);
|
||||
$ascii = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $value);
|
||||
return $ascii === false ? $value : strtolower($ascii);
|
||||
}
|
||||
|
||||
private static function rows(PDO $db, string $sql, string $like, int $limit, callable $map): array
|
||||
{
|
||||
$s = $db->prepare($sql);
|
||||
|
|
|
|||
Loading…
Reference in a new issue