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 ),
];
}
}