2026-02-04 23:31:53 +01:00
< ? php
2026-02-11 19:28:12 +01:00
namespace MintyPHP\Repository\User ;
2026-02-04 23:31:53 +01:00
use MintyPHP\DB ;
2026-02-11 19:28:12 +01:00
use MintyPHP\Repository\Support\RepoQuery ;
2026-02-04 23:31:53 +01:00
class UserRepository
{
2026-02-11 19:28:12 +01:00
private static function buildUserFilters ( array $options ) : array
2026-02-04 23:31:53 +01:00
{
$search = trim (( string ) ( $options [ 'search' ] ? ? '' ));
$active = $options [ 'active' ] ? ? null ;
$createdFrom = trim (( string ) ( $options [ 'created_from' ] ? ? '' ));
$createdTo = trim (( string ) ( $options [ 'created_to' ] ? ? '' ));
$tenant = trim (( string ) ( $options [ 'tenant' ] ? ? '' ));
$tenantUuids = array_filter ( array_map ( 'trim' , explode ( ',' , ( string ) ( $options [ 'tenants' ] ? ? '' ))));
$roleIds = self :: normalizeIdList ( $options [ 'roles' ] ? ? []);
$departmentIds = self :: normalizeIdList ( $options [ 'departments' ] ? ? []);
$emailVerified = $options [ 'email_verified' ] ? ? null ;
2026-02-11 19:28:12 +01:00
$loginStatus = $options [ 'login_status' ] ? ? null ;
2026-02-04 23:31:53 +01:00
$where = [];
$params = [];
2026-02-11 19:28:12 +01:00
RepoQuery :: addLikeFilter (
$where ,
$params ,
[ 'users.first_name' , 'users.last_name' , 'users.email' ],
$search
);
RepoQuery :: addEnumFilter ( $where , $params , $active , [
[ 'aliases' => [ '1' , 'true' , 'active' ], 'sql' => 'users.active = ?' , 'params' => [ '1' ]],
[ 'aliases' => [ '0' , 'false' , 'inactive' ], 'sql' => 'users.active = ?' , 'params' => [ '0' ]],
]);
2026-02-04 23:31:53 +01:00
if ( $createdFrom !== '' ) {
$where [] = 'users.created >= ?' ;
$params [] = $createdFrom . ' 00:00:00' ;
}
if ( $createdTo !== '' ) {
$where [] = 'users.created <= ?' ;
$params [] = $createdTo . ' 23:59:59' ;
}
if ( $tenantUuids ) {
$where [] = 'exists (select 1 from user_tenants ut2 join tenants t2 on t2.id = ut2.tenant_id where ut2.user_id = users.id and t2.uuid in (???))' ;
$params [] = array_values ( $tenantUuids );
2026-02-11 19:28:12 +01:00
} else {
RepoQuery :: addEqualsFilter (
$where ,
$params ,
$tenant ,
'exists (select 1 from user_tenants ut2 join tenants t2 on t2.id = ut2.tenant_id where ut2.user_id = users.id and t2.uuid = ?)'
);
2026-02-04 23:31:53 +01:00
}
if ( $roleIds ) {
$where [] = 'exists (select 1 from user_roles ur2 where ur2.user_id = users.id and ur2.role_id in (???))' ;
$params [] = array_map ( 'strval' , $roleIds );
}
if ( $departmentIds ) {
$where [] = 'exists (select 1 from user_departments ud2 where ud2.user_id = users.id and ud2.department_id in (???))' ;
$params [] = array_map ( 'strval' , $departmentIds );
}
2026-02-11 19:28:12 +01:00
RepoQuery :: addEnumFilter ( $where , $params , $emailVerified , [
[ 'aliases' => [ '1' , 'true' , 'verified' , 'yes' ], 'sql' => 'users.email_verified_at is not null' ],
[ 'aliases' => [ '0' , 'false' , 'unverified' , 'no' ], 'sql' => 'users.email_verified_at is null' ],
]);
RepoQuery :: addEnumFilter ( $where , $params , $loginStatus , [
[ 'aliases' => [ 'never' , 'none' , 'no' ], 'sql' => 'users.last_login_at is null' ],
[ 'aliases' => [ 'ever' , 'logged' , 'yes' ], 'sql' => 'users.last_login_at is not null' ],
]);
2026-02-04 23:31:53 +01:00
if ( ! empty ( $options [ 'tenantUserId' ])) {
$tenantUserId = ( int ) $options [ 'tenantUserId' ];
if ( $tenantUserId > 0 ) {
if ( defined ( 'TENANT_SCOPE_STRICT' ) && TENANT_SCOPE_STRICT ) {
$where [] = 'exists (select 1 from user_tenants ut join user_tenants ut2 on ut2.tenant_id = ut.tenant_id ' .
" join tenants t on t.id = ut.tenant_id and t.status = 'active' " .
'where ut2.user_id = ? and ut.user_id = users.id)' ;
$params [] = ( string ) $tenantUserId ;
} else {
$where [] = '(not exists (select 1 from user_tenants ut where ut.user_id = users.id) ' .
'or exists (select 1 from user_tenants ut join user_tenants ut2 on ut2.tenant_id = ut.tenant_id ' .
" join tenants t on t.id = ut.tenant_id and t.status = 'active' " .
'where ut2.user_id = ? and ut.user_id = users.id))' ;
$params [] = ( string ) $tenantUserId ;
}
}
}
$whereSql = $where ? ( ' where ' . implode ( ' and ' , $where )) : '' ;
2026-02-11 19:28:12 +01:00
return [ $whereSql , $params ];
}
2026-02-04 23:31:53 +01:00
2026-02-11 19:28:12 +01:00
private static function buildListQuery ( string $whereSql , string $order , string $dir ) : string
{
return 'select users.id, users.uuid, users.first_name, users.last_name, users.display_name, users.email, users.profile_description, users.job_title, users.phone, users.mobile, users.short_dial, users.address, users.postal_code, users.city, users.country, users.region, users.hire_date, users.theme, users.primary_tenant_id, users.created_by, users.modified_by, users.created, users.modified, users.last_login_at, users.active, ' .
2026-02-04 23:31:53 +01:00
'pt.description as primary_tenant_label ' .
" from users left join tenants pt on pt.id = users.primary_tenant_id and pt.status = 'active' " .
$whereSql .
sprintf ( ' order by `users`.`%s` %s limit ? offset ?' , $order , $dir );
2026-02-11 19:28:12 +01:00
}
2026-02-04 23:31:53 +01:00
2026-02-11 19:28:12 +01:00
private static function extractIds ( array $list ) : array
{
2026-02-04 23:31:53 +01:00
$ids = [];
foreach ( $list as $user ) {
if ( isset ( $user [ 'id' ])) {
$ids [] = ( int ) $user [ 'id' ];
}
}
2026-02-11 19:28:12 +01:00
return $ids ;
}
2026-02-04 23:31:53 +01:00
2026-02-11 19:28:12 +01:00
private static function collectLabels ( array $rows , string $userKey , string $labelKey ) : array
{
$labelsByUser = [];
foreach ( $rows as $row ) {
$userId = 0 ;
$label = '' ;
if ( isset ( $row [ $userKey ]) && is_array ( $row [ $userKey ])) {
$userId = ( int ) ( $row [ $userKey ][ 'user_id' ] ? ? 0 );
}
if ( isset ( $row [ $labelKey ]) && is_array ( $row [ $labelKey ])) {
$label = ( string ) ( $row [ $labelKey ][ 'description' ] ? ? '' );
}
if ( $userId === 0 || $label === '' ) {
foreach ( $row as $value ) {
if ( ! is_array ( $value )) {
continue ;
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
if ( $userId === 0 && isset ( $value [ 'user_id' ])) {
$userId = ( int ) $value [ 'user_id' ];
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
if ( $label === '' && isset ( $value [ 'description' ])) {
$label = ( string ) $value [ 'description' ];
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
}
}
if ( $userId === 0 && isset ( $row [ 'user_id' ])) {
$userId = ( int ) $row [ 'user_id' ];
}
if ( $label === '' && isset ( $row [ 'description' ])) {
$label = ( string ) $row [ 'description' ];
}
if ( $userId > 0 && $label !== '' ) {
$labelsByUser [ $userId ] ? ? = [];
$labelsByUser [ $userId ][] = $label ;
}
}
return $labelsByUser ;
}
private static function hydrateUserLabels ( array $list , array $options ) : array
{
$ids = self :: extractIds ( $list );
if ( ! $ids ) {
return $list ;
}
$scopeToActiveTenants = ! empty ( $options [ 'tenantUserId' ]);
$tenantLabelJoin = $scopeToActiveTenants
? " join tenants t on t.id = ut.tenant_id and t.status = 'active' "
: 'join tenants t on t.id = ut.tenant_id ' ;
$placeholders = implode ( ',' , array_fill ( 0 , count ( $ids ), '?' ));
$labelRows = DB :: select (
'select ut.user_id as user_id, t.id as tenant_id, t.description as description from user_tenants ut ' . $tenantLabelJoin .
'where ut.user_id in (' . $placeholders . ') order by t.description asc' ,
... array_map ( 'strval' , $ids )
);
$roleLabelRows = DB :: select (
'select ur.user_id as user_id, r.description as description from user_roles ur join roles r on r.id = ur.role_id and r.active = 1 ' .
'where ur.user_id in (' . $placeholders . ') order by r.description asc' ,
... array_map ( 'strval' , $ids )
);
$departmentLabelRows = DB :: select (
'select ud.user_id as user_id, d.description as description from user_departments ud join departments d on d.id = ud.department_id and d.active = 1 ' .
'where ud.user_id in (' . $placeholders . ') order by d.description asc' ,
... array_map ( 'strval' , $ids )
);
$tenantMapByUser = [];
foreach ( $labelRows as $row ) {
$userId = 0 ;
$tenantId = 0 ;
$label = '' ;
if ( isset ( $row [ 'ut' ]) && is_array ( $row [ 'ut' ])) {
$userId = ( int ) ( $row [ 'ut' ][ 'user_id' ] ? ? 0 );
}
if ( isset ( $row [ 't' ]) && is_array ( $row [ 't' ])) {
$tenantId = ( int ) ( $row [ 't' ][ 'tenant_id' ] ? ? 0 );
$label = ( string ) ( $row [ 't' ][ 'description' ] ? ? '' );
}
if ( $userId === 0 || $tenantId === 0 || $label === '' ) {
foreach ( $row as $value ) {
if ( ! is_array ( $value )) {
continue ;
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
if ( $userId === 0 && isset ( $value [ 'user_id' ])) {
$userId = ( int ) $value [ 'user_id' ];
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
if ( $tenantId === 0 && isset ( $value [ 'tenant_id' ])) {
$tenantId = ( int ) $value [ 'tenant_id' ];
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
if ( $label === '' && isset ( $value [ 'description' ])) {
$label = ( string ) $value [ 'description' ];
2026-02-04 23:31:53 +01:00
}
}
}
2026-02-11 19:28:12 +01:00
if ( $userId === 0 && isset ( $row [ 'user_id' ])) {
$userId = ( int ) $row [ 'user_id' ];
}
if ( $tenantId === 0 && isset ( $row [ 'tenant_id' ])) {
$tenantId = ( int ) $row [ 'tenant_id' ];
}
if ( $label === '' && isset ( $row [ 'description' ])) {
$label = ( string ) $row [ 'description' ];
}
if ( $userId > 0 && $tenantId > 0 && $label !== '' ) {
$tenantMapByUser [ $userId ] ? ? = [];
$tenantMapByUser [ $userId ][ $tenantId ] = $label ;
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
}
$tenantLabelsByUser = [];
foreach ( $tenantMapByUser as $userId => $map ) {
$tenantLabelsByUser [ $userId ] = array_values ( $map );
}
$roleLabelsByUser = self :: collectLabels ( $roleLabelRows , 'ur' , 'r' );
$departmentLabelsByUser = self :: collectLabels ( $departmentLabelRows , 'ud' , 'd' );
foreach ( $list as & $user ) {
$userId = ( int ) ( $user [ 'id' ] ? ? 0 );
$primaryId = ( int ) ( $user [ 'primary_tenant_id' ] ? ? 0 );
$user [ 'tenant_labels' ] = $tenantLabelsByUser [ $userId ] ? ? [];
if ( $primaryId > 0 && isset ( $tenantMapByUser [ $userId ][ $primaryId ])) {
$user [ 'primary_tenant_label' ] = $tenantMapByUser [ $userId ][ $primaryId ];
}
$user [ 'role_labels' ] = $roleLabelsByUser [ $userId ] ? ? [];
$user [ 'department_labels' ] = $departmentLabelsByUser [ $userId ] ? ? [];
}
unset ( $user );
2026-02-04 23:31:53 +01:00
2026-02-11 19:28:12 +01:00
return $list ;
}
private static function unwrap ( ? array $row ) : ? array
{
if ( ! $row ) {
return null ;
}
return $row [ 'users' ] ? ? null ;
}
private static function unwrapList ( $rows ) : array
{
if ( ! is_array ( $rows )) {
return [];
}
$list = [];
foreach ( $rows as $row ) {
$user = $row [ 'users' ] ? ? null ;
if ( is_array ( $user )) {
foreach ( $row as $key => $value ) {
if ( $key === 'users' || is_array ( $value )) {
continue ;
}
$user [ $key ] = $value ;
}
if ( isset ( $row [ 'pt' ]) && is_array ( $row [ 'pt' ])) {
$label = ( string ) ( $row [ 'pt' ][ 'description' ] ? ? '' );
if ( $label !== '' ) {
$user [ 'primary_tenant_label' ] = $label ;
}
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
$list [] = $user ;
2026-02-04 23:31:53 +01:00
}
}
2026-02-11 19:28:12 +01:00
return $list ;
}
public static function list () : array
{
$rows = DB :: select (
'select id, uuid, first_name, last_name, display_name, email, profile_description, job_title, phone, mobile, short_dial, theme, primary_tenant_id, created_by, modified_by, created, modified, active from users order by id desc'
);
return self :: unwrapList ( $rows );
}
public static function updateLastLogin ( int $userId ) : void
{
if ( $userId <= 0 ) {
return ;
}
DB :: query ( 'update users set last_login_at = UTC_TIMESTAMP() where id = ?' , ( string ) $userId );
}
public static function listPaged ( array $options ) : array
{
$allowedOrder = [ 'id' , 'uuid' , 'first_name' , 'last_name' , 'email' , 'created' , 'modified' , 'active' , 'last_login_at' ];
[ $limit , $offset ] = RepoQuery :: sanitizeLimitOffset ( $options );
[ $order , $dir ] = RepoQuery :: sanitizeOrder ( $options , $allowedOrder );
[ $whereSql , $params ] = self :: buildUserFilters ( $options );
$count = DB :: selectValue ( 'select count(*) from users' . $whereSql , ... $params );
$total = $count ? ( int ) $count : 0 ;
$query = self :: buildListQuery ( $whereSql , $order , $dir );
$queryParams = array_merge ( $params , [( string ) $limit , ( string ) $offset ]);
$rows = call_user_func_array ([ 'MintyPHP\\DB' , 'select' ], array_merge ([ $query ], $queryParams ));
$list = self :: unwrapList ( $rows );
$list = self :: hydrateUserLabels ( $list , $options );
2026-02-04 23:31:53 +01:00
$result = [
'total' => $total ,
'rows' => $list ,
];
return $result ;
}
public static function find ( int $id ) : ? array
{
$row = DB :: selectOne (
2026-02-11 19:28:12 +01:00
'select id, uuid, first_name, last_name, display_name, email, profile_description, job_title, phone, mobile, short_dial, address, postal_code, city, country, region, hire_date, email_verified_at, password, locale, totp_secret, theme, primary_tenant_id, created_by, modified_by, created, modified, active from users where id = ? limit 1' ,
2026-02-04 23:31:53 +01:00
( string ) $id
);
return self :: unwrap ( $row );
}
public static function findByUuid ( string $uuid ) : ? array
{
$row = DB :: selectOne (
2026-02-11 19:28:12 +01:00
'select id, uuid, first_name, last_name, display_name, email, profile_description, job_title, phone, mobile, short_dial, address, postal_code, city, country, region, hire_date, email_verified_at, password, locale, totp_secret, theme, primary_tenant_id, created_by, modified_by, created, modified, active, active_changed_at, active_changed_by from users where uuid = ? limit 1' ,
2026-02-04 23:31:53 +01:00
$uuid
);
return self :: unwrap ( $row );
}
public static function findByEmail ( string $email ) : ? array
{
$row = DB :: selectOne (
2026-02-11 19:28:12 +01:00
'select id, uuid, first_name, last_name, display_name, email, profile_description, job_title, phone, mobile, short_dial, address, postal_code, city, country, region, hire_date, email_verified_at, email_verified_at, password, locale, totp_secret, theme, primary_tenant_id, created_by, modified_by, created, modified, active, active_changed_at, active_changed_by from users where email = ? limit 1' ,
2026-02-04 23:31:53 +01:00
$email
);
return self :: unwrap ( $row );
}
2026-02-11 19:28:12 +01:00
private static function buildDisplayName ( array $data ) : string
{
$first = trim (( string ) ( $data [ 'first_name' ] ? ? '' ));
$last = trim (( string ) ( $data [ 'last_name' ] ? ? '' ));
$name = trim ( $first . ' ' . $last );
if ( $name === '' ) {
$name = trim (( string ) ( $data [ 'email' ] ? ? '' ));
}
return $name ;
}
2026-02-04 23:31:53 +01:00
private static function uuidV4 () : string
{
$data = random_bytes ( 16 );
$data [ 6 ] = chr (( ord ( $data [ 6 ]) & 0x0f ) | 0x40 );
$data [ 8 ] = chr (( ord ( $data [ 8 ]) & 0x3f ) | 0x80 );
return vsprintf ( '%s%s-%s-%s-%s-%s%s%s' , str_split ( bin2hex ( $data ), 4 ));
}
public static function create ( array $data )
{
$hash = password_hash ( $data [ 'password' ], PASSWORD_DEFAULT );
return DB :: insert (
2026-02-11 19:28:12 +01:00
'insert into users (uuid, first_name, last_name, display_name, email, profile_description, job_title, phone, mobile, short_dial, address, postal_code, city, country, region, hire_date, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, created, active, active_changed_at, active_changed_by) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),?,?,?)' ,
2026-02-04 23:31:53 +01:00
$data [ 'uuid' ] ? ? self :: uuidV4 (),
$data [ 'first_name' ],
$data [ 'last_name' ],
2026-02-11 19:28:12 +01:00
self :: buildDisplayName ( $data ),
2026-02-04 23:31:53 +01:00
$data [ 'email' ],
$data [ 'profile_description' ] ? ? null ,
$data [ 'job_title' ] ? ? null ,
$data [ 'phone' ] ? ? null ,
$data [ 'mobile' ] ? ? null ,
$data [ 'short_dial' ] ? ? null ,
$data [ 'address' ] ? ? null ,
$data [ 'postal_code' ] ? ? null ,
$data [ 'city' ] ? ? null ,
$data [ 'country' ] ? ? null ,
$data [ 'region' ] ? ? null ,
$data [ 'hire_date' ] ? ? null ,
$hash ,
$data [ 'locale' ] ? ? null ,
$data [ 'totp_secret' ],
$data [ 'theme' ] ? ? 'light' ,
$data [ 'primary_tenant_id' ] ? ? null ,
$data [ 'current_tenant_id' ] ? ? $data [ 'primary_tenant_id' ] ? ? null ,
$data [ 'created_by' ] ? ? null ,
$data [ 'active' ],
$data [ 'active_changed_at' ] ? ? null ,
$data [ 'active_changed_by' ] ? ? null
);
}
public static function update ( int $id , array $data ) : bool
{
$fields = [
'first_name' => $data [ 'first_name' ],
'last_name' => $data [ 'last_name' ],
2026-02-11 19:28:12 +01:00
'display_name' => self :: buildDisplayName ( $data ),
2026-02-04 23:31:53 +01:00
'email' => $data [ 'email' ],
'profile_description' => $data [ 'profile_description' ] ? ? null ,
'job_title' => $data [ 'job_title' ] ? ? null ,
'phone' => $data [ 'phone' ] ? ? null ,
'mobile' => $data [ 'mobile' ] ? ? null ,
'short_dial' => $data [ 'short_dial' ] ? ? null ,
'address' => $data [ 'address' ] ? ? null ,
'postal_code' => $data [ 'postal_code' ] ? ? null ,
'city' => $data [ 'city' ] ? ? null ,
'country' => $data [ 'country' ] ? ? null ,
'region' => $data [ 'region' ] ? ? null ,
'hire_date' => $data [ 'hire_date' ] ? ? null ,
'totp_secret' => $data [ 'totp_secret' ],
'active' => $data [ 'active' ],
];
if ( array_key_exists ( 'locale' , $data )) {
$fields [ 'locale' ] = $data [ 'locale' ];
}
if ( array_key_exists ( 'theme' , $data )) {
$fields [ 'theme' ] = $data [ 'theme' ];
}
if ( array_key_exists ( 'primary_tenant_id' , $data )) {
$fields [ 'primary_tenant_id' ] = $data [ 'primary_tenant_id' ];
}
if ( array_key_exists ( 'current_tenant_id' , $data )) {
$fields [ 'current_tenant_id' ] = $data [ 'current_tenant_id' ];
}
if ( array_key_exists ( 'modified_by' , $data )) {
$fields [ 'modified_by' ] = $data [ 'modified_by' ];
}
if ( array_key_exists ( 'active_changed_at' , $data )) {
$fields [ 'active_changed_at' ] = $data [ 'active_changed_at' ];
}
if ( array_key_exists ( 'active_changed_by' , $data )) {
$fields [ 'active_changed_by' ] = $data [ 'active_changed_by' ];
}
if ( ! empty ( $data [ 'password' ])) {
$fields [ 'password' ] = password_hash ( $data [ 'password' ], PASSWORD_DEFAULT );
}
$setParts = [];
$params = [];
foreach ( $fields as $field => $value ) {
$setParts [] = sprintf ( '`%s` = ?' , $field );
$params [] = $value ;
}
$params [] = ( string ) $id ;
$query = 'update users set ' . implode ( ', ' , $setParts ) . ' where id = ?' ;
$result = DB :: update ( $query , ... $params );
return $result !== false ;
}
public static function setActive ( int $id , bool $active , ? int $changedBy = null ) : bool
{
$result = DB :: update (
'update users set active = ?, active_changed_at = NOW(), active_changed_by = ? where id = ?' ,
$active ? 1 : 0 ,
$changedBy ,
( string ) $id
);
return $result !== false ;
}
public static function setCurrentTenant ( int $id , int $tenantId ) : bool
{
$result = DB :: update (
'update users set current_tenant_id = ? where id = ?' ,
( string ) $tenantId ,
( string ) $id
);
return $result !== false ;
}
public static function setActiveByUuids ( array $uuids , bool $active , ? int $modifiedBy = null ) : bool
{
$uuids = array_values ( array_filter ( array_map ( 'trim' , $uuids )));
if ( ! $uuids ) {
return false ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $uuids ), '?' ));
$query = " update users set active = ?, modified_by = ?, active_changed_at = NOW(), active_changed_by = ? where uuid in ( $placeholders ) " ;
$params = array_merge ([ $active ? 1 : 0 , $modifiedBy , $modifiedBy ], $uuids );
$result = DB :: update ( $query , ... $params );
return $result !== false ;
}
public static function setLocale ( int $id , string $locale ) : bool
{
$result = DB :: update ( 'update users set locale = ? where id = ?' , $locale , ( string ) $id );
return $result !== false ;
}
public static function setTheme ( int $id , string $theme ) : bool
{
$result = DB :: update ( 'update users set theme = ? where id = ?' , $theme , ( string ) $id );
return $result !== false ;
}
public static function setPassword ( int $id , string $password ) : bool
{
$hash = password_hash ( $password , PASSWORD_DEFAULT );
$result = DB :: update ( 'update users set password = ?, modified_by = NULL where id = ?' , $hash , ( string ) $id );
return $result !== false ;
}
public static function setEmailVerified ( int $id ) : bool
{
$result = DB :: update ( 'update users set email_verified_at = NOW() where id = ?' , ( string ) $id );
return $result !== false ;
}
public static function delete ( int $id ) : bool
{
$result = DB :: delete ( 'delete from users where id = ?' , ( string ) $id );
return $result !== false ;
}
public static function deleteByUuids ( array $uuids ) : bool
{
$uuids = array_values ( array_filter ( array_map ( 'trim' , $uuids )));
if ( ! $uuids ) {
return false ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $uuids ), '?' ));
$query = " delete from users where uuid in ( $placeholders ) " ;
$result = DB :: delete ( $query , ... $uuids );
return $result !== false ;
}
private static function normalizeIdList ( $value ) : array
{
if ( is_string ( $value )) {
$value = array_filter ( array_map ( 'trim' , explode ( ',' , $value )));
} elseif ( ! is_array ( $value )) {
return [];
}
$ids = [];
foreach ( $value as $item ) {
if ( $item === '' || $item === null ) {
continue ;
}
$ids [] = ( int ) $item ;
}
$ids = array_values ( array_filter ( array_unique ( $ids ), static function ( $id ) {
return $id > 0 ;
}));
return $ids ;
}
}