bank_sql/
wesweb01/bank_sql/modules/user.php1 lines
<?php
# Fil som skapar klass för användare och användardata.
require "utility.php";
require "database.php";
# $db är definierad i database.php
class User extends DatabaseTable
# En klass för en användare. Innehåller funktioner för transaktioner och datalagring.
{
protected static $dbPrimaryKey = "userId"; # PK för user-tabellen (läs mer i database.php)
protected static $dbTable = "user"; # Namn på databastabellen
public static function GetUserFromName($username): ?User
# Statisk funktion som hämtar ett användarobjekt utifrån användarnamn.
{
global $db;
$userData = $db->query("SELECT userId FROM user WHERE username=:username", array("username" => $username));
if (!$userData) # Kontrollerar att användaren finns.
return null;
return new User($userData["userId"]);
}
public static function RegisterUser($username, $password): ?int
# Statisk funktion som skapar ett konto från användarnamn och lösenord.
{
global $db, $masterBankAccount;
$passwordSalt = generate_salt(); # Skapar lösenordssalt.
$passwordHash = hash_password($password, $passwordSalt); # Hashar lösenordet
try {
# Försöker lägga till användaren
$db->query(
"INSERT INTO user (username, passwordHash, passwordSalt) VALUES (:username, :passwordHash, :passwordSalt)",
array("username" => $username, "passwordHash" => $passwordHash, "passwordSalt" => $passwordSalt)
);
} catch (PDOException $ex) {
# Eftersom det finns en UNIQUE-constraint på username kommer databasen ge en error ifall användarnamnet redan finns.
return null;
}
$user = new User($db->getLastId()); # Skapar användarobjekt
$account = $user->createAccount("Bankkonto"); # Lägger till ett bankkonto
# Ger detta konto en välkomstbonus på 1000 kr.
Transaction::AddTransaction($masterBankAccount, $account, 1000, "signup_bonus");
return $user->id;
}
public static function TryLoginUser($username, $password): ?User
# Statisk funktion som försöker logga in användare med användarnamn och lösenord.
{
global $db;
$userData = $db->query("SELECT userId, passwordHash, passwordSalt FROM user WHERE username=:username", array("username" => $username));
if (!$userData) # Kontrollerar att användaren finns.
return null;
$passwordHash = hash_password($password, $userData["passwordSalt"]); # Hashar lösenordet och kollar att de stämmer överens.
if ($userData["passwordHash"] != $passwordHash)
return null;
return new User($userData["userId"]); # Skapar ett nytt användarobjekt ifall användarnamn och lösenord stämde.
}
public function createAccount($name): Account
# Funktion som skapar ett nytt (bank)konto. Koden förklarar sig själv.
{
global $db;
$db->query(
"INSERT INTO userAccount(userId, `name`) VALUES (:userId, :accountName)",
array(
"userId" => $this->id,
"accountName" => $name ?? "Nytt konto"
)
);
return new Account($db->getLastId());
}
public function getMainAccount(): ?Account
# Hämtar huvudkontot. Huvudkontot är ett konto som insättningar, uttag och mottagning av externa transaktioner sker på.
# Det kan inte tas bort.
{
foreach ($this->accounts as $account) {
if ($account->isMainAccount)
return $account;
}
return null; # Bör aldrig inträffa
}
public function getAccountFromId($accountId): ?Account
# Hämtar ett kontoobjekt utifrån konto-id.
{
foreach ($this->accounts as $account) {
if ($account->accountId == $accountId)
return $account;
}
return null;
}
public function logDeposit($amount): void
# Sparar ett uttag från huvudkontot.
{
global $masterBankAccount;
Transaction::AddTransaction($masterBankAccount, $this->getMainAccount(), $amount, "deposit");
}
public function logWithdrawal($amount): void
# Sparar en insättning till huvudkontot.
{
global $masterBankAccount;
Transaction::AddTransaction($this->getMainAccount(), $masterBankAccount, $amount, "withdrawal");
}
public function logInternalTransaction($senderAccount, $recipientAccount, $amount): void
# Sparar en intern transkation (mellan två konton hos samma användare).
{
Transaction::AddTransaction($senderAccount, $recipientAccount, $amount, "transaction");
}
public function logExternalTransaction($senderAccount, $recipientUser, $amount): void
# Sparar en extern transkation (från en användare till en annan).
{
$recipientAccount = $recipientUser->getMainAccount(); # Pengarna skickas till mottagarens huvudkonto.
Transaction::AddTransaction($senderAccount, $recipientAccount, $amount, "transaction");
}
public function deleteAccount($account): void
# Funktion som tar bort ett bankkonto.
{
# Resterande pengar skickas till huvudkontot.
Transaction::AddTransaction($account, $this->getMainAccount(), $account->balance, "deletec_account");
$account->isActive = 0; # Kontot tas inte faktiskt bort, utan inaktiveras bara.
$account->updateValues(array("isActive"));
}
}
# Skapar två relationer, en för User->accounts och en för Account->transactions.
# Detta gör det möjligt att enkelt komma åt relationerna, exempelvis en användares konton.
DatabaseTable::AddRelation(User::class, Account::class, "userId", "accounts");
DatabaseTable::AddRelation(Account::class, Transaction::class, "accountId", "transactions", "`date` DESC");
class Account extends DatabaseTable
# Klass för en användares bankkonto
{
protected static $dbPrimaryKey = "accountId"; # PK för user-tabellen.
protected static $dbTable = "userAccount"; # Namn på databastabellen.
protected static $dbReadTable = "userAccountBalanceView"; # Namn på databastabellen/vyn som den enbart läser ifrån.
public static function GetAccountFromId($accountId): ?Account
# Hämtar ett kontoobjekt utifrån konto-id.
{
global $db;
$pk = self::$dbPrimaryKey; # Namnet på PK-property
$table = self::$dbReadTable ?? self::$dbTable; # Tabellen som den ska läsa ifrån
# Kör SQL-satsen och hämtar kontot som har PK = $accountId.
$instanceData = $db->query(
"SELECT * FROM {$table} WHERE {$pk}=:id",
array(
"id" => $accountId
)
);
if (!$instanceData)
return null; # Ifall inget konto hittades
$instance = new Account($accountId); # En ny kontoinstans skapas.
foreach ($instanceData as $index => $value) { # Eftersom vi redan har hämtat data fyller vi den direkt,
# och så slipper vi köra ett till databasanrop senare.
$instance->{$index} = $value;
}
return $instance;
}
}
$masterBankAccount = new Account(1); # Bankkonto som ägs av banken.
# Finns för att ge välkomstbonus, samt insättningar och uttag.
class Transaction extends DatabaseTable
# Klass för transaktioner.
{
protected static $dbPrimaryKey = "transactionId"; # PK för user-tabellen.
protected static $dbTable = "transaction"; # Namn på databastabellen.
protected static $dbReadTable = "userAccountTransactionView"; # Namn på databastabellen/vyn som den enbart läser ifrån.
public static function AddTransaction($senderAccount, $recipientAccount, $amount, $type)
{
# Statisk funktion som lägger till en transaktion mellan två bankkonton.
# Använder lite SQL-magi som jag lärde mig, där man kan använda outputen av en SELECT-sats istället för
# att använda VALUES-satsen. Detta gör det möjligt att hämta ett transactionTypeId utifrån name-parametern
# i ett svep.
global $db;
$db->query("INSERT INTO `transaction`(senderAccountId, recipientAccountId, transactionTypeId, amount, `date`)
SELECT :senderAccountId, :recipientAccountId, tt.transactionTypeId, :amount, NOW()
FROM transactionType tt WHERE tt.name=:transactionType",
array(
"senderAccountId" => $senderAccount->id,
"recipientAccountId" => $recipientAccount->id,
"amount" => $amount,
"transactionType" => $type ?? "transaction"
)
);
}
}
?>