Files
breadcrumb-the-shire/lib/Support/SearchConfig.php

259 lines
13 KiB
PHP
Raw Normal View History

2026-02-04 23:31:53 +01:00
<?php
namespace MintyPHP\Support;
2026-02-11 19:28:12 +01:00
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserAvatarService;
2026-02-04 23:31:53 +01:00
class SearchConfig
{
public static function tenantScopeFilters(): array
{
return [
'users' => 'and exists (select 1 from user_tenants ut where ut.user_id = users.id and ut.tenant_id in (???))',
'address-book' => 'and exists (select 1 from user_tenants ut where ut.user_id = users.id and ut.tenant_id in (???))',
'tenants' => 'and id in (???)',
'departments' => 'and exists (select 1 from tenant_departments td where td.department_id = departments.id and td.tenant_id in (???))',
];
}
2026-02-11 19:28:12 +01:00
private static function normalizeLikeQuery(string $query): string
{
$query = trim($query);
if ($query === '') {
return '';
}
$query = str_replace('\\', '\\\\', $query);
$query = str_replace('_', '\\_', $query);
$query = str_replace('*', '%', $query);
if (!str_starts_with($query, '%')) {
$query = '%' . $query;
}
if (!str_ends_with($query, '%')) {
$query = $query . '%';
}
return $query;
}
public static function normalizeScoreQuery(string $query): string
{
$query = trim($query);
if ($query == '') {
return '';
}
return str_replace(['*', '%', '_'], '', $query);
}
2026-02-04 23:31:53 +01:00
public static function resources(string $query, string $locale): array
{
2026-02-11 19:28:12 +01:00
$like = self::normalizeLikeQuery($query);
2026-02-04 23:31:53 +01:00
return [
[
'key' => 'address-book',
'label' => t('Address book'),
'permission' => PermissionService::ADDRESS_BOOK_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from users where active = 1 and (first_name like ? escape '\\\\' or last_name like ? escape '\\\\' or email like ? escape '\\\\') {{tenantFilter}}",
2026-02-04 23:31:53 +01:00
'countParams' => [$like, $like, $like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select uuid, first_name, last_name, email from users where active = 1 and (first_name like ? escape '\\\\' or last_name like ? escape '\\\\' or email like ? escape '\\\\') {{tenantFilter}} order by last_name, first_name limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$like, $like, $like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select uuid, first_name, last_name, email from users where active = 1 and (first_name like ? escape '\\\\' or last_name like ? escape '\\\\' or email like ? escape '\\\\') {{tenantFilter}} order by last_name, first_name",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like, $like, $like],
],
[
'key' => 'users',
'label' => t('Users'),
'permission' => PermissionService::USERS_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from users where (first_name like ? escape '\\\\' or last_name like ? escape '\\\\' or email like ? escape '\\\\') {{tenantFilter}}",
2026-02-04 23:31:53 +01:00
'countParams' => [$like, $like, $like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select uuid, first_name, last_name, email from users where (first_name like ? escape '\\\\' or last_name like ? escape '\\\\' or email like ? escape '\\\\') {{tenantFilter}} order by last_name, first_name limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$like, $like, $like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select uuid, first_name, last_name, email from users where (first_name like ? escape '\\\\' or last_name like ? escape '\\\\' or email like ? escape '\\\\') {{tenantFilter}} order by last_name, first_name",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like, $like, $like],
],
[
'key' => 'tenants',
'label' => t('Tenants'),
'permission' => PermissionService::TENANTS_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from tenants where description like ? escape '\\\\' {{tenantFilter}}",
2026-02-04 23:31:53 +01:00
'countParams' => [$like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select uuid, description from tenants where description like ? escape '\\\\' {{tenantFilter}} order by description limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select uuid, description from tenants where description like ? escape '\\\\' {{tenantFilter}} order by description",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like],
],
[
'key' => 'departments',
'label' => t('Departments'),
'permission' => PermissionService::DEPARTMENTS_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from departments where description like ? escape '\\\\' {{tenantFilter}}",
2026-02-04 23:31:53 +01:00
'countParams' => [$like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select uuid, description from departments where description like ? escape '\\\\' {{tenantFilter}} order by description limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select uuid, description from departments where description like ? escape '\\\\' {{tenantFilter}} order by description",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like],
],
[
'key' => 'roles',
'label' => t('Roles'),
'permission' => PermissionService::ROLES_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from roles where active = 1 and description like ? escape '\\\\'",
2026-02-04 23:31:53 +01:00
'countParams' => [$like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select uuid, description from roles where active = 1 and description like ? escape '\\\\' order by description limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select uuid, description from roles where active = 1 and description like ? escape '\\\\' order by description",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like],
],
[
'key' => 'permissions',
'label' => t('Permissions'),
'permission' => PermissionService::PERMISSIONS_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from permissions where active = 1 and (`key` like ? escape '\\\\' or description like ? escape '\\\\')",
2026-02-04 23:31:53 +01:00
'countParams' => [$like, $like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select id, description, `key` from permissions where active = 1 and (`key` like ? escape '\\\\' or description like ? escape '\\\\') order by `key` limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$like, $like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select id, description, `key` from permissions where active = 1 and (`key` like ? escape '\\\\' or description like ? escape '\\\\') order by `key`",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like, $like],
],
[
'key' => 'pages',
'label' => t('Pages'),
'permission' => '',
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from pages p join page_contents pc on pc.page_id = p.id and pc.locale = ? where p.slug like ? escape '\\\\' or pc.content like ? escape '\\\\'",
2026-02-04 23:31:53 +01:00
'countParams' => [$locale, $like, $like],
2026-02-11 19:28:12 +01:00
'previewSql' => "select p.slug from pages p join page_contents pc on pc.page_id = p.id and pc.locale = ? where p.slug like ? escape '\\\\' or pc.content like ? escape '\\\\' order by p.slug limit ?",
2026-02-04 23:31:53 +01:00
'previewParams' => [$locale, $like, $like],
2026-02-11 19:28:12 +01:00
'resultSql' => "select p.slug from pages p join page_contents pc on pc.page_id = p.id and pc.locale = ? where p.slug like ? escape '\\\\' or pc.content like ? escape '\\\\' order by p.slug",
2026-02-04 23:31:53 +01:00
'resultParams' => [$locale, $like, $like],
],
[
'key' => 'settings',
'label' => t('Settings'),
'permission' => PermissionService::SETTINGS_VIEW,
2026-02-11 19:28:12 +01:00
'countSql' => "select count(*) from settings where `key` like ? escape '\\\\' or value like ? escape '\\\\'",
2026-02-04 23:31:53 +01:00
'countParams' => [$like, $like],
'previewSql' => null,
'previewParams' => [],
2026-02-11 19:28:12 +01:00
'resultSql' => "select `key`, value from settings where `key` like ? escape '\\\\' or value like ? escape '\\\\' order by `key`",
2026-02-04 23:31:53 +01:00
'resultParams' => [$like, $like],
],
];
}
public static function iconForKey(string $key): string
{
return match ($key) {
'address-book' => 'bi-people',
'users' => 'bi-person-badge',
'tenants' => 'bi-buildings',
'departments' => 'bi-diagram-3',
'roles' => 'bi-people',
'permissions' => 'bi-shield-lock',
'pages' => 'bi-file-text',
'settings' => 'bi-gear',
default => 'bi-search',
};
}
public static function listUrl(string $key, string $query): string
{
$encoded = urlencode($query);
return match ($key) {
'address-book' => lurl('address-book') . '?search=' . $encoded,
'users' => lurl('admin/users') . '?search=' . $encoded,
'tenants' => lurl('admin/tenants') . '?search=' . $encoded,
'departments' => lurl('admin/departments') . '?search=' . $encoded,
'roles' => lurl('admin/roles') . '?search=' . $encoded,
'permissions' => lurl('admin/permissions') . '?search=' . $encoded,
'pages' => lurl(''),
'settings' => lurl('admin/settings'),
default => lurl(''),
};
}
public static function mapPreviewItem(string $key, array $data, string $query): ?array
{
if ($key === 'users') {
$label = trim(($data['first_name'] ?? '') . ' ' . ($data['last_name'] ?? ''));
$email = trim((string) ($data['email'] ?? ''));
if ($email !== '') {
$label = $label === '' ? $email : ($label . ' — ' . $email);
}
$url = lurl('admin/users/edit/' . ($data['uuid'] ?? '')) . '?search=' . urlencode($query);
} elseif ($key === 'address-book') {
$label = trim(($data['first_name'] ?? '') . ' ' . ($data['last_name'] ?? ''));
$email = trim((string) ($data['email'] ?? ''));
if ($email !== '') {
$label = $label === '' ? $email : ($label . ' — ' . $email);
}
$url = lurl('address-book/view/' . ($data['uuid'] ?? '')) . '?search=' . urlencode($query);
} elseif ($key === 'permissions') {
$label = (string) ($data['description'] ?? '');
$url = lurl('admin/permissions/edit/' . ($data['id'] ?? '')) . '?search=' . urlencode($query);
} elseif ($key === 'pages') {
$label = (string) ($data['slug'] ?? '');
$url = lurl('page/' . $label) . '?search=' . urlencode($query);
} else {
$label = (string) ($data['description'] ?? '');
$url = lurl('admin/' . $key . '/edit/' . ($data['uuid'] ?? '')) . '?search=' . urlencode($query);
}
if ($label === '' || $url === '') {
return null;
}
return ['label' => $label, 'url' => $url];
}
public static function mapResultItem(string $key, string $label, array $data): ?array
{
$title = '';
$description = '';
$url = '';
$image = '';
if ($key === 'users') {
$title = trim(($data['first_name'] ?? '') . ' ' . ($data['last_name'] ?? ''));
$description = (string) ($data['email'] ?? '');
$url = lurl('admin/users/edit/' . ($data['uuid'] ?? ''));
} elseif ($key === 'address-book') {
$title = trim(($data['first_name'] ?? '') . ' ' . ($data['last_name'] ?? ''));
$description = (string) ($data['email'] ?? '');
$uuid = (string) ($data['uuid'] ?? '');
$url = lurl('address-book/view/' . $uuid);
if ($uuid !== '' && UserAvatarService::hasAvatar($uuid)) {
$image = lurl('admin/users/avatar-file') . '?uuid=' . urlencode($uuid) . '&size=64';
}
} elseif ($key === 'permissions') {
$title = (string) ($data['key'] ?? '');
$description = (string) ($data['description'] ?? '');
$url = lurl('admin/permissions/edit/' . ($data['id'] ?? ''));
} elseif ($key === 'pages') {
$title = (string) ($data['slug'] ?? '');
$description = t('Page');
$url = lurl('page/' . $title);
} elseif ($key === 'settings') {
$title = (string) ($data['key'] ?? '');
$description = (string) ($data['value'] ?? '');
$url = lurl('admin/settings');
} else {
$title = (string) ($data['description'] ?? '');
$description = $label;
$url = lurl('admin/' . $key . '/edit/' . ($data['uuid'] ?? ''));
}
if ($title === '' || $url === '') {
return null;
}
return [
'type' => $label,
'title' => $title,
'description' => $description,
'url' => $url,
'image' => $image,
'icon' => self::iconForKey($key),
];
}
}