new system prototype
This commit is contained in:
211
lib/repositories/UserRepo.php
Normal file
211
lib/repositories/UserRepo.php
Normal file
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
class UserRepo
|
||||
{
|
||||
/**
|
||||
* Full user list with role-table JOINs for location, supervisorID, supervisorUsername.
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
public static function listAll(PDO $pdo): array
|
||||
{
|
||||
return $pdo->query("
|
||||
SELECT u.userID, u.username, u.role, u.entityID, u.mustChangePassword, u.createdAt,
|
||||
COALESCE(a.location, s.location, '') AS location,
|
||||
c.supervisorID,
|
||||
sv.username AS supervisorUsername
|
||||
FROM users u
|
||||
LEFT JOIN admin a ON a.adminID = u.entityID AND u.role = 'admin'
|
||||
LEFT JOIN supervisor s ON s.supervisorID = u.entityID AND u.role = 'supervisor'
|
||||
LEFT JOIN coach c ON c.coachID = u.entityID AND u.role = 'coach'
|
||||
LEFT JOIN supervisor sv ON sv.supervisorID = c.supervisorID
|
||||
ORDER BY u.role, u.username
|
||||
")->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Coaches that belong to the given supervisor.
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
public static function listBySupervisor(PDO $pdo, string $supervisorID): array
|
||||
{
|
||||
$svName = self::getSupervisorName($pdo, $supervisorID);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT u.userID, u.username, u.role, u.entityID, u.mustChangePassword, u.createdAt,
|
||||
'' AS location, c.supervisorID, :svname AS supervisorUsername
|
||||
FROM users u
|
||||
JOIN coach c ON c.coachID = u.entityID AND u.role = 'coach'
|
||||
WHERE c.supervisorID = :svid
|
||||
ORDER BY u.username
|
||||
");
|
||||
$stmt->execute([':svid' => $supervisorID, ':svname' => $svName]);
|
||||
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{supervisorID: string, username: string, location: string}>
|
||||
*/
|
||||
public static function listSupervisors(PDO $pdo): array
|
||||
{
|
||||
return $pdo->query(
|
||||
"SELECT supervisorID, username, location FROM supervisor ORDER BY username"
|
||||
)->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function findByUsername(PDO $pdo, string $username): ?array
|
||||
{
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :u");
|
||||
$stmt->execute([':u' => $username]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{role: string, entityID: string}|null
|
||||
*/
|
||||
public static function findById(PDO $pdo, string $userID): ?array
|
||||
{
|
||||
$stmt = $pdo->prepare("SELECT role, entityID FROM users WHERE userID = :uid");
|
||||
$stmt->execute([':uid' => $userID]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
public static function usernameExists(PDO $pdo, string $username): bool
|
||||
{
|
||||
$stmt = $pdo->prepare("SELECT 1 FROM users WHERE username = :u");
|
||||
$stmt->execute([':u' => $username]);
|
||||
|
||||
return (bool) $stmt->fetch();
|
||||
}
|
||||
|
||||
public static function supervisorExists(PDO $pdo, string $supervisorID): bool
|
||||
{
|
||||
$stmt = $pdo->prepare("SELECT 1 FROM supervisor WHERE supervisorID = :sid");
|
||||
$stmt->execute([':sid' => $supervisorID]);
|
||||
|
||||
return (bool) $stmt->fetch();
|
||||
}
|
||||
|
||||
public static function coachBelongsToSupervisor(PDO $pdo, string $coachEntityID, string $supervisorID): bool
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT coachID FROM coach WHERE coachID = :cid AND supervisorID = :svid"
|
||||
);
|
||||
$stmt->execute([':cid' => $coachEntityID, ':svid' => $supervisorID]);
|
||||
|
||||
return (bool) $stmt->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new user inside a transaction: role-specific table first, then users.
|
||||
* Caller is responsible for wrapping in qdb_open(true) / qdb_save().
|
||||
*/
|
||||
public static function create(
|
||||
PDO $pdo,
|
||||
string $userID,
|
||||
string $entityID,
|
||||
string $username,
|
||||
string $passwordHash,
|
||||
string $role,
|
||||
string $location,
|
||||
string $supervisorID,
|
||||
int $mustChangePassword
|
||||
): void {
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
switch ($role) {
|
||||
case 'admin':
|
||||
$pdo->prepare("INSERT INTO admin (adminID, username, location) VALUES (:id, :u, :loc)")
|
||||
->execute([':id' => $entityID, ':u' => $username, ':loc' => $location]);
|
||||
break;
|
||||
case 'supervisor':
|
||||
$pdo->prepare("INSERT INTO supervisor (supervisorID, username, location) VALUES (:id, :u, :loc)")
|
||||
->execute([':id' => $entityID, ':u' => $username, ':loc' => $location]);
|
||||
break;
|
||||
case 'coach':
|
||||
$pdo->prepare("INSERT INTO coach (coachID, supervisorID, username) VALUES (:id, :sid, :u)")
|
||||
->execute([':id' => $entityID, ':sid' => $supervisorID, ':u' => $username]);
|
||||
break;
|
||||
}
|
||||
|
||||
$pdo->prepare("
|
||||
INSERT INTO users (userID, username, passwordHash, role, entityID, mustChangePassword, createdAt)
|
||||
VALUES (:uid, :u, :hash, :role, :eid, :mcp, :now)
|
||||
")->execute([
|
||||
':uid' => $userID,
|
||||
':u' => $username,
|
||||
':hash' => $passwordHash,
|
||||
':role' => $role,
|
||||
':eid' => $entityID,
|
||||
':mcp' => $mustChangePassword,
|
||||
':now' => time(),
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user + role-specific row in a transaction.
|
||||
*/
|
||||
public static function delete(PDO $pdo, string $userID, string $role, string $entityID): void
|
||||
{
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
$pdo->prepare("DELETE FROM users WHERE userID = :uid")
|
||||
->execute([':uid' => $userID]);
|
||||
|
||||
switch ($role) {
|
||||
case 'admin':
|
||||
$pdo->prepare("DELETE FROM admin WHERE adminID = :id")
|
||||
->execute([':id' => $entityID]);
|
||||
break;
|
||||
case 'supervisor':
|
||||
$pdo->prepare("DELETE FROM supervisor WHERE supervisorID = :id")
|
||||
->execute([':id' => $entityID]);
|
||||
break;
|
||||
case 'coach':
|
||||
$pdo->prepare("DELETE FROM coach WHERE coachID = :id")
|
||||
->execute([':id' => $entityID]);
|
||||
break;
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public static function updatePassword(PDO $pdo, string $userID, string $newHash): void
|
||||
{
|
||||
$pdo->prepare(
|
||||
"UPDATE users SET passwordHash = :h, mustChangePassword = 0 WHERE userID = :uid"
|
||||
)->execute([':h' => $newHash, ':uid' => $userID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Username or empty string if not found.
|
||||
*/
|
||||
public static function getSupervisorName(PDO $pdo, string $supervisorID): string
|
||||
{
|
||||
$stmt = $pdo->prepare("SELECT username FROM supervisor WHERE supervisorID = :svid");
|
||||
$stmt->execute([':svid' => $supervisorID]);
|
||||
|
||||
return $stmt->fetchColumn() ?: '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user