instances added god may help
This commit is contained in:
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class PermissionRepository
|
||||
{
|
||||
public static function list(): array
|
||||
public function list(): array
|
||||
{
|
||||
$rows = DB::select('select id, `key`, description, active, is_system, created from permissions order by `key` asc');
|
||||
if (!is_array($rows)) {
|
||||
@@ -23,7 +23,7 @@ class PermissionRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function listActive(): array
|
||||
public function listActive(): array
|
||||
{
|
||||
$rows = DB::select(
|
||||
'select id, `key`, description, active, is_system, created from permissions where active = 1 order by `key` asc'
|
||||
@@ -41,7 +41,7 @@ class PermissionRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function listPaged(array $options): array
|
||||
public function listPaged(array $options): array
|
||||
{
|
||||
$search = trim((string) ($options['search'] ?? ''));
|
||||
$allowedOrder = [
|
||||
@@ -79,7 +79,7 @@ class PermissionRepository
|
||||
return ['data' => $list, 'total' => (int) $total];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, `key`, description, active, is_system, created from permissions where id = ? limit 1',
|
||||
@@ -89,7 +89,7 @@ class PermissionRepository
|
||||
return is_array($data) ? $data : null;
|
||||
}
|
||||
|
||||
public static function findByKey(string $key): ?array
|
||||
public function findByKey(string $key): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, `key`, description, active, is_system, created from permissions where `key` = ? limit 1',
|
||||
@@ -99,7 +99,7 @@ class PermissionRepository
|
||||
return is_array($data) ? $data : null;
|
||||
}
|
||||
|
||||
public static function create(array $data): ?int
|
||||
public function create(array $data): ?int
|
||||
{
|
||||
$key = trim((string) ($data['key'] ?? ''));
|
||||
$desc = trim((string) ($data['description'] ?? ''));
|
||||
@@ -115,7 +115,7 @@ class PermissionRepository
|
||||
return $result ? (int) $result : null;
|
||||
}
|
||||
|
||||
public static function update(int $id, array $data): bool
|
||||
public function update(int $id, array $data): bool
|
||||
{
|
||||
$key = trim((string) ($data['key'] ?? ''));
|
||||
$desc = trim((string) ($data['description'] ?? ''));
|
||||
@@ -132,7 +132,7 @@ class PermissionRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function delete(int $id): bool
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$result = DB::delete('delete from permissions where id = ?', (string) $id);
|
||||
return (bool) $result;
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class RolePermissionRepository
|
||||
{
|
||||
public static function listPermissionIdsByRoleId(int $roleId): array
|
||||
public function listPermissionIdsByRoleId(int $roleId): array
|
||||
{
|
||||
$rows = DB::select('select permission_id from role_permissions where role_id = ?', (string) $roleId);
|
||||
if (!is_array($rows)) {
|
||||
@@ -22,7 +22,7 @@ class RolePermissionRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function countPermissionsByRoleIds(array $roleIds): array
|
||||
public function countPermissionsByRoleIds(array $roleIds): array
|
||||
{
|
||||
$roleIds = array_values(array_unique(array_map('intval', $roleIds)));
|
||||
$roleIds = array_values(array_filter($roleIds, static fn ($id) => $id > 0));
|
||||
@@ -54,7 +54,7 @@ class RolePermissionRepository
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function replaceForRole(int $roleId, array $permissionIds): bool
|
||||
public function replaceForRole(int $roleId, array $permissionIds): bool
|
||||
{
|
||||
DB::delete('delete from role_permissions where role_id = ?', (string) $roleId);
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $permissionIds))));
|
||||
@@ -71,7 +71,7 @@ class RolePermissionRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function listRoleIdsByPermissionId(int $permissionId): array
|
||||
public function listRoleIdsByPermissionId(int $permissionId): array
|
||||
{
|
||||
$rows = DB::select('select role_id from role_permissions where permission_id = ?', (string) $permissionId);
|
||||
if (!is_array($rows)) {
|
||||
@@ -87,7 +87,7 @@ class RolePermissionRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function replaceForPermission(int $permissionId, array $roleIds): bool
|
||||
public function replaceForPermission(int $permissionId, array $roleIds): bool
|
||||
{
|
||||
DB::delete('delete from role_permissions where permission_id = ?', (string) $permissionId);
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $roleIds))));
|
||||
@@ -104,7 +104,7 @@ class RolePermissionRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function listPermissionKeysByRoleIds(array $roleIds): array
|
||||
public function listPermissionKeysByRoleIds(array $roleIds): array
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $roleIds))));
|
||||
if (!$ids) {
|
||||
@@ -132,7 +132,7 @@ class RolePermissionRepository
|
||||
return array_values(array_unique($keys));
|
||||
}
|
||||
|
||||
public static function listPermissionsWithRolesByRoleIds(array $roleIds): array
|
||||
public function listPermissionsWithRolesByRoleIds(array $roleIds): array
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $roleIds))));
|
||||
if (!$ids) {
|
||||
@@ -179,7 +179,7 @@ class RolePermissionRepository
|
||||
return array_values($permMap);
|
||||
}
|
||||
|
||||
private static function extractIntField(array $row, string $field): int
|
||||
private function extractIntField(array $row, string $field): int
|
||||
{
|
||||
foreach ($row as $value) {
|
||||
if (!is_array($value)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class RoleRepository
|
||||
{
|
||||
private static function unwrap(?array $row): ?array
|
||||
private function unwrap(?array $row): ?array
|
||||
{
|
||||
if (!$row) {
|
||||
return null;
|
||||
@@ -15,7 +15,7 @@ class RoleRepository
|
||||
return $row['roles'] ?? null;
|
||||
}
|
||||
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -30,23 +30,23 @@ class RoleRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function list(): array
|
||||
public function list(): array
|
||||
{
|
||||
$rows = DB::select(
|
||||
'select id, uuid, description, code, active, created_by, modified_by, created, modified from roles order by id desc'
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listActive(): array
|
||||
public function listActive(): array
|
||||
{
|
||||
$rows = DB::select(
|
||||
'select id, uuid, description, code, active, created_by, modified_by, created, modified from roles where active = 1 order by description asc'
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listByIds(array $roleIds): array
|
||||
public function listByIds(array $roleIds): array
|
||||
{
|
||||
$roleIds = array_values(array_unique(array_map('intval', $roleIds)));
|
||||
$roleIds = array_values(array_filter($roleIds, static fn ($id) => $id > 0));
|
||||
@@ -59,10 +59,10 @@ class RoleRepository
|
||||
'select id, uuid, description, code, active, created_by, modified_by, created, modified from roles where id in (' . $placeholders . ')',
|
||||
...array_map('strval', $roleIds)
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listIds(): array
|
||||
public function listIds(): array
|
||||
{
|
||||
$rows = DB::select('select id from roles');
|
||||
if (!is_array($rows)) {
|
||||
@@ -78,7 +78,7 @@ class RoleRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listActiveIds(): array
|
||||
public function listActiveIds(): array
|
||||
{
|
||||
$rows = DB::select('select id from roles where active = 1');
|
||||
if (!is_array($rows)) {
|
||||
@@ -94,7 +94,7 @@ class RoleRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listPaged(array $options): array
|
||||
public function listPaged(array $options): array
|
||||
{
|
||||
$search = trim((string) ($options['search'] ?? ''));
|
||||
$allowedOrder = ['id', 'uuid', 'description', 'code', 'active', 'created', 'modified'];
|
||||
@@ -123,29 +123,29 @@ class RoleRepository
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'rows' => self::unwrapList($rows),
|
||||
'rows' => $this->unwrapList($rows),
|
||||
];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, description, code, active, created_by, modified_by, created, modified from roles where id = ? limit 1',
|
||||
(string) $id
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function findByUuid(string $uuid): ?array
|
||||
public function findByUuid(string $uuid): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, description, code, active, created_by, modified_by, created, modified from roles where uuid = ? limit 1',
|
||||
$uuid
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function existsByCode(string $code, int $excludeId = 0): bool
|
||||
public function existsByCode(string $code, int $excludeId = 0): bool
|
||||
{
|
||||
$code = trim($code);
|
||||
if ($code === '') {
|
||||
@@ -159,7 +159,7 @@ class RoleRepository
|
||||
return $count ? ((int) $count > 0) : false;
|
||||
}
|
||||
|
||||
public static function create(array $data)
|
||||
public function create(array $data)
|
||||
{
|
||||
return DB::insert(
|
||||
'insert into roles (uuid, description, code, active, created_by, created) values (?,?,?,?,?,NOW())',
|
||||
@@ -171,7 +171,7 @@ class RoleRepository
|
||||
);
|
||||
}
|
||||
|
||||
public static function update(int $id, array $data): bool
|
||||
public function update(int $id, array $data): bool
|
||||
{
|
||||
$fields = [
|
||||
'description' => $data['description'],
|
||||
@@ -195,7 +195,7 @@ class RoleRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function delete(int $id): bool
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$result = DB::delete('delete from roles where id = ?', (string) $id);
|
||||
return $result !== false;
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class UserRoleRepository
|
||||
{
|
||||
public static function listRoleIdsByUserId(int $userId): array
|
||||
public function listRoleIdsByUserId(int $userId): array
|
||||
{
|
||||
$rows = DB::select('select role_id from user_roles where user_id = ?', (string) $userId);
|
||||
if (!is_array($rows)) {
|
||||
@@ -22,7 +22,7 @@ class UserRoleRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function replaceForUser(int $userId, array $roleIds): bool
|
||||
public function replaceForUser(int $userId, array $roleIds): bool
|
||||
{
|
||||
DB::delete('delete from user_roles where user_id = ?', (string) $userId);
|
||||
if (!$roleIds) {
|
||||
@@ -40,17 +40,17 @@ class UserRoleRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function countUsersByRoleIds(array $roleIds): array
|
||||
public function countUsersByRoleIds(array $roleIds): array
|
||||
{
|
||||
return self::countByRoleIds($roleIds, false);
|
||||
return $this->countByRoleIds($roleIds, false);
|
||||
}
|
||||
|
||||
public static function countActiveUsersByRoleIds(array $roleIds): array
|
||||
public function countActiveUsersByRoleIds(array $roleIds): array
|
||||
{
|
||||
return self::countByRoleIds($roleIds, true);
|
||||
return $this->countByRoleIds($roleIds, true);
|
||||
}
|
||||
|
||||
private static function countByRoleIds(array $roleIds, bool $activeOnly): array
|
||||
private function countByRoleIds(array $roleIds, bool $activeOnly): array
|
||||
{
|
||||
$roleIds = array_values(array_unique(array_map('intval', $roleIds)));
|
||||
$roleIds = array_values(array_filter($roleIds, static fn ($id) => $id > 0));
|
||||
@@ -73,17 +73,17 @@ class UserRoleRepository
|
||||
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$roleId = self::extractIntField($row, 'role_id');
|
||||
$roleId = $this->extractIntField($row, 'role_id');
|
||||
if ($roleId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$result[$roleId] = self::extractIntField($row, 'user_count');
|
||||
$result[$roleId] = $this->extractIntField($row, 'user_count');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function extractIntField(array $row, string $field): int
|
||||
private function extractIntField(array $row, string $field): int
|
||||
{
|
||||
foreach ($row as $value) {
|
||||
if (!is_array($value)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ApiAuditLogRepository
|
||||
{
|
||||
public static function create(array $data): int|false
|
||||
public function create(array $data): int|false
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into api_audit_log (
|
||||
@@ -32,7 +32,7 @@ class ApiAuditLogRepository
|
||||
return $id ? (int) $id : false;
|
||||
}
|
||||
|
||||
public static function listPaged(array $filters): array
|
||||
public function listPaged(array $filters): array
|
||||
{
|
||||
$search = trim((string) ($filters['search'] ?? ''));
|
||||
$status = strtolower(trim((string) ($filters['status'] ?? '')));
|
||||
@@ -134,7 +134,7 @@ class ApiAuditLogRepository
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = self::normalizeRow($row);
|
||||
$item = $this->normalizeRow($row);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
@@ -147,7 +147,7 @@ class ApiAuditLogRepository
|
||||
];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select
|
||||
@@ -181,10 +181,10 @@ class ApiAuditLogRepository
|
||||
(string) $id
|
||||
);
|
||||
|
||||
return self::normalizeRow($row);
|
||||
return $this->normalizeRow($row);
|
||||
}
|
||||
|
||||
public static function purgeOlderThanDays(int $days): int
|
||||
public function purgeOlderThanDays(int $days): int
|
||||
{
|
||||
if ($days <= 0) {
|
||||
return 0;
|
||||
@@ -197,7 +197,7 @@ class ApiAuditLogRepository
|
||||
return is_int($deleted) ? $deleted : 0;
|
||||
}
|
||||
|
||||
private static function normalizeRow(mixed $row): ?array
|
||||
private function normalizeRow(mixed $row): ?array
|
||||
{
|
||||
if (!is_array($row)) {
|
||||
return null;
|
||||
@@ -220,4 +220,3 @@ class ApiAuditLogRepository
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ImportAuditRunRepository
|
||||
{
|
||||
public static function createRunning(array $data): int|false
|
||||
public function createRunning(array $data): int|false
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into import_audit_runs (
|
||||
@@ -25,7 +25,7 @@ class ImportAuditRunRepository
|
||||
return $id ? (int) $id : false;
|
||||
}
|
||||
|
||||
public static function finishById(int $id, array $data): bool
|
||||
public function finishById(int $id, array $data): bool
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return false;
|
||||
@@ -55,7 +55,7 @@ class ImportAuditRunRepository
|
||||
return (int) $updated > 0;
|
||||
}
|
||||
|
||||
public static function listPaged(array $filters): array
|
||||
public function listPaged(array $filters): array
|
||||
{
|
||||
$search = trim((string) ($filters['search'] ?? ''));
|
||||
$profileKey = strtolower(trim((string) ($filters['profile_key'] ?? '')));
|
||||
@@ -157,7 +157,7 @@ class ImportAuditRunRepository
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = self::normalizeRow($row);
|
||||
$item = $this->normalizeRow($row);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
@@ -170,7 +170,7 @@ class ImportAuditRunRepository
|
||||
];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
@@ -209,10 +209,10 @@ class ImportAuditRunRepository
|
||||
(string) $id
|
||||
);
|
||||
|
||||
return self::normalizeRow($row);
|
||||
return $this->normalizeRow($row);
|
||||
}
|
||||
|
||||
public static function purgeOlderThanDays(int $days): int
|
||||
public function purgeOlderThanDays(int $days): int
|
||||
{
|
||||
if ($days <= 0) {
|
||||
return 0;
|
||||
@@ -226,7 +226,7 @@ class ImportAuditRunRepository
|
||||
return is_int($deleted) ? $deleted : 0;
|
||||
}
|
||||
|
||||
private static function normalizeRow(mixed $row): ?array
|
||||
private function normalizeRow(mixed $row): ?array
|
||||
{
|
||||
if (!is_array($row)) {
|
||||
return null;
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class UserLifecycleAuditRepository
|
||||
{
|
||||
public static function create(array $row): int|false
|
||||
public function create(array $row): int|false
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into user_lifecycle_audit_log (
|
||||
@@ -33,7 +33,7 @@ class UserLifecycleAuditRepository
|
||||
return $id ? (int) $id : false;
|
||||
}
|
||||
|
||||
public static function updateStatus(int $id, string $status, ?string $reasonCode = null): bool
|
||||
public function updateStatus(int $id, string $status, ?string $reasonCode = null): bool
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return false;
|
||||
@@ -52,7 +52,7 @@ class UserLifecycleAuditRepository
|
||||
return $updated !== false;
|
||||
}
|
||||
|
||||
public static function listPaged(array $filters): array
|
||||
public function listPaged(array $filters): array
|
||||
{
|
||||
$search = trim((string) ($filters['search'] ?? ''));
|
||||
$action = strtolower(trim((string) ($filters['action'] ?? '')));
|
||||
@@ -147,7 +147,7 @@ class UserLifecycleAuditRepository
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = self::normalizeRow($row, false);
|
||||
$item = $this->normalizeRow($row, false);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
@@ -157,7 +157,7 @@ class UserLifecycleAuditRepository
|
||||
return ['total' => $total, 'rows' => $normalized];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
@@ -201,10 +201,10 @@ class UserLifecycleAuditRepository
|
||||
(string) $id
|
||||
);
|
||||
|
||||
return self::normalizeRow($row, true);
|
||||
return $this->normalizeRow($row, true);
|
||||
}
|
||||
|
||||
public static function findDeleteEventForRestore(int $id, bool $forUpdate = false): ?array
|
||||
public function findDeleteEventForRestore(int $id, bool $forUpdate = false): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
@@ -233,7 +233,7 @@ class UserLifecycleAuditRepository
|
||||
return is_array($item) ? $item : null;
|
||||
}
|
||||
|
||||
public static function markRestored(int $id, int $restoredBy, int $restoredUserId): bool
|
||||
public function markRestored(int $id, int $restoredBy, int $restoredUserId): bool
|
||||
{
|
||||
if ($id <= 0 || $restoredBy <= 0 || $restoredUserId <= 0) {
|
||||
return false;
|
||||
@@ -251,7 +251,7 @@ class UserLifecycleAuditRepository
|
||||
return (int) $updated > 0;
|
||||
}
|
||||
|
||||
public static function purgeOlderThanDays(int $days): int
|
||||
public function purgeOlderThanDays(int $days): int
|
||||
{
|
||||
if ($days <= 0) {
|
||||
return 0;
|
||||
@@ -264,7 +264,7 @@ class UserLifecycleAuditRepository
|
||||
return is_int($deleted) ? $deleted : 0;
|
||||
}
|
||||
|
||||
private static function normalizeRow(mixed $row, bool $includeSnapshot): ?array
|
||||
private function normalizeRow(mixed $row, bool $includeSnapshot): ?array
|
||||
{
|
||||
if (!is_array($row)) {
|
||||
return null;
|
||||
@@ -294,4 +294,3 @@ class UserLifecycleAuditRepository
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class ApiTokenRepository
|
||||
{
|
||||
private const UUID_REGEX = '/^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i';
|
||||
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -24,12 +24,12 @@ class ApiTokenRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function isUuid(string $value): bool
|
||||
public function isUuid(string $value): bool
|
||||
{
|
||||
return (bool) preg_match(self::UUID_REGEX, trim($value));
|
||||
}
|
||||
|
||||
public static function create(
|
||||
public function create(
|
||||
int $userId,
|
||||
string $name,
|
||||
string $selector,
|
||||
@@ -52,7 +52,7 @@ class ApiTokenRepository
|
||||
return $id ? (int) $id : null;
|
||||
}
|
||||
|
||||
public static function findBySelector(string $selector): ?array
|
||||
public function findBySelector(string $selector): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, user_id, name, selector, token_hash, tenant_id, last_used_at, last_ip, expires_at, revoked_at, created_by, created from user_api_tokens where selector = ? limit 1',
|
||||
@@ -64,7 +64,7 @@ class ApiTokenRepository
|
||||
return $row['user_api_tokens'];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, user_id, name, selector, tenant_id, last_used_at, last_ip, expires_at, revoked_at, created_by, created from user_api_tokens where id = ? limit 1',
|
||||
@@ -76,10 +76,10 @@ class ApiTokenRepository
|
||||
return $row['user_api_tokens'];
|
||||
}
|
||||
|
||||
public static function findByUuid(string $uuid): ?array
|
||||
public function findByUuid(string $uuid): ?array
|
||||
{
|
||||
$uuid = trim($uuid);
|
||||
if (!self::isUuid($uuid)) {
|
||||
if (!$this->isUuid($uuid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -93,10 +93,10 @@ class ApiTokenRepository
|
||||
return $row['user_api_tokens'];
|
||||
}
|
||||
|
||||
public static function findByUuidForUser(string $uuid, int $userId): ?array
|
||||
public function findByUuidForUser(string $uuid, int $userId): ?array
|
||||
{
|
||||
$uuid = trim($uuid);
|
||||
if ($userId <= 0 || !self::isUuid($uuid)) {
|
||||
if ($userId <= 0 || !$this->isUuid($uuid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class ApiTokenRepository
|
||||
return $row['user_api_tokens'];
|
||||
}
|
||||
|
||||
public static function updateLastUsed(int $id, string $ip): bool
|
||||
public function updateLastUsed(int $id, string $ip): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update user_api_tokens set last_used_at = NOW(), last_ip = ? where id = ?',
|
||||
@@ -121,7 +121,7 @@ class ApiTokenRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function revoke(int $id): bool
|
||||
public function revoke(int $id): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update user_api_tokens set revoked_at = NOW() where id = ? and revoked_at is null',
|
||||
@@ -130,10 +130,10 @@ class ApiTokenRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function revokeByUuidForUser(string $uuid, int $userId): bool
|
||||
public function revokeByUuidForUser(string $uuid, int $userId): bool
|
||||
{
|
||||
$uuid = trim($uuid);
|
||||
if ($userId <= 0 || !self::isUuid($uuid)) {
|
||||
if ($userId <= 0 || !$this->isUuid($uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class ApiTokenRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function revokeAllForUser(int $userId, ?int $tenantId = null): int
|
||||
public function revokeAllForUser(int $userId, ?int $tenantId = null): int
|
||||
{
|
||||
if ($tenantId !== null && $tenantId > 0) {
|
||||
$result = DB::update(
|
||||
@@ -162,7 +162,7 @@ class ApiTokenRepository
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public static function revokeAllActiveByAdmin(): int
|
||||
public function revokeAllActiveByAdmin(): int
|
||||
{
|
||||
$result = DB::update(
|
||||
'update user_api_tokens set revoked_at = NOW() where revoked_at is null and (expires_at is null or expires_at > NOW())'
|
||||
@@ -170,7 +170,7 @@ class ApiTokenRepository
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public static function listByUserId(int $userId, int $limit = 25): array
|
||||
public function listByUserId(int $userId, int $limit = 25): array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return [];
|
||||
@@ -185,10 +185,10 @@ class ApiTokenRepository
|
||||
(string) $userId,
|
||||
(string) $limit
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function countActiveForUser(int $userId): int
|
||||
public function countActiveForUser(int $userId): int
|
||||
{
|
||||
$count = DB::selectValue(
|
||||
'select count(*) from user_api_tokens where user_id = ? and revoked_at is null and (expires_at is null or expires_at > NOW())',
|
||||
@@ -197,7 +197,7 @@ class ApiTokenRepository
|
||||
return $count ? (int) $count : 0;
|
||||
}
|
||||
|
||||
public static function countActiveForUserExcludingId(int $userId, int $excludeId): int
|
||||
public function countActiveForUserExcludingId(int $userId, int $excludeId): int
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return 0;
|
||||
@@ -211,7 +211,7 @@ class ApiTokenRepository
|
||||
return $count ? (int) $count : 0;
|
||||
}
|
||||
|
||||
public static function countActive(): int
|
||||
public function countActive(): int
|
||||
{
|
||||
$count = DB::selectValue(
|
||||
'select count(*) from user_api_tokens where revoked_at is null and (expires_at is null or expires_at > NOW())'
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class EmailVerificationRepository
|
||||
{
|
||||
public static function create(int $userId, string $codeHash, string $expiresAt): ?int
|
||||
public function create(int $userId, string $codeHash, string $expiresAt): ?int
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into email_verifications (user_id, code_hash, expires_at, attempts, used_at, created) values (?,?,?,?,NULL,NOW())',
|
||||
@@ -18,7 +18,7 @@ class EmailVerificationRepository
|
||||
return $id ? (int) $id : null;
|
||||
}
|
||||
|
||||
public static function invalidateForUser(int $userId): bool
|
||||
public function invalidateForUser(int $userId): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update email_verifications set used_at = NOW() where user_id = ? and used_at is null',
|
||||
@@ -27,7 +27,7 @@ class EmailVerificationRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function findActiveByUserId(int $userId): ?array
|
||||
public function findActiveByUserId(int $userId): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, code_hash, expires_at, attempts, used_at from email_verifications where user_id = ? and used_at is null and expires_at > UTC_TIMESTAMP() order by id desc limit 1',
|
||||
@@ -39,7 +39,7 @@ class EmailVerificationRepository
|
||||
return $row['email_verifications'];
|
||||
}
|
||||
|
||||
public static function findById(int $id): ?array
|
||||
public function findById(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, code_hash, expires_at, attempts, used_at from email_verifications where id = ? limit 1',
|
||||
@@ -51,7 +51,7 @@ class EmailVerificationRepository
|
||||
return $row['email_verifications'];
|
||||
}
|
||||
|
||||
public static function incrementAttempts(int $id): bool
|
||||
public function incrementAttempts(int $id): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update email_verifications set attempts = attempts + 1 where id = ?',
|
||||
@@ -60,7 +60,7 @@ class EmailVerificationRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function markUsed(int $id): bool
|
||||
public function markUsed(int $id): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update email_verifications set used_at = NOW() where id = ?',
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class PasswordResetRepository
|
||||
{
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -21,7 +21,7 @@ class PasswordResetRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function create(int $userId, string $codeHash, string $expiresAt): ?int
|
||||
public function create(int $userId, string $codeHash, string $expiresAt): ?int
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into password_resets (user_id, code_hash, expires_at, attempts, used_at, created) values (?,?,?,?,NULL,NOW())',
|
||||
@@ -33,7 +33,7 @@ class PasswordResetRepository
|
||||
return $id ? (int) $id : null;
|
||||
}
|
||||
|
||||
public static function invalidateForUser(int $userId): bool
|
||||
public function invalidateForUser(int $userId): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update password_resets set used_at = NOW() where user_id = ? and used_at is null',
|
||||
@@ -42,7 +42,7 @@ class PasswordResetRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function findActiveByUserId(int $userId): ?array
|
||||
public function findActiveByUserId(int $userId): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, code_hash, expires_at, attempts, used_at from password_resets where user_id = ? and used_at is null and expires_at > UTC_TIMESTAMP() order by id desc limit 1',
|
||||
@@ -54,7 +54,7 @@ class PasswordResetRepository
|
||||
return $row['password_resets'];
|
||||
}
|
||||
|
||||
public static function findById(int $id): ?array
|
||||
public function findById(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, code_hash, expires_at, attempts, used_at from password_resets where id = ? limit 1',
|
||||
@@ -66,7 +66,7 @@ class PasswordResetRepository
|
||||
return $row['password_resets'];
|
||||
}
|
||||
|
||||
public static function incrementAttempts(int $id): bool
|
||||
public function incrementAttempts(int $id): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update password_resets set attempts = attempts + 1 where id = ?',
|
||||
@@ -75,7 +75,7 @@ class PasswordResetRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function markUsed(int $id): bool
|
||||
public function markUsed(int $id): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update password_resets set used_at = NOW() where id = ?',
|
||||
@@ -84,7 +84,7 @@ class PasswordResetRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function listByUserId(int $userId, int $limit = 20): array
|
||||
public function listByUserId(int $userId, int $limit = 20): array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return [];
|
||||
@@ -99,6 +99,6 @@ class PasswordResetRepository
|
||||
(string) $userId,
|
||||
(string) $limit
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class RememberTokenRepository
|
||||
{
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -21,7 +21,7 @@ class RememberTokenRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function create(int $userId, string $selector, string $tokenHash, string $expiresAt): ?int
|
||||
public function create(int $userId, string $selector, string $tokenHash, string $expiresAt): ?int
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into user_remember_tokens (user_id, selector, token_hash, expires_at, created) values (?,?,?,?,NOW())',
|
||||
@@ -33,7 +33,7 @@ class RememberTokenRepository
|
||||
return $id ? (int) $id : null;
|
||||
}
|
||||
|
||||
public static function findBySelector(string $selector): ?array
|
||||
public function findBySelector(string $selector): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, selector, token_hash, expires_at, expired_by_admin_at, last_used from user_remember_tokens where selector = ? limit 1',
|
||||
@@ -45,7 +45,7 @@ class RememberTokenRepository
|
||||
return $row['user_remember_tokens'];
|
||||
}
|
||||
|
||||
public static function updateToken(int $id, string $tokenHash, string $expiresAt): bool
|
||||
public function updateToken(int $id, string $tokenHash, string $expiresAt): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update user_remember_tokens set token_hash = ?, expires_at = ?, expired_by_admin_at = NULL, last_used = NOW() where id = ?',
|
||||
@@ -56,7 +56,7 @@ class RememberTokenRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function expireAllByAdmin(): int
|
||||
public function expireAllByAdmin(): int
|
||||
{
|
||||
$result = DB::update(
|
||||
'update user_remember_tokens set expires_at = NOW(), expired_by_admin_at = NOW() where expires_at > NOW()'
|
||||
@@ -64,19 +64,19 @@ class RememberTokenRepository
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public static function deleteById(int $id): bool
|
||||
public function deleteById(int $id): bool
|
||||
{
|
||||
$result = DB::delete('delete from user_remember_tokens where id = ?', (string) $id);
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function deleteByUserId(int $userId): bool
|
||||
public function deleteByUserId(int $userId): bool
|
||||
{
|
||||
$result = DB::delete('delete from user_remember_tokens where user_id = ?', (string) $userId);
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function listByUserId(int $userId, int $limit = 20): array
|
||||
public function listByUserId(int $userId, int $limit = 20): array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return [];
|
||||
@@ -91,10 +91,10 @@ class RememberTokenRepository
|
||||
(string) $userId,
|
||||
(string) $limit
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function countActive(): int
|
||||
public function countActive(): int
|
||||
{
|
||||
$count = DB::selectValue('select count(*) from user_remember_tokens where expires_at > NOW()');
|
||||
return $count ? (int) $count : 0;
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class MailLogRepository
|
||||
{
|
||||
public static function create(array $data): ?int
|
||||
public function create(array $data): ?int
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into mail_log (to_email, subject, template, status, created_at) values (?,?,?,?,NOW())',
|
||||
@@ -19,7 +19,7 @@ class MailLogRepository
|
||||
return $id ? (int) $id : null;
|
||||
}
|
||||
|
||||
public static function markSent(int $id, ?string $providerMessageId = null): bool
|
||||
public function markSent(int $id, ?string $providerMessageId = null): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update mail_log set status = ?, sent_at = NOW(), provider_message_id = ?, error_message = NULL where id = ?',
|
||||
@@ -30,7 +30,7 @@ class MailLogRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function markFailed(int $id, string $errorMessage): bool
|
||||
public function markFailed(int $id, string $errorMessage): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'update mail_log set status = ?, error_message = ? where id = ?',
|
||||
@@ -41,30 +41,7 @@ class MailLogRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
private static function unwrap(?array $row): ?array
|
||||
{
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
return $row['mail_log'] ?? null;
|
||||
}
|
||||
|
||||
private static function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$mailLog = $row['mail_log'] ?? null;
|
||||
if (is_array($mailLog)) {
|
||||
$list[] = $mailLog;
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function listPaged(array $options): array
|
||||
public function listPaged(array $options): array
|
||||
{
|
||||
$search = trim((string) ($options['search'] ?? ''));
|
||||
$status = trim((string) ($options['status'] ?? ''));
|
||||
@@ -101,16 +78,41 @@ class MailLogRepository
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'rows' => self::unwrapList($rows),
|
||||
'rows' => $this->unwrapList($rows),
|
||||
];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, to_email, subject, template, status, created_at, sent_at, error_message, provider_message_id from mail_log where id = ? limit 1',
|
||||
(string) $id
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
private function unwrap(?array $row): ?array
|
||||
{
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
return $row['mail_log'] ?? null;
|
||||
}
|
||||
|
||||
private function unwrapList(mixed $rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$mailLog = $row['mail_log'] ?? null;
|
||||
if (is_array($mailLog)) {
|
||||
$list[] = $mailLog;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class DepartmentRepository
|
||||
{
|
||||
private static function unwrap(?array $row): ?array
|
||||
private function unwrap(?array $row): ?array
|
||||
{
|
||||
if (!$row) {
|
||||
return null;
|
||||
@@ -15,7 +15,7 @@ class DepartmentRepository
|
||||
return $row['departments'] ?? null;
|
||||
}
|
||||
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -30,15 +30,15 @@ class DepartmentRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function list(): array
|
||||
public function list(): array
|
||||
{
|
||||
$rows = DB::select(
|
||||
'select id, uuid, description, tenant_id, code, cost_center, active, created_by, modified_by, created, modified from departments order by id desc'
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listIds(): array
|
||||
public function listIds(): array
|
||||
{
|
||||
$rows = DB::select('select id from departments');
|
||||
if (!is_array($rows)) {
|
||||
@@ -54,7 +54,7 @@ class DepartmentRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listActiveIdsByTenantIds(array $tenantIds): array
|
||||
public function listActiveIdsByTenantIds(array $tenantIds): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
$tenantIds = array_filter($tenantIds, static fn ($id) => $id > 0);
|
||||
@@ -79,7 +79,7 @@ class DepartmentRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listByTenantIds(array $tenantIds): array
|
||||
public function listByTenantIds(array $tenantIds): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
$tenantIds = array_filter($tenantIds, static fn ($id) => $id > 0);
|
||||
@@ -94,10 +94,10 @@ class DepartmentRepository
|
||||
'order by departments.description asc',
|
||||
...array_map('strval', $tenantIds)
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listByIds(array $departmentIds, bool $includeInactive = false): array
|
||||
public function listByIds(array $departmentIds, bool $includeInactive = false): array
|
||||
{
|
||||
$departmentIds = array_values(array_unique(array_map('intval', $departmentIds)));
|
||||
$departmentIds = array_filter($departmentIds, static fn ($id) => $id > 0);
|
||||
@@ -110,10 +110,10 @@ class DepartmentRepository
|
||||
'select id, uuid, description, tenant_id, code, cost_center, active, created_by, modified_by, created, modified from departments where ' . $activeSql . 'id in (' . $placeholders . ') order by description asc',
|
||||
...array_map('strval', $departmentIds)
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listPaged(array $options): array
|
||||
public function listPaged(array $options): array
|
||||
{
|
||||
$search = trim((string) ($options['search'] ?? ''));
|
||||
$tenant = trim((string) ($options['tenant'] ?? ''));
|
||||
@@ -171,7 +171,7 @@ class DepartmentRepository
|
||||
$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 = $this->unwrapList($rows);
|
||||
$ids = [];
|
||||
foreach ($list as $department) {
|
||||
if (isset($department['id'])) {
|
||||
@@ -217,25 +217,25 @@ class DepartmentRepository
|
||||
];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, description, tenant_id, code, cost_center, active, created_by, modified_by, created, modified from departments where id = ? limit 1',
|
||||
(string) $id
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function findByUuid(string $uuid): ?array
|
||||
public function findByUuid(string $uuid): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, description, tenant_id, code, cost_center, active, created_by, modified_by, created, modified from departments where uuid = ? limit 1',
|
||||
$uuid
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function existsByCode(string $code, int $excludeId = 0): bool
|
||||
public function existsByCode(string $code, int $excludeId = 0): bool
|
||||
{
|
||||
$code = trim($code);
|
||||
if ($code === '') {
|
||||
@@ -249,7 +249,7 @@ class DepartmentRepository
|
||||
return (int) $count > 0;
|
||||
}
|
||||
|
||||
public static function existsByTenantAndDescription(int $tenantId, string $description, int $excludeId = 0): bool
|
||||
public function existsByTenantAndDescription(int $tenantId, string $description, int $excludeId = 0): bool
|
||||
{
|
||||
$tenantId = (int) $tenantId;
|
||||
$description = trim($description);
|
||||
@@ -275,7 +275,7 @@ class DepartmentRepository
|
||||
return (int) $count > 0;
|
||||
}
|
||||
|
||||
public static function countByTenantId(int $tenantId): int
|
||||
public function countByTenantId(int $tenantId): int
|
||||
{
|
||||
if ($tenantId <= 0) {
|
||||
return 0;
|
||||
@@ -284,7 +284,7 @@ class DepartmentRepository
|
||||
return $count ? (int) $count : 0;
|
||||
}
|
||||
|
||||
public static function create(array $data)
|
||||
public function create(array $data)
|
||||
{
|
||||
return DB::insert(
|
||||
'insert into departments (uuid, description, tenant_id, code, cost_center, active, created_by, created) values (?,?,?,?,?,?,?,NOW())',
|
||||
@@ -298,7 +298,7 @@ class DepartmentRepository
|
||||
);
|
||||
}
|
||||
|
||||
public static function update(int $id, array $data): bool
|
||||
public function update(int $id, array $data): bool
|
||||
{
|
||||
$fields = [
|
||||
'description' => $data['description'],
|
||||
@@ -324,7 +324,7 @@ class DepartmentRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function setTenant(int $id, int $tenantId): bool
|
||||
public function setTenant(int $id, int $tenantId): bool
|
||||
{
|
||||
if ($id <= 0 || $tenantId <= 0) {
|
||||
return false;
|
||||
@@ -337,7 +337,7 @@ class DepartmentRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function delete(int $id): bool
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$result = DB::delete('delete from departments where id = ?', (string) $id);
|
||||
return $result !== false;
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class UserDepartmentRepository
|
||||
{
|
||||
public static function listDepartmentIdsByUserId(int $userId): array
|
||||
public function listDepartmentIdsByUserId(int $userId): array
|
||||
{
|
||||
$rows = DB::select('select department_id from user_departments where user_id = ?', (string) $userId);
|
||||
if (!is_array($rows)) {
|
||||
@@ -22,7 +22,7 @@ class UserDepartmentRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function replaceForUser(int $userId, array $departmentIds): bool
|
||||
public function replaceForUser(int $userId, array $departmentIds): bool
|
||||
{
|
||||
DB::delete('delete from user_departments where user_id = ?', (string) $userId);
|
||||
if (!$departmentIds) {
|
||||
@@ -40,7 +40,7 @@ class UserDepartmentRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function removeInvalidForDepartment(int $departmentId): int
|
||||
public function removeInvalidForDepartment(int $departmentId): int
|
||||
{
|
||||
$query = 'delete ud from user_departments ud ' .
|
||||
'where ud.department_id = ? and not exists (' .
|
||||
@@ -52,17 +52,17 @@ class UserDepartmentRepository
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public static function countUsersByDepartmentIds(array $departmentIds): array
|
||||
public function countUsersByDepartmentIds(array $departmentIds): array
|
||||
{
|
||||
return self::countByDepartmentIds($departmentIds, false);
|
||||
return $this->countByDepartmentIds($departmentIds, false);
|
||||
}
|
||||
|
||||
public static function countActiveUsersByDepartmentIds(array $departmentIds): array
|
||||
public function countActiveUsersByDepartmentIds(array $departmentIds): array
|
||||
{
|
||||
return self::countByDepartmentIds($departmentIds, true);
|
||||
return $this->countByDepartmentIds($departmentIds, true);
|
||||
}
|
||||
|
||||
private static function countByDepartmentIds(array $departmentIds, bool $activeOnly): array
|
||||
private function countByDepartmentIds(array $departmentIds, bool $activeOnly): array
|
||||
{
|
||||
$departmentIds = array_values(array_unique(array_map('intval', $departmentIds)));
|
||||
$departmentIds = array_values(array_filter($departmentIds, static fn ($id) => $id > 0));
|
||||
@@ -85,17 +85,17 @@ class UserDepartmentRepository
|
||||
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$departmentId = self::extractIntField($row, 'department_id');
|
||||
$departmentId = $this->extractIntField($row, 'department_id');
|
||||
if ($departmentId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$result[$departmentId] = self::extractIntField($row, 'user_count');
|
||||
$result[$departmentId] = $this->extractIntField($row, 'user_count');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function extractIntField(array $row, string $field): int
|
||||
private function extractIntField(array $row, string $field): int
|
||||
{
|
||||
foreach ($row as $value) {
|
||||
if (!is_array($value)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ScheduledJobRepository
|
||||
{
|
||||
public static function create(array $data): int|false
|
||||
public function create(array $data): int|false
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into scheduled_jobs (
|
||||
@@ -30,26 +30,26 @@ class ScheduledJobRepository
|
||||
return $id ? (int) $id : false;
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return null;
|
||||
}
|
||||
$row = DB::selectOne('select * from scheduled_jobs where id = ? limit 1', (string) $id);
|
||||
return self::normalizeRow($row);
|
||||
return $this->normalizeRow($row);
|
||||
}
|
||||
|
||||
public static function findByKey(string $jobKey): ?array
|
||||
public function findByKey(string $jobKey): ?array
|
||||
{
|
||||
$jobKey = trim($jobKey);
|
||||
if ($jobKey === '') {
|
||||
return null;
|
||||
}
|
||||
$row = DB::selectOne('select * from scheduled_jobs where job_key = ? limit 1', $jobKey);
|
||||
return self::normalizeRow($row);
|
||||
return $this->normalizeRow($row);
|
||||
}
|
||||
|
||||
public static function listPaged(array $filters): array
|
||||
public function listPaged(array $filters): array
|
||||
{
|
||||
$search = trim((string) ($filters['search'] ?? ''));
|
||||
$enabled = trim((string) ($filters['enabled'] ?? ''));
|
||||
@@ -92,7 +92,7 @@ class ScheduledJobRepository
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = self::normalizeRow($row);
|
||||
$item = $this->normalizeRow($row);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class ScheduledJobRepository
|
||||
];
|
||||
}
|
||||
|
||||
public static function listDueJobs(string $nowUtc, int $limit = 20): array
|
||||
public function listDueJobs(string $nowUtc, int $limit = 20): array
|
||||
{
|
||||
$limit = max(1, min(200, $limit));
|
||||
$rows = DB::select(
|
||||
@@ -122,7 +122,7 @@ class ScheduledJobRepository
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = self::normalizeRow($row);
|
||||
$item = $this->normalizeRow($row);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
@@ -131,7 +131,7 @@ class ScheduledJobRepository
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
public static function updateJobMeta(int $id, array $data): bool
|
||||
public function updateJobMeta(int $id, array $data): bool
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return false;
|
||||
@@ -176,7 +176,7 @@ class ScheduledJobRepository
|
||||
* Returns true only when the UPDATE affected a row, i.e. the job was successfully
|
||||
* claimed by this runner. Returns false if the job is already running (not stale).
|
||||
*/
|
||||
public static function markRunning(int $id, string $startedAtUtc): bool
|
||||
public function markRunning(int $id, string $startedAtUtc): bool
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return false;
|
||||
@@ -206,7 +206,7 @@ class ScheduledJobRepository
|
||||
return (int) $updated > 0;
|
||||
}
|
||||
|
||||
public static function finishRun(
|
||||
public function finishRun(
|
||||
int $id,
|
||||
string $status,
|
||||
string $startedAtUtc,
|
||||
@@ -238,7 +238,7 @@ class ScheduledJobRepository
|
||||
return $updated !== false;
|
||||
}
|
||||
|
||||
private static function normalizeRow(mixed $row): ?array
|
||||
private function normalizeRow(mixed $row): ?array
|
||||
{
|
||||
if (!is_array($row)) {
|
||||
return null;
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ScheduledJobRunRepository
|
||||
{
|
||||
public static function create(array $data): int|false
|
||||
public function create(array $data): int|false
|
||||
{
|
||||
$id = DB::insert(
|
||||
'insert into scheduled_job_runs (
|
||||
@@ -30,7 +30,7 @@ class ScheduledJobRunRepository
|
||||
return $id ? (int) $id : false;
|
||||
}
|
||||
|
||||
public static function listPagedByJobId(int $jobId, array $filters): array
|
||||
public function listPagedByJobId(int $jobId, array $filters): array
|
||||
{
|
||||
if ($jobId <= 0) {
|
||||
return ['total' => 0, 'rows' => []];
|
||||
@@ -97,7 +97,7 @@ class ScheduledJobRunRepository
|
||||
$normalized = [];
|
||||
if (is_array($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$item = self::normalizeRow($row);
|
||||
$item = $this->normalizeRow($row);
|
||||
if ($item !== null) {
|
||||
$normalized[] = $item;
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class ScheduledJobRunRepository
|
||||
return ['total' => $total, 'rows' => $normalized];
|
||||
}
|
||||
|
||||
public static function purgeOlderThanDays(int $days): int
|
||||
public function purgeOlderThanDays(int $days): int
|
||||
{
|
||||
if ($days <= 0) {
|
||||
return 0;
|
||||
@@ -119,7 +119,7 @@ class ScheduledJobRunRepository
|
||||
return is_int($deleted) ? $deleted : 0;
|
||||
}
|
||||
|
||||
private static function normalizeRow(mixed $row): ?array
|
||||
private function normalizeRow(mixed $row): ?array
|
||||
{
|
||||
if (!is_array($row)) {
|
||||
return null;
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class SchedulerRuntimeRepository
|
||||
{
|
||||
public static function touchHeartbeat(string $result, ?string $errorCode = null, ?string $heartbeatAtUtc = null): bool
|
||||
public function touchHeartbeat(string $result, ?string $errorCode = null, ?string $heartbeatAtUtc = null): bool
|
||||
{
|
||||
$heartbeatAtUtc = trim((string) ($heartbeatAtUtc ?? ''));
|
||||
if ($heartbeatAtUtc === '') {
|
||||
@@ -17,7 +17,7 @@ class SchedulerRuntimeRepository
|
||||
if ($result === '') {
|
||||
$result = 'ok';
|
||||
}
|
||||
$errorCode = self::nullableTrim($errorCode);
|
||||
$errorCode = $this->nullableTrim($errorCode);
|
||||
|
||||
$updated = DB::update(
|
||||
'insert into scheduler_runtime_status (id, last_heartbeat_at, last_result, last_error_code) ' .
|
||||
@@ -34,7 +34,7 @@ class SchedulerRuntimeRepository
|
||||
return $updated !== false;
|
||||
}
|
||||
|
||||
public static function findStatus(): ?array
|
||||
public function findStatus(): ?array
|
||||
{
|
||||
$row = DB::selectOne('select * from scheduler_runtime_status where id = 1 limit 1');
|
||||
if (!is_array($row)) {
|
||||
@@ -44,7 +44,7 @@ class SchedulerRuntimeRepository
|
||||
return is_array($item) ? $item : null;
|
||||
}
|
||||
|
||||
private static function nullableTrim(?string $value): ?string
|
||||
private function nullableTrim(?string $value): ?string
|
||||
{
|
||||
$value = trim((string) $value);
|
||||
return $value !== '' ? $value : null;
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class RateLimitRepository
|
||||
{
|
||||
public static function findByScopeAndHash(string $scope, string $subjectHash): ?array
|
||||
public function findByScopeAndHash(string $scope, string $subjectHash): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, scope, subject_hash, hits, window_started_at, blocked_until, created, modified from request_rate_limits where scope = ? and subject_hash = ? limit 1',
|
||||
@@ -19,7 +19,7 @@ class RateLimitRepository
|
||||
return $row['request_rate_limits'];
|
||||
}
|
||||
|
||||
public static function create(
|
||||
public function create(
|
||||
string $scope,
|
||||
string $subjectHash,
|
||||
int $hits,
|
||||
@@ -37,7 +37,7 @@ class RateLimitRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function updateStateById(
|
||||
public function updateStateById(
|
||||
int $id,
|
||||
int $hits,
|
||||
string $windowStartedAt,
|
||||
@@ -57,7 +57,7 @@ class RateLimitRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function deleteByScopeAndHash(string $scope, string $subjectHash): bool
|
||||
public function deleteByScopeAndHash(string $scope, string $subjectHash): bool
|
||||
{
|
||||
$result = DB::delete(
|
||||
'delete from request_rate_limits where scope = ? and subject_hash = ?',
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class SettingRepository
|
||||
{
|
||||
public static function find(string $key): ?array
|
||||
public function find(string $key): ?array
|
||||
{
|
||||
$row = DB::selectOne('select `key`, `value`, `description`, `updated_at` from settings where `key` = ? limit 1', $key);
|
||||
if (!$row) {
|
||||
@@ -15,16 +15,16 @@ class SettingRepository
|
||||
return $row['settings'] ?? $row;
|
||||
}
|
||||
|
||||
public static function getValue(string $key): ?string
|
||||
public function getValue(string $key): ?string
|
||||
{
|
||||
$row = self::find($key);
|
||||
$row = $this->find($key);
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
return array_key_exists('value', $row) ? (string) $row['value'] : null;
|
||||
}
|
||||
|
||||
public static function set(string $key, ?string $value, ?string $description = null): bool
|
||||
public function set(string $key, ?string $value, ?string $description = null): bool
|
||||
{
|
||||
$query = 'insert into settings (`key`, `value`, `description`) values (?, ?, ?) '
|
||||
. 'on duplicate key update `value` = values(`value`), '
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class TenantMicrosoftAuthRepository
|
||||
{
|
||||
private static function unwrap($row): ?array
|
||||
private function unwrap($row): ?array
|
||||
{
|
||||
if (!$row || !is_array($row)) {
|
||||
return null;
|
||||
@@ -17,16 +17,16 @@ class TenantMicrosoftAuthRepository
|
||||
return $row;
|
||||
}
|
||||
|
||||
public static function findByTenantId(int $tenantId): ?array
|
||||
public function findByTenantId(int $tenantId): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, tenant_id, enabled, enforce_microsoft_login, sync_profile_on_login, sync_profile_fields, entra_tenant_id, allowed_domains, use_shared_app, client_id_override, client_secret_override_enc, created, modified from tenant_auth_microsoft where tenant_id = ? limit 1',
|
||||
(string) $tenantId
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function listByTenantIds(array $tenantIds): array
|
||||
public function listByTenantIds(array $tenantIds): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
$tenantIds = array_values(array_filter($tenantIds, static fn ($id) => $id > 0));
|
||||
@@ -46,7 +46,7 @@ class TenantMicrosoftAuthRepository
|
||||
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$item = self::unwrap($row);
|
||||
$item = $this->unwrap($row);
|
||||
if (!is_array($item)) {
|
||||
continue;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ class TenantMicrosoftAuthRepository
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upsertByTenantId(int $tenantId, array $data): bool
|
||||
public function upsertByTenantId(int $tenantId, array $data): bool
|
||||
{
|
||||
$result = DB::update(
|
||||
'insert into tenant_auth_microsoft (tenant_id, enabled, enforce_microsoft_login, sync_profile_on_login, sync_profile_fields, entra_tenant_id, allowed_domains, use_shared_app, client_id_override, client_secret_override_enc, created) values (?,?,?,?,?,?,?,?,?,?,NOW()) ' .
|
||||
@@ -81,5 +81,4 @@ class TenantMicrosoftAuthRepository
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class TenantRepository
|
||||
{
|
||||
private static function unwrap(?array $row): ?array
|
||||
private function unwrap(?array $row): ?array
|
||||
{
|
||||
if (!$row) {
|
||||
return null;
|
||||
@@ -15,7 +15,7 @@ class TenantRepository
|
||||
return $row['tenants'] ?? null;
|
||||
}
|
||||
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -30,15 +30,15 @@ class TenantRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function list(): array
|
||||
public function list(): array
|
||||
{
|
||||
$rows = DB::select(
|
||||
'select id, uuid, description, address, postal_code, city, country, region, vat_id, tax_number, phone, fax, email, support_email, support_phone, billing_email, website, privacy_url, imprint_url, primary_color, default_theme, allow_user_theme, status, status_changed_at, status_changed_by, created_by, modified_by, created, modified from tenants order by id desc'
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listIds(): array
|
||||
public function listIds(): array
|
||||
{
|
||||
$rows = DB::select('select id from tenants');
|
||||
if (!is_array($rows)) {
|
||||
@@ -54,7 +54,7 @@ class TenantRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listByIds(array $tenantIds): array
|
||||
public function listByIds(array $tenantIds): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
$tenantIds = array_values(array_filter($tenantIds, static fn ($id) => $id > 0));
|
||||
@@ -67,10 +67,10 @@ class TenantRepository
|
||||
'select id, uuid, description, address, postal_code, city, country, region, vat_id, tax_number, phone, fax, email, support_email, support_phone, billing_email, website, privacy_url, imprint_url, primary_color, default_theme, allow_user_theme, status, status_changed_at, status_changed_by, created_by, modified_by, created, modified from tenants where id in (' . $placeholders . ')',
|
||||
...array_map('strval', $tenantIds)
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function listActiveIdsByIds(array $tenantIds): array
|
||||
public function listActiveIdsByIds(array $tenantIds): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
if (!$tenantIds) {
|
||||
@@ -98,7 +98,7 @@ class TenantRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listPaged(array $options): array
|
||||
public function listPaged(array $options): array
|
||||
{
|
||||
$search = trim((string) ($options['search'] ?? ''));
|
||||
$allowedOrder = ['id', 'uuid', 'description', 'status', 'created', 'modified'];
|
||||
@@ -140,29 +140,29 @@ class TenantRepository
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'rows' => self::unwrapList($rows),
|
||||
'rows' => $this->unwrapList($rows),
|
||||
];
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, description, address, postal_code, city, country, region, vat_id, tax_number, phone, fax, email, support_email, support_phone, billing_email, website, privacy_url, imprint_url, primary_color, default_theme, allow_user_theme, status, status_changed_at, status_changed_by, created_by, modified_by, created, modified from tenants where id = ? limit 1',
|
||||
(string) $id
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function findByUuid(string $uuid): ?array
|
||||
public function findByUuid(string $uuid): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, uuid, description, address, postal_code, city, country, region, vat_id, tax_number, phone, fax, email, support_email, support_phone, billing_email, website, privacy_url, imprint_url, primary_color, default_theme, allow_user_theme, status, status_changed_at, status_changed_by, created_by, modified_by, created, modified from tenants where uuid = ? limit 1',
|
||||
$uuid
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function create(array $data)
|
||||
public function create(array $data)
|
||||
{
|
||||
return DB::insert(
|
||||
'insert into tenants (uuid, description, address, postal_code, city, country, region, vat_id, tax_number, phone, fax, email, support_email, support_phone, billing_email, website, privacy_url, imprint_url, primary_color, default_theme, allow_user_theme, status, status_changed_at, status_changed_by, created_by, created) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())',
|
||||
@@ -194,7 +194,7 @@ class TenantRepository
|
||||
);
|
||||
}
|
||||
|
||||
public static function update(int $id, array $data): bool
|
||||
public function update(int $id, array $data): bool
|
||||
{
|
||||
$fields = [
|
||||
'description' => $data['description'],
|
||||
@@ -242,7 +242,7 @@ class TenantRepository
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function delete(int $id): bool
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$result = DB::delete('delete from tenants where id = ?', (string) $id);
|
||||
return $result !== false;
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class UserTenantRepository
|
||||
{
|
||||
public static function listTenantIdsByUserId(int $userId): array
|
||||
public function listTenantIdsByUserId(int $userId): array
|
||||
{
|
||||
$rows = DB::select('select tenant_id from user_tenants where user_id = ?', (string) $userId);
|
||||
if (!is_array($rows)) {
|
||||
@@ -22,7 +22,7 @@ class UserTenantRepository
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function replaceForUser(int $userId, array $tenantIds): bool
|
||||
public function replaceForUser(int $userId, array $tenantIds): bool
|
||||
{
|
||||
DB::delete('delete from user_tenants where user_id = ?', (string) $userId);
|
||||
if (!$tenantIds) {
|
||||
@@ -40,17 +40,17 @@ class UserTenantRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function countUsersByTenantIds(array $tenantIds): array
|
||||
public function countUsersByTenantIds(array $tenantIds): array
|
||||
{
|
||||
return self::countByTenantIds($tenantIds, false);
|
||||
return $this->countByTenantIds($tenantIds, false);
|
||||
}
|
||||
|
||||
public static function countActiveUsersByTenantIds(array $tenantIds): array
|
||||
public function countActiveUsersByTenantIds(array $tenantIds): array
|
||||
{
|
||||
return self::countByTenantIds($tenantIds, true);
|
||||
return $this->countByTenantIds($tenantIds, true);
|
||||
}
|
||||
|
||||
private static function countByTenantIds(array $tenantIds, bool $activeOnly): array
|
||||
private function countByTenantIds(array $tenantIds, bool $activeOnly): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
$tenantIds = array_values(array_filter($tenantIds, static fn ($id) => $id > 0));
|
||||
@@ -74,17 +74,17 @@ class UserTenantRepository
|
||||
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$tenantId = self::extractIntField($row, 'tenant_id');
|
||||
$tenantId = $this->extractIntField($row, 'tenant_id');
|
||||
if ($tenantId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$result[$tenantId] = self::extractIntField($row, 'user_count');
|
||||
$result[$tenantId] = $this->extractIntField($row, 'user_count');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function extractIntField(array $row, string $field): int
|
||||
private function extractIntField(array $row, string $field): int
|
||||
{
|
||||
foreach ($row as $value) {
|
||||
if (!is_array($value)) {
|
||||
|
||||
@@ -6,7 +6,7 @@ use MintyPHP\DB;
|
||||
|
||||
class UserExternalIdentityRepository
|
||||
{
|
||||
private static function unwrap($row): ?array
|
||||
private function unwrap($row): ?array
|
||||
{
|
||||
if (!$row || !is_array($row)) {
|
||||
return null;
|
||||
@@ -17,7 +17,7 @@ class UserExternalIdentityRepository
|
||||
return $row;
|
||||
}
|
||||
|
||||
public static function findByProviderTidOid(string $provider, string $tid, string $oid): ?array
|
||||
public function findByProviderTidOid(string $provider, string $tid, string $oid): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, provider, oid, tid, issuer, subject, email_at_link_time, created from user_external_identities where provider = ? and tid = ? and oid = ? limit 1',
|
||||
@@ -25,10 +25,10 @@ class UserExternalIdentityRepository
|
||||
$tid,
|
||||
$oid
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function findByProviderIssuerSubject(string $provider, string $issuer, string $subject): ?array
|
||||
public function findByProviderIssuerSubject(string $provider, string $issuer, string $subject): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'select id, user_id, provider, oid, tid, issuer, subject, email_at_link_time, created from user_external_identities where provider = ? and issuer = ? and subject = ? limit 1',
|
||||
@@ -36,10 +36,10 @@ class UserExternalIdentityRepository
|
||||
$issuer,
|
||||
$subject
|
||||
);
|
||||
return self::unwrap($row);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public static function createLink(array $data)
|
||||
public function createLink(array $data)
|
||||
{
|
||||
return DB::insert(
|
||||
'insert into user_external_identities (user_id, provider, oid, tid, issuer, subject, email_at_link_time, created) values (?,?,?,?,?,?,?,NOW())',
|
||||
|
||||
384
lib/Repository/User/UserListQueryRepository.php
Normal file
384
lib/Repository/User/UserListQueryRepository.php
Normal file
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Repository\User;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class UserListQueryRepository
|
||||
{
|
||||
private function buildUserFilters(array $options): array
|
||||
{
|
||||
$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 = RepoQuery::normalizeIdList($options['roles'] ?? []);
|
||||
$departmentIds = RepoQuery::normalizeIdList($options['departments'] ?? []);
|
||||
$emailVerified = $options['email_verified'] ?? null;
|
||||
$loginStatus = $options['login_status'] ?? null;
|
||||
$customFieldFilterSpec = is_array($options['customFieldFilterSpec'] ?? null)
|
||||
? $options['customFieldFilterSpec']
|
||||
: [];
|
||||
$customFieldFilters = is_array($customFieldFilterSpec['filters'] ?? null)
|
||||
? $customFieldFilterSpec['filters']
|
||||
: [];
|
||||
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
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']],
|
||||
]);
|
||||
|
||||
if ($createdFrom !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $createdFrom)) {
|
||||
$where[] = 'users.created >= ?';
|
||||
$params[] = $createdFrom . ' 00:00:00';
|
||||
}
|
||||
if ($createdTo !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $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);
|
||||
} 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 = ?)'
|
||||
);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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'],
|
||||
]);
|
||||
if (!empty($customFieldFilters['select']) && is_array($customFieldFilters['select'])) {
|
||||
foreach ($customFieldFilters['select'] as $definitionId => $optionId) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$optionId = (int) $optionId;
|
||||
if ($definitionId <= 0 || $optionId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.option_id = ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = (string) $optionId;
|
||||
}
|
||||
}
|
||||
if (!empty($customFieldFilters['boolean']) && is_array($customFieldFilters['boolean'])) {
|
||||
foreach ($customFieldFilters['boolean'] as $definitionId => $boolValue) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$boolValue = (int) $boolValue;
|
||||
if ($definitionId <= 0 || ($boolValue !== 0 && $boolValue !== 1)) {
|
||||
continue;
|
||||
}
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.value_bool = ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = (string) $boolValue;
|
||||
}
|
||||
}
|
||||
if (!empty($customFieldFilters['multiselect']) && is_array($customFieldFilters['multiselect'])) {
|
||||
foreach ($customFieldFilters['multiselect'] as $definitionId => $optionIds) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$optionIds = RepoQuery::normalizeIdList($optionIds);
|
||||
if ($definitionId <= 0 || !$optionIds) {
|
||||
continue;
|
||||
}
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'join user_custom_field_value_options ucfvo on ucfvo.value_id = ucfv.id ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfvo.option_id in (???))';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = array_map('strval', $optionIds);
|
||||
}
|
||||
}
|
||||
if (!empty($customFieldFilters['date']) && is_array($customFieldFilters['date'])) {
|
||||
foreach ($customFieldFilters['date'] as $definitionId => $bounds) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$from = is_array($bounds) ? trim((string) ($bounds['from'] ?? '')) : '';
|
||||
$to = is_array($bounds) ? trim((string) ($bounds['to'] ?? '')) : '';
|
||||
if ($definitionId <= 0 || ($from === '' && $to === '')) {
|
||||
continue;
|
||||
}
|
||||
if ($from !== '') {
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.value_date >= ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = $from;
|
||||
}
|
||||
if ($to !== '') {
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.value_date <= ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = $to;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)) : '';
|
||||
return [$whereSql, $params];
|
||||
}
|
||||
|
||||
private 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.last_login_provider, users.active, ' .
|
||||
'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);
|
||||
}
|
||||
|
||||
private function extractIds(array $list): array
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($list as $user) {
|
||||
if (isset($user['id'])) {
|
||||
$ids[] = (int) $user['id'];
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
if ($userId === 0 && isset($value['user_id'])) {
|
||||
$userId = (int) $value['user_id'];
|
||||
}
|
||||
if ($label === '' && isset($value['description'])) {
|
||||
$label = (string) $value['description'];
|
||||
}
|
||||
}
|
||||
}
|
||||
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 function hydrateUserLabels(array $list, array $options): array
|
||||
{
|
||||
$ids = $this->extractIds($list);
|
||||
if (!$ids) {
|
||||
return $list;
|
||||
}
|
||||
|
||||
$scopeUserId = (int) ($options['tenantUserId'] ?? 0);
|
||||
$scopeToActiveTenants = $scopeUserId > 0;
|
||||
$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), '?'));
|
||||
$tenantScopeSql = '';
|
||||
$tenantScopeParams = [];
|
||||
if ($scopeToActiveTenants) {
|
||||
$tenantScopeSql = ' and exists (select 1 from user_tenants uts ' .
|
||||
"join tenants ts on ts.id = uts.tenant_id and ts.status = 'active' " .
|
||||
'where uts.user_id = ? and uts.tenant_id = ut.tenant_id)';
|
||||
$tenantScopeParams[] = (string) $scopeUserId;
|
||||
}
|
||||
|
||||
$labelSql = '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 . ')' . $tenantScopeSql . ' order by t.description asc';
|
||||
$labelRows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge(
|
||||
[$labelSql],
|
||||
array_merge(array_map('strval', $ids), $tenantScopeParams)
|
||||
));
|
||||
$roleRows = 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)
|
||||
);
|
||||
|
||||
$departmentScopeSql = '';
|
||||
$departmentScopeParams = [];
|
||||
if ($scopeToActiveTenants) {
|
||||
$departmentScopeSql = ' and exists (select 1 from user_tenants uts ' .
|
||||
"join tenants ts on ts.id = uts.tenant_id and ts.status = 'active' " .
|
||||
'where uts.user_id = ? and uts.tenant_id = d.tenant_id)';
|
||||
$departmentScopeParams[] = (string) $scopeUserId;
|
||||
}
|
||||
$departmentLabelSql = '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 . ')' . $departmentScopeSql . ' order by d.description asc';
|
||||
$departmentRows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge(
|
||||
[$departmentLabelSql],
|
||||
array_merge(array_map('strval', $ids), $departmentScopeParams)
|
||||
));
|
||||
|
||||
$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;
|
||||
}
|
||||
if ($userId === 0 && isset($value['user_id'])) {
|
||||
$userId = (int) $value['user_id'];
|
||||
}
|
||||
if ($tenantId === 0 && isset($value['tenant_id'])) {
|
||||
$tenantId = (int) $value['tenant_id'];
|
||||
}
|
||||
if ($label === '' && isset($value['description'])) {
|
||||
$label = (string) $value['description'];
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
$tenantLabelsByUser = [];
|
||||
foreach ($tenantMapByUser as $userId => $map) {
|
||||
$tenantLabelsByUser[$userId] = array_values($map);
|
||||
}
|
||||
$roleLabelsByUser = $this->collectLabels($roleRows, 'ur', 'r');
|
||||
$departmentLabelsByUser = $this->collectLabels($departmentRows, '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);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
$list[] = $user;
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function listPaged(array $options): array
|
||||
{
|
||||
$allowedOrder = ['id', 'uuid', 'first_name', 'last_name', 'display_name', 'email', 'created', 'modified', 'active', 'last_login_at'];
|
||||
[$limit, $offset] = RepoQuery::sanitizeLimitOffset($options);
|
||||
[$order, $dir] = RepoQuery::sanitizeOrder($options, $allowedOrder);
|
||||
[$whereSql, $params] = $this->buildUserFilters($options);
|
||||
|
||||
$count = DB::selectValue('select count(*) from users' . $whereSql, ...$params);
|
||||
$total = $count ? (int) $count : 0;
|
||||
|
||||
$query = $this->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 = $this->unwrapList($rows);
|
||||
$list = $this->hydrateUserLabels($list, $options);
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'rows' => $list,
|
||||
];
|
||||
}
|
||||
}
|
||||
154
lib/Repository/User/UserReadRepository.php
Normal file
154
lib/Repository/User/UserReadRepository.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Repository\User;
|
||||
|
||||
use MintyPHP\DB;
|
||||
|
||||
class UserReadRepository
|
||||
{
|
||||
public function findAuthzSnapshot(int $userId): ?array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$row = DB::selectOne(
|
||||
'select id, active, authz_version, locale, theme, current_tenant_id from users where id = ? limit 1',
|
||||
(string) $userId
|
||||
);
|
||||
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'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, last_login_at, last_login_provider, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, modified_by, created, modified, active, authz_version from users where id = ? limit 1',
|
||||
(string) $id
|
||||
);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public function findByUuid(string $uuid): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'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, last_login_at, last_login_provider, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, modified_by, created, modified, active, authz_version, active_changed_at, active_changed_by from users where uuid = ? limit 1',
|
||||
$uuid
|
||||
);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public function findByEmail(string $email): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'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, last_login_at, last_login_provider, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, modified_by, created, modified, active, authz_version, active_changed_at, active_changed_by from users where email = ? limit 1',
|
||||
$email
|
||||
);
|
||||
return $this->unwrap($row);
|
||||
}
|
||||
|
||||
public function listPrivilegedUserIdsByPermissionKeys(array $permissionKeys): array
|
||||
{
|
||||
$keys = array_values(array_unique(array_filter(array_map(
|
||||
static fn ($key) => trim((string) $key),
|
||||
$permissionKeys
|
||||
))));
|
||||
if (!$keys) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($keys), '?'));
|
||||
$rows = DB::select(
|
||||
'select distinct ur.user_id from user_roles ur ' .
|
||||
'join roles r on r.id = ur.role_id and r.active = 1 ' .
|
||||
'join role_permissions rp on rp.role_id = ur.role_id ' .
|
||||
'join permissions p on p.id = rp.permission_id and p.active = 1 ' .
|
||||
"where p.`key` in ($placeholders)",
|
||||
...$keys
|
||||
);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
foreach ($rows as $row) {
|
||||
$data = $row['ur'] ?? $row['user_roles'] ?? $row;
|
||||
$userId = (int) ($data['user_id'] ?? $row['user_id'] ?? 0);
|
||||
if ($userId > 0) {
|
||||
$ids[] = $userId;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public function listIdsForAutoDeactivate(int $days, array $excludedUserIds, int $limit = 500): array
|
||||
{
|
||||
if ($days <= 0 || $limit <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$excluded = array_values(array_unique(array_filter(array_map('intval', $excludedUserIds), static fn ($id) => $id > 0)));
|
||||
$query = 'select id from users where active = 1 and coalesce(last_login_at, created) <= DATE_SUB(UTC_TIMESTAMP(), INTERVAL ' .
|
||||
(int) $days .
|
||||
' DAY)';
|
||||
$params = [];
|
||||
if ($excluded) {
|
||||
$placeholders = implode(',', array_fill(0, count($excluded), '?'));
|
||||
$query .= " and id not in ($placeholders)";
|
||||
$params = array_map('strval', $excluded);
|
||||
}
|
||||
$query .= ' order by coalesce(last_login_at, created) asc limit ?';
|
||||
$params[] = (string) $limit;
|
||||
$rows = DB::select($query, ...$params);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
return $this->extractIdList($rows);
|
||||
}
|
||||
|
||||
public function listIdsForAutoDelete(int $days, array $excludedUserIds, int $limit = 500): array
|
||||
{
|
||||
if ($days <= 0 || $limit <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$excluded = array_values(array_unique(array_filter(array_map('intval', $excludedUserIds), static fn ($id) => $id > 0)));
|
||||
$query = 'select id from users where active = 0 and active_changed_at is not null and active_changed_at <= DATE_SUB(UTC_TIMESTAMP(), INTERVAL ' .
|
||||
(int) $days .
|
||||
' DAY)';
|
||||
$params = [];
|
||||
if ($excluded) {
|
||||
$placeholders = implode(',', array_fill(0, count($excluded), '?'));
|
||||
$query .= " and id not in ($placeholders)";
|
||||
$params = array_map('strval', $excluded);
|
||||
}
|
||||
$query .= ' order by active_changed_at asc limit ?';
|
||||
$params[] = (string) $limit;
|
||||
$rows = DB::select($query, ...$params);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
return $this->extractIdList($rows);
|
||||
}
|
||||
|
||||
private function unwrap(?array $row): ?array
|
||||
{
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
return $row['users'] ?? null;
|
||||
}
|
||||
|
||||
private function extractIdList(array $rows): array
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($rows as $row) {
|
||||
$data = $row['users'] ?? $row;
|
||||
$id = (int) ($data['id'] ?? $row['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
$ids[] = $id;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
}
|
||||
@@ -1,841 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Repository\User;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class UserRepository
|
||||
{
|
||||
private static function buildUserFilters(array $options): array
|
||||
{
|
||||
$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 = RepoQuery::normalizeIdList($options['roles'] ?? []);
|
||||
$departmentIds = RepoQuery::normalizeIdList($options['departments'] ?? []);
|
||||
$emailVerified = $options['email_verified'] ?? null;
|
||||
$loginStatus = $options['login_status'] ?? null;
|
||||
$customFieldFilterSpec = is_array($options['customFieldFilterSpec'] ?? null)
|
||||
? $options['customFieldFilterSpec']
|
||||
: [];
|
||||
$customFieldFilters = is_array($customFieldFilterSpec['filters'] ?? null)
|
||||
? $customFieldFilterSpec['filters']
|
||||
: [];
|
||||
|
||||
$where = [];
|
||||
$params = [];
|
||||
|
||||
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']],
|
||||
]);
|
||||
|
||||
if ($createdFrom !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $createdFrom)) {
|
||||
$where[] = 'users.created >= ?';
|
||||
$params[] = $createdFrom . ' 00:00:00';
|
||||
}
|
||||
if ($createdTo !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $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);
|
||||
} 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 = ?)'
|
||||
);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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'],
|
||||
]);
|
||||
if (!empty($customFieldFilters['select']) && is_array($customFieldFilters['select'])) {
|
||||
foreach ($customFieldFilters['select'] as $definitionId => $optionId) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$optionId = (int) $optionId;
|
||||
if ($definitionId <= 0 || $optionId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.option_id = ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = (string) $optionId;
|
||||
}
|
||||
}
|
||||
if (!empty($customFieldFilters['boolean']) && is_array($customFieldFilters['boolean'])) {
|
||||
foreach ($customFieldFilters['boolean'] as $definitionId => $boolValue) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$boolValue = (int) $boolValue;
|
||||
if ($definitionId <= 0 || ($boolValue !== 0 && $boolValue !== 1)) {
|
||||
continue;
|
||||
}
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.value_bool = ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = (string) $boolValue;
|
||||
}
|
||||
}
|
||||
if (!empty($customFieldFilters['multiselect']) && is_array($customFieldFilters['multiselect'])) {
|
||||
foreach ($customFieldFilters['multiselect'] as $definitionId => $optionIds) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$optionIds = RepoQuery::normalizeIdList($optionIds);
|
||||
if ($definitionId <= 0 || !$optionIds) {
|
||||
continue;
|
||||
}
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'join user_custom_field_value_options ucfvo on ucfvo.value_id = ucfv.id ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfvo.option_id in (???))';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = array_map('strval', $optionIds);
|
||||
}
|
||||
}
|
||||
if (!empty($customFieldFilters['date']) && is_array($customFieldFilters['date'])) {
|
||||
foreach ($customFieldFilters['date'] as $definitionId => $bounds) {
|
||||
$definitionId = (int) $definitionId;
|
||||
$from = is_array($bounds) ? trim((string) ($bounds['from'] ?? '')) : '';
|
||||
$to = is_array($bounds) ? trim((string) ($bounds['to'] ?? '')) : '';
|
||||
if ($definitionId <= 0 || ($from === '' && $to === '')) {
|
||||
continue;
|
||||
}
|
||||
if ($from !== '') {
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.value_date >= ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = $from;
|
||||
}
|
||||
if ($to !== '') {
|
||||
$where[] = 'exists (select 1 from user_custom_field_values ucfv ' .
|
||||
'where ucfv.user_id = users.id and ucfv.definition_id = ? and ucfv.value_date <= ?)';
|
||||
$params[] = (string) $definitionId;
|
||||
$params[] = $to;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)) : '';
|
||||
return [$whereSql, $params];
|
||||
}
|
||||
|
||||
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.last_login_provider, users.active, ' .
|
||||
'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);
|
||||
}
|
||||
|
||||
private static function extractIds(array $list): array
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($list as $user) {
|
||||
if (isset($user['id'])) {
|
||||
$ids[] = (int) $user['id'];
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if ($userId === 0 && isset($value['user_id'])) {
|
||||
$userId = (int) $value['user_id'];
|
||||
}
|
||||
if ($label === '' && isset($value['description'])) {
|
||||
$label = (string) $value['description'];
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
$scopeUserId = (int) ($options['tenantUserId'] ?? 0);
|
||||
$scopeToActiveTenants = $scopeUserId > 0;
|
||||
$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), '?'));
|
||||
$tenantScopeSql = '';
|
||||
$tenantScopeParams = [];
|
||||
if ($scopeToActiveTenants) {
|
||||
$tenantScopeSql = ' and exists (select 1 from user_tenants uts ' .
|
||||
"join tenants ts on ts.id = uts.tenant_id and ts.status = 'active' " .
|
||||
'where uts.user_id = ? and uts.tenant_id = ut.tenant_id)';
|
||||
$tenantScopeParams[] = (string) $scopeUserId;
|
||||
}
|
||||
|
||||
$labelSql = '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 . ')' . $tenantScopeSql . ' order by t.description asc';
|
||||
$labelRows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge(
|
||||
[$labelSql],
|
||||
array_merge(array_map('strval', $ids), $tenantScopeParams)
|
||||
));
|
||||
$roleRows = 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)
|
||||
);
|
||||
|
||||
$departmentScopeSql = '';
|
||||
$departmentScopeParams = [];
|
||||
if ($scopeToActiveTenants) {
|
||||
$departmentScopeSql = ' and exists (select 1 from user_tenants uts ' .
|
||||
"join tenants ts on ts.id = uts.tenant_id and ts.status = 'active' " .
|
||||
'where uts.user_id = ? and uts.tenant_id = d.tenant_id)';
|
||||
$departmentScopeParams[] = (string) $scopeUserId;
|
||||
}
|
||||
$departmentLabelSql = '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 . ')' . $departmentScopeSql . ' order by d.description asc';
|
||||
$departmentRows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge(
|
||||
[$departmentLabelSql],
|
||||
array_merge(array_map('strval', $ids), $departmentScopeParams)
|
||||
));
|
||||
|
||||
$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;
|
||||
}
|
||||
if ($userId === 0 && isset($value['user_id'])) {
|
||||
$userId = (int) $value['user_id'];
|
||||
}
|
||||
if ($tenantId === 0 && isset($value['tenant_id'])) {
|
||||
$tenantId = (int) $value['tenant_id'];
|
||||
}
|
||||
if ($label === '' && isset($value['description'])) {
|
||||
$label = (string) $value['description'];
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
$tenantLabelsByUser = [];
|
||||
foreach ($tenantMapByUser as $userId => $map) {
|
||||
$tenantLabelsByUser[$userId] = array_values($map);
|
||||
}
|
||||
$roleLabelsByUser = self::collectLabels($roleRows, 'ur', 'r');
|
||||
$departmentLabelsByUser = self::collectLabels($departmentRows, '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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
$list[] = $user;
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function updateLastLogin(int $userId, string $provider = 'local'): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
$provider = trim(strtolower($provider));
|
||||
if (!in_array($provider, ['local', 'microsoft'], true)) {
|
||||
$provider = 'local';
|
||||
}
|
||||
DB::query('update users set last_login_at = UTC_TIMESTAMP(), last_login_provider = ? where id = ?', $provider, (string) $userId);
|
||||
}
|
||||
|
||||
public static function findAuthzSnapshot(int $userId): ?array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$row = DB::selectOne(
|
||||
'select id, active, authz_version, locale, theme, current_tenant_id from users where id = ? limit 1',
|
||||
(string) $userId
|
||||
);
|
||||
|
||||
return self::unwrap($row);
|
||||
}
|
||||
|
||||
public static function bumpAuthzVersion(int $userId): bool
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = DB::update(
|
||||
'update users set authz_version = authz_version + 1 where id = ?',
|
||||
(string) $userId
|
||||
);
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public static function bumpAuthzVersionByUserIds(array $userIds): int
|
||||
{
|
||||
$userIds = array_values(array_unique(array_map('intval', $userIds)));
|
||||
$userIds = array_values(array_filter($userIds, static fn ($id) => $id > 0));
|
||||
if (!$userIds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
|
||||
$result = DB::update(
|
||||
"update users set authz_version = authz_version + 1 where id in ($placeholders)",
|
||||
...array_map('strval', $userIds)
|
||||
);
|
||||
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public static function listPaged(array $options): array
|
||||
{
|
||||
$allowedOrder = ['id', 'uuid', 'first_name', 'last_name', 'display_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);
|
||||
|
||||
$result = [
|
||||
'total' => $total,
|
||||
'rows' => $list,
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function find(int $id): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'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, last_login_at, last_login_provider, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, modified_by, created, modified, active, authz_version from users where id = ? limit 1',
|
||||
(string) $id
|
||||
);
|
||||
return self::unwrap($row);
|
||||
}
|
||||
|
||||
public static function findByUuid(string $uuid): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'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, last_login_at, last_login_provider, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, modified_by, created, modified, active, authz_version, active_changed_at, active_changed_by from users where uuid = ? limit 1',
|
||||
$uuid
|
||||
);
|
||||
return self::unwrap($row);
|
||||
}
|
||||
|
||||
public static function findByEmail(string $email): ?array
|
||||
{
|
||||
$row = DB::selectOne(
|
||||
'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, last_login_at, last_login_provider, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, modified_by, created, modified, active, authz_version, active_changed_at, active_changed_by from users where email = ? limit 1',
|
||||
$email
|
||||
);
|
||||
return self::unwrap($row);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static function create(array $data): int|false
|
||||
{
|
||||
$hash = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
return DB::insert(
|
||||
'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(),?,?,?)',
|
||||
$data['uuid'] ?? RepoQuery::uuidV4(),
|
||||
$data['first_name'],
|
||||
$data['last_name'],
|
||||
self::buildDisplayName($data),
|
||||
$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'],
|
||||
'display_name' => self::buildDisplayName($data),
|
||||
'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 listPrivilegedUserIdsByPermissionKeys(array $permissionKeys): array
|
||||
{
|
||||
$keys = array_values(array_unique(array_filter(array_map(
|
||||
static fn ($key) => trim((string) $key),
|
||||
$permissionKeys
|
||||
))));
|
||||
if (!$keys) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($keys), '?'));
|
||||
$rows = DB::select(
|
||||
'select distinct ur.user_id from user_roles ur ' .
|
||||
'join roles r on r.id = ur.role_id and r.active = 1 ' .
|
||||
'join role_permissions rp on rp.role_id = ur.role_id ' .
|
||||
'join permissions p on p.id = rp.permission_id and p.active = 1 ' .
|
||||
"where p.`key` in ($placeholders)",
|
||||
...$keys
|
||||
);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
foreach ($rows as $row) {
|
||||
$data = $row['ur'] ?? $row['user_roles'] ?? $row;
|
||||
$userId = (int) ($data['user_id'] ?? $row['user_id'] ?? 0);
|
||||
if ($userId > 0) {
|
||||
$ids[] = $userId;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public static function listIdsForAutoDeactivate(int $days, array $excludedUserIds, int $limit = 500): array
|
||||
{
|
||||
if ($days <= 0 || $limit <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$excluded = array_values(array_unique(array_filter(array_map('intval', $excludedUserIds), static fn ($id) => $id > 0)));
|
||||
$query = 'select id from users where active = 1 and coalesce(last_login_at, created) <= DATE_SUB(UTC_TIMESTAMP(), INTERVAL ' .
|
||||
(int) $days .
|
||||
' DAY)';
|
||||
$params = [];
|
||||
if ($excluded) {
|
||||
$placeholders = implode(',', array_fill(0, count($excluded), '?'));
|
||||
$query .= " and id not in ($placeholders)";
|
||||
$params = array_map('strval', $excluded);
|
||||
}
|
||||
$query .= ' order by coalesce(last_login_at, created) asc limit ?';
|
||||
$params[] = (string) $limit;
|
||||
$rows = DB::select($query, ...$params);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
return self::extractIdList($rows);
|
||||
}
|
||||
|
||||
public static function listIdsForAutoDelete(int $days, array $excludedUserIds, int $limit = 500): array
|
||||
{
|
||||
if ($days <= 0 || $limit <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$excluded = array_values(array_unique(array_filter(array_map('intval', $excludedUserIds), static fn ($id) => $id > 0)));
|
||||
$query = 'select id from users where active = 0 and active_changed_at is not null and active_changed_at <= DATE_SUB(UTC_TIMESTAMP(), INTERVAL ' .
|
||||
(int) $days .
|
||||
' DAY)';
|
||||
$params = [];
|
||||
if ($excluded) {
|
||||
$placeholders = implode(',', array_fill(0, count($excluded), '?'));
|
||||
$query .= " and id not in ($placeholders)";
|
||||
$params = array_map('strval', $excluded);
|
||||
}
|
||||
$query .= ' order by active_changed_at asc limit ?';
|
||||
$params[] = (string) $limit;
|
||||
$rows = DB::select($query, ...$params);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
return self::extractIdList($rows);
|
||||
}
|
||||
|
||||
public static function setInactiveByIds(array $userIds, ?int $changedBy = null): int
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $userIds), static fn ($id) => $id > 0)));
|
||||
if (!$ids) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
$query = "update users set active = 0, modified_by = ?, active_changed_at = UTC_TIMESTAMP(), active_changed_by = ? where active = 1 and id in ($placeholders)";
|
||||
$params = array_merge([$changedBy, $changedBy], array_map('strval', $ids));
|
||||
$result = DB::update($query, ...$params);
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public static function deleteByIds(array $userIds): int
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $userIds), static fn ($id) => $id > 0)));
|
||||
if (!$ids) {
|
||||
return 0;
|
||||
}
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
$result = DB::delete(
|
||||
"delete from users where id in ($placeholders)",
|
||||
...array_map('strval', $ids)
|
||||
);
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
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 updateProfileFieldsFromSso(int $id, array $fields): bool
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$existing = self::find($id);
|
||||
if (!$existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowed = ['first_name', 'last_name', 'phone', 'mobile'];
|
||||
$updates = [];
|
||||
foreach ($allowed as $field) {
|
||||
if (!array_key_exists($field, $fields)) {
|
||||
continue;
|
||||
}
|
||||
$value = trim((string) $fields[$field]);
|
||||
if ($value === '') {
|
||||
continue;
|
||||
}
|
||||
if ((string) ($existing[$field] ?? '') === $value) {
|
||||
continue;
|
||||
}
|
||||
$updates[$field] = $value;
|
||||
}
|
||||
|
||||
if (!$updates) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($updates['first_name']) || isset($updates['last_name'])) {
|
||||
$displayData = [
|
||||
'first_name' => $updates['first_name'] ?? (string) ($existing['first_name'] ?? ''),
|
||||
'last_name' => $updates['last_name'] ?? (string) ($existing['last_name'] ?? ''),
|
||||
'email' => (string) ($existing['email'] ?? ''),
|
||||
];
|
||||
$updates['display_name'] = self::buildDisplayName($displayData);
|
||||
}
|
||||
|
||||
$setParts = [];
|
||||
$params = [];
|
||||
foreach ($updates as $field => $value) {
|
||||
$setParts[] = sprintf('`%s` = ?', $field);
|
||||
$params[] = $value;
|
||||
}
|
||||
$params[] = (string) $id;
|
||||
|
||||
$result = DB::update(
|
||||
'update users set ' . implode(', ', $setParts) . ' where id = ?',
|
||||
...$params
|
||||
);
|
||||
|
||||
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 extractIdList(array $rows): array
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($rows as $row) {
|
||||
$data = $row['users'] ?? $row;
|
||||
$id = (int) ($data['id'] ?? $row['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
$ids[] = $id;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class UserSavedFilterRepository
|
||||
{
|
||||
private static function unwrapList($rows): array
|
||||
private function unwrapList($rows): array
|
||||
{
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
@@ -22,7 +22,7 @@ class UserSavedFilterRepository
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function listByUserAndContext(int $userId, string $context): array
|
||||
public function listByUserAndContext(int $userId, string $context): array
|
||||
{
|
||||
if ($userId <= 0 || $context === '') {
|
||||
return [];
|
||||
@@ -32,10 +32,10 @@ class UserSavedFilterRepository
|
||||
(string) $userId,
|
||||
$context
|
||||
);
|
||||
return self::unwrapList($rows);
|
||||
return $this->unwrapList($rows);
|
||||
}
|
||||
|
||||
public static function countByUserAndContext(int $userId, string $context): int
|
||||
public function countByUserAndContext(int $userId, string $context): int
|
||||
{
|
||||
if ($userId <= 0 || $context === '') {
|
||||
return 0;
|
||||
@@ -48,7 +48,7 @@ class UserSavedFilterRepository
|
||||
return $count ? (int) $count : 0;
|
||||
}
|
||||
|
||||
public static function create(array $data): int|false
|
||||
public function create(array $data): int|false
|
||||
{
|
||||
$userId = (int) ($data['user_id'] ?? 0);
|
||||
$context = trim((string) ($data['context'] ?? ''));
|
||||
@@ -67,7 +67,7 @@ class UserSavedFilterRepository
|
||||
);
|
||||
}
|
||||
|
||||
public static function deleteByUuidForUserAndContext(string $uuid, int $userId, string $context): bool
|
||||
public function deleteByUuidForUserAndContext(string $uuid, int $userId, string $context): bool
|
||||
{
|
||||
$uuid = trim($uuid);
|
||||
$context = trim($context);
|
||||
|
||||
319
lib/Repository/User/UserWriteRepository.php
Normal file
319
lib/Repository/User/UserWriteRepository.php
Normal file
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Repository\User;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class UserWriteRepository
|
||||
{
|
||||
public function updateLastLogin(int $userId, string $provider = 'local'): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
$provider = trim(strtolower($provider));
|
||||
if (!in_array($provider, ['local', 'microsoft'], true)) {
|
||||
$provider = 'local';
|
||||
}
|
||||
DB::query('update users set last_login_at = UTC_TIMESTAMP(), last_login_provider = ? where id = ?', $provider, (string) $userId);
|
||||
}
|
||||
|
||||
public function bumpAuthzVersion(int $userId): bool
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = DB::update(
|
||||
'update users set authz_version = authz_version + 1 where id = ?',
|
||||
(string) $userId
|
||||
);
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function bumpAuthzVersionByUserIds(array $userIds): int
|
||||
{
|
||||
$userIds = array_values(array_unique(array_map('intval', $userIds)));
|
||||
$userIds = array_values(array_filter($userIds, static fn ($id) => $id > 0));
|
||||
if (!$userIds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
|
||||
$result = DB::update(
|
||||
"update users set authz_version = authz_version + 1 where id in ($placeholders)",
|
||||
...array_map('strval', $userIds)
|
||||
);
|
||||
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public function create(array $data): int|false
|
||||
{
|
||||
$hash = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
return DB::insert(
|
||||
'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(),?,?,?)',
|
||||
$data['uuid'] ?? RepoQuery::uuidV4(),
|
||||
$data['first_name'],
|
||||
$data['last_name'],
|
||||
$this->buildDisplayName($data),
|
||||
$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 function update(int $id, array $data): bool
|
||||
{
|
||||
$fields = [
|
||||
'first_name' => $data['first_name'],
|
||||
'last_name' => $data['last_name'],
|
||||
'display_name' => $this->buildDisplayName($data),
|
||||
'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 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 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 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 function setInactiveByIds(array $userIds, ?int $changedBy = null): int
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $userIds), static fn ($id) => $id > 0)));
|
||||
if (!$ids) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
$query = "update users set active = 0, modified_by = ?, active_changed_at = UTC_TIMESTAMP(), active_changed_by = ? where active = 1 and id in ($placeholders)";
|
||||
$params = array_merge([$changedBy, $changedBy], array_map('strval', $ids));
|
||||
$result = DB::update($query, ...$params);
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public function deleteByIds(array $userIds): int
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $userIds), static fn ($id) => $id > 0)));
|
||||
if (!$ids) {
|
||||
return 0;
|
||||
}
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
$result = DB::delete(
|
||||
"delete from users where id in ($placeholders)",
|
||||
...array_map('strval', $ids)
|
||||
);
|
||||
return $result !== false ? (int) $result : 0;
|
||||
}
|
||||
|
||||
public function setLocale(int $id, string $locale): bool
|
||||
{
|
||||
$result = DB::update('update users set locale = ? where id = ?', $locale, (string) $id);
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function setTheme(int $id, string $theme): bool
|
||||
{
|
||||
$result = DB::update('update users set theme = ? where id = ?', $theme, (string) $id);
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function updateProfileFieldsFromSso(int $id, array $fields): bool
|
||||
{
|
||||
if ($id <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = DB::selectOne('select first_name, last_name, email, phone, mobile from users where id = ? limit 1', (string) $id);
|
||||
$existing = $row['users'] ?? null;
|
||||
if (!is_array($existing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowed = ['first_name', 'last_name', 'phone', 'mobile'];
|
||||
$updates = [];
|
||||
foreach ($allowed as $field) {
|
||||
if (!array_key_exists($field, $fields)) {
|
||||
continue;
|
||||
}
|
||||
$value = trim((string) $fields[$field]);
|
||||
if ($value === '') {
|
||||
continue;
|
||||
}
|
||||
if ((string) ($existing[$field] ?? '') === $value) {
|
||||
continue;
|
||||
}
|
||||
$updates[$field] = $value;
|
||||
}
|
||||
|
||||
if (!$updates) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($updates['first_name']) || isset($updates['last_name'])) {
|
||||
$displayData = [
|
||||
'first_name' => $updates['first_name'] ?? (string) ($existing['first_name'] ?? ''),
|
||||
'last_name' => $updates['last_name'] ?? (string) ($existing['last_name'] ?? ''),
|
||||
'email' => (string) ($existing['email'] ?? ''),
|
||||
];
|
||||
$updates['display_name'] = $this->buildDisplayName($displayData);
|
||||
}
|
||||
|
||||
$setParts = [];
|
||||
$params = [];
|
||||
foreach ($updates as $field => $value) {
|
||||
$setParts[] = sprintf('`%s` = ?', $field);
|
||||
$params[] = $value;
|
||||
}
|
||||
$params[] = (string) $id;
|
||||
|
||||
$result = DB::update(
|
||||
'update users set ' . implode(', ', $setParts) . ' where id = ?',
|
||||
...$params
|
||||
);
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public 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 function setEmailVerified(int $id): bool
|
||||
{
|
||||
$result = DB::update('update users set email_verified_at = NOW() where id = ?', (string) $id);
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
$result = DB::delete('delete from users where id = ?', (string) $id);
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public 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 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user