unwrapList($rows); } public function countByUser(int $userId): int { if ($userId <= 0) { return 0; } $count = DB::selectValue( 'select count(*) from user_bookmark_groups where user_id = ?', (string) $userId ); return $count ? (int) $count : 0; } public function findById(int $id, int $userId): array|false { if ($id <= 0 || $userId <= 0) { return false; } $rows = DB::select( 'select id, user_id, name, icon, sort_order, created, modified from user_bookmark_groups where id = ? and user_id = ?', (string) $id, (string) $userId ); $list = $this->unwrapList($rows); return $list[0] ?? false; } public function create(array $data): int|false { $userId = (int) ($data['user_id'] ?? 0); $name = trim((string) ($data['name'] ?? '')); $icon = trim((string) ($data['icon'] ?? 'bi-folder')); $sortOrder = (int) ($data['sort_order'] ?? 0); if ($userId <= 0 || $name === '' || $icon === '') { return false; } return DB::insert( 'insert into user_bookmark_groups (user_id, name, icon, sort_order, created) values (?,?,?,?,NOW())', (string) $userId, $name, $icon, (string) $sortOrder ); } public function update(int $id, int $userId, array $data): bool { if ($id <= 0 || $userId <= 0) { return false; } $sets = []; $params = []; if (array_key_exists('name', $data)) { $name = trim((string) $data['name']); if ($name === '') { return false; } $sets[] = 'name = ?'; $params[] = $name; } if (array_key_exists('icon', $data)) { $icon = trim((string) $data['icon']); if ($icon === '') { return false; } $sets[] = 'icon = ?'; $params[] = $icon; } if ($sets === []) { return false; } $params[] = (string) $id; $params[] = (string) $userId; $affected = DB::update( 'update user_bookmark_groups set ' . implode(', ', $sets) . ' where id = ? and user_id = ?', ...$params ); return $affected !== false; } public function delete(int $id, int $userId): bool { if ($id <= 0 || $userId <= 0) { return false; } $deleted = DB::delete( 'delete from user_bookmark_groups where id = ? and user_id = ?', (string) $id, (string) $userId ); return $deleted !== false && (int) $deleted > 0; } public function updateSortOrders(int $userId, array $idOrderPairs): bool { if ($userId <= 0 || $idOrderPairs === []) { return false; } $idList = []; foreach ($idOrderPairs as $pair) { $id = (int) $pair['id']; if ($id <= 0) { return false; } $idList[] = $id; } $idList = array_values(array_unique($idList)); $existingCount = DB::selectValue( 'select count(*) from user_bookmark_groups where user_id = ? and id in (???)', (string) $userId, array_map('strval', $idList) ); if ((int) $existingCount !== count($idList)) { return false; } $db = DB::handle(); try { $db->begin_transaction(); foreach ($idOrderPairs as $pair) { $id = (int) $pair['id']; $sortOrder = (int) $pair['sort_order']; if ($id <= 0 || $sortOrder <= 0) { $db->rollback(); return false; } $updated = DB::update( 'update user_bookmark_groups set sort_order = ? where id = ? and user_id = ?', (string) $sortOrder, (string) $id, (string) $userId ); if ($updated === false) { $db->rollback(); return false; } } $db->commit(); return true; } catch (\Throwable) { try { $db->rollback(); } catch (\Throwable) { // no-op } return false; } } }